50 === 50:假。 50 == 50:是吗?

时间:2011-05-18 02:32:34

标签: javascript

我完全失去了。

我有一个功能..

Number.prototype.abs = function () {
    return this >= 0 ? this : this * -1;
};

..返回数字的绝对值..

(50).abs(); // 50
(-50).abs(); // 50

..但是没有正确比较..

(50).abs() === 50; // False

..有时。

(50).abs() == 50; // True
(-50).abs() === 50; // True

关于它的问题是,它适用于Chrome 12和Firefox 4,但不适用于IE 9,Safari 5或Opera 11。

我没有看到代码有任何问题,因为它适用于Chrome和Firefox,它是浏览器特有的,但我不知道是什么。

更新:浏览器的具体区别是严格模式支持。我在严格模式下运行我的代码,它引入了一些使我的代码工作的更改。它在浏览器中失败的原因是因为它们具有不完整或缺失的严格模式。

为什么它会返回false?

6 个答案:

答案 0 :(得分:36)

尽管Jeremy Heiler是正确的,但他的理由却被误解了。为什么你得到object而不是number与构造函数无关。

此处的问题是this关键字。您需要了解使用this时会发生什么。通过ECMA草案进行一些挖掘将向您展示

  

this关键字的计算结果为当前执行上下文的ThisBinding值。

(我会更改上述内容。this关键字不会评估任何内容的,我们很快就会看到。)嗯,好的,但究竟是怎么做的{ {1}}工作?请继续阅读!

  

执行以下步骤时   控制进入执行上下文   用于包含的功能代码   函数对象F,提供的调用者   thisArg和调用者提供的   argumentsList:

     
      
  1. 如果功能代码是严格代码,请将ThisBinding设置为thisArg。
  2.   
  3. 否则,如果thisArg为null或未定义,则将ThisBinding设置为   全球对象。
  4.   
  5. 如果Type(thisArg)不是Object,则将ThisBinding设置为     的 ToObject(thisArg)。
  6.   
  7. 否则将ThisBinding设置为thisArg。
  8.   
  9. 让localEnv成为调用NewDeclarativeEnvironment的结果   传递[[Scope]]的值   F的内部属性为   参数。
  10.   
  11. 将LexicalEnvironment设置为localEnv。
  12.   
  13. 将VariableEnvironment设置为localEnv。
  14.   
  15. 让代码为F的[[Code]]内部属性的值。
  16.   
  17. 使用功能代码执行声明绑定实例化   代码和argumentList,如10.5
  18. 中所述   

其中就是摩擦(看看粗体部分)。如果从非对象上下文调用函数,ThisBinding(也就是使用ThisBinding)总是返回包装在对象内的上下文的值。解决问题的最简单方法是:

this

...强制Number.prototype.abs = function () { "use strict"; // if available // * 1 implicitly coerces 'this' to a number value return this >= 0 ? this * 1 : this * -1; //... or Number(this) explicitly coerces 'this' to its toNumber value return Number(this >= 0 ? this : this * -1); }; 对象(或强制严格模式)。但我认为理解this的工作原理很重要,这个问题就是一个很好的例子。

答案 1 :(得分:20)

这是因为50本身是一个数字,而您正在返回一个数字对象

alert(typeof 50); // number
alert(typeof (50).abs()); // object

http://jsfiddle.net/Pkkaq/

ECMAScript reference的第4.3.21节:

  

使用创建Number对象   一个新的Number构造函数   表达式,提供Number值   作为一个论点。结果对象   有一个内部属性的价值   是数值。一个数字对象   可以被强制转换为数值   将Number构造函数称为   功能

换句话说,数字不能严格等于数字对象

typeof 50 === typeof new Number(50) //--> false; number != object

(-50).abs()按预期工作的原因是因为它乘以-1。当Number 对象乘以Number 时,它将变为Number 。在这种情况下,如果参数为正,则简单地返回对象,导致返回对象

根据上面引用的参考资料,以下是对您的方法的修复:

Number.prototype.abs = function () {
    return Number(this >= 0 ? this : this * -1);
};

答案 2 :(得分:5)

Triple equals(===)检查类型和值以确保它们相等。它失败的原因与new Number(5) !== 5new String("Text") !== "Text"相同,因为它们的类型不同。但是,当您使用负绝对值时,您正在执行输出原始数字而不是数字对象的数学计算。因此,类型检查匹配,这是真的。

答案 3 :(得分:5)

Math.abs(-50) === 50无处不在。所以你可以将Number.prototype.abs重写为:

Number.prototype.abs = function () {
    return Math.abs(this);
};

我想。在IE9和Chrome 11中经过测试Math.abs(50) === 50true

使用您的方法制作(50).abs()=== 50的其他方法可能是:

return this >= 0 ? this.valueOf() : this * -1;
return this >= 0 ? this * 1 : this * -1;

因此,当>时,扩展名不返回对象(this) 0,但是数值。

但我建议您只使用已有的Math.abs方法,在这种情况下,您可以确保Math.abs(50) === 50;返回true并避免不必要的monkey patch

为了完整性:从选定的答案可以看出,使用strict也是一个解决方案。

答案 4 :(得分:2)

如果两个操作数具有相同的TYPE且值相等,则===返回true。我敢打赌,返回false的实现返回float而不是int。

答案 5 :(得分:2)

你的abs方法有一个问题。函数中的“this”是一个对象,所以当你返回“this”时它就是一种对象。 “this”* -1通过javascript转换为数字。

正如人们所建议的那样,使用Math.abs()可能是最好的方法。

如果您真的希望自己的功能有效,请执行以下操作:

Number.prototype.abs = function () {
    return this >= 0 ? parseInt(this) : this * -1;
};

当然,这假设您只使用整数。