为什么将Date视为带有+的字符串和任何其他算术运算符的相同数字?

时间:2017-10-09 16:53:32

标签: javascript date

根据我的理解,如果对象具有valueOf函数,则在对象需要转换为基元时将使用它。如果对象具有toString函数,则在对象需要转换为字符串时将使用该函数。因此,当您使用+时,首先应使用valueOf(如果存在),然后使用toString

这似乎是做什么的:

var obj1 = {
  valueOf: () => 0
};

var obj2 = {
  toString: () => 'a'
};

var obj3 = { 
  valueOf: () => 0,
  toString: () => 'a'
};

obj1 + obj1; // -> 0
obj2 + obj2; // -> 'aa'
obj3 + obj3; // -> 0

现在,日期正在实施valueOftoString,例如obj3,但当您执行date + date时,您会得到一个字符串!
使用任何其他算术运算符将日期视为执行操作的数字并返回有效数字。

以下是一些代码来证明我的困惑:

var date = new Date(2017,1,1);

date - date; // -> 0
date * date: // -> 2.20790950849296e+24
date / date; // -> 1
date % date; // -> 0
date + date; // -> "Wed Feb 01 2017 00:00:00 GMT+0100 (CET)Wed Feb 01 2017 00:00:00 GMT+0100 (CET)"

3 个答案:

答案 0 :(得分:0)

如果第一个操作数是字符串,procedure TCustomDialog.FormPaint(Sender: TObject); var Rect: TRect; BorderColor: TColor; BrushColor: TColor; begin // Rect for Form's borders; Rect.Left := 0; Rect.Top := 0; Rect.Right := ClientWidth; Rect.Bottom := ClientHeight; BorderColor := HtmlToTColor('#ffffff'); BrushColor := HtmlToTColor('#ffffff'); // Here I set the colors of Canvas.Pen (border) and Canvas.Brush (Filling), // similar to Bootstrap themes/classes (Default, Success, Warning, Danger); case DialogType of dtInformation: begin BorderColor := HtmlToTColor(Header_Color_Pen_Information); BrushColor := HtmlToTColor(Header_Color_Brush_Information); end; dtSuccess: begin BorderColor := HtmlToTColor(Header_Color_Pen_Success); BrushColor := HtmlToTColor(Header_Color_Brush_Success); end; dtWarning: begin BorderColor := HtmlToTColor(Header_Color_Pen_Warning); BrushColor := HtmlToTColor(Header_Color_Brush_Warning); end; dtError: begin BorderColor := HtmlToTColor(Header_Color_Pen_Error); BrushColor := HtmlToTColor(Header_Color_Brush_Error); end; end; with Canvas do begin Pen.Color := BorderColor; Pen.Width := Form_Pen_Width; // Draw rounded borders for Form; RoundRect(1, 1, Rect.Right - 1, Rect.Bottom - 1, Form_Border_Radius - 1, Form_Border_Radius - 1); // Rect for Dialog's Header; Rect.Left := Component_Gutter; Rect.Top := Component_Gutter; Rect.Right := ClientWidth - Component_Gutter; Rect.Bottom := Form_Header_Height; RoundRect(Component_Gutter, Component_Gutter, ClientWidth - Component_Gutter, Form_Header_Height, Form_Border_Radius - 2, Form_Border_Radius - 2); Brush.Color := BrushColor; FillRect(Rect); end; end; 运算符将充当JS中的连接符。由于+产生一个字符串,因此在这种情况下它将作为连接符。

答案 1 :(得分:0)

这是因为Date有一个异国情调的@@toPrimitive,它更喜欢字符串数字。见#sec-date.prototype-@@toprimitive

  

Date对象在内置ECMAScript对象中是唯一的   对待"默认"等同于" string",所有其他内置   ECMAScript对象处理"默认"等同于"数字"。

答案 2 :(得分:0)

借助 Symbol.toPrimitive 属性(用作函数值),可以将对象转换为原始值。

  

使用字符串参数提示调用该函数,该参数指定结果原语值的首选类型。提示参数可以是"数字","字符串"和"默认"。

日期对象的语法Date()[Symbol.toPrimitive](hint);

  

如果提示是"字符串"或"默认",@@ toPrimitive尝试调用toString方法。如果toString属性不存在,它会尝试调用valueOf方法,如果valueOf也不存在,@@ toPrimitive会抛出TypeError。

     

如果提示是" number",@@ toPrimitive首先尝试调用valueOf,如果失败,则调用toString。



var date = new Date(2017,1,1);

console.log('hint is "number":',+date + +date); // using unary plus operator
console.log('hint is "default":',date + date); // no hint (falls to hint == 'string')
console.log('hint is "string":',`${date + date}`); // using template literals




+运算符是所有算术运算符中最混乱的运算符。如果没有提示将Date实例转换为数字,它将充当字符串连接符