我完全失去了。
我有一个功能..
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?
答案 0 :(得分:36)
尽管Jeremy Heiler是正确的,但他的理由却被误解了。为什么你得到object
而不是number
与构造函数无关。
此处的问题是this
关键字。您需要了解使用this
时会发生什么。通过ECMA草案进行一些挖掘将向您展示
this关键字的计算结果为当前执行上下文的ThisBinding值。
(我会更改上述内容。this
关键字不会评估任何内容的值,我们很快就会看到。)嗯,好的,但究竟是怎么做的{ {1}}工作?请继续阅读!
执行以下步骤时 控制进入执行上下文 用于包含的功能代码 函数对象F,提供的调用者 thisArg和调用者提供的 argumentsList:
- 如果功能代码是严格代码,请将ThisBinding设置为thisArg。
- 否则,如果thisArg为null或未定义,则将ThisBinding设置为 全球对象。
- 如果Type(thisArg)不是Object,则将ThisBinding设置为 的 ToObject(thisArg)。强>
- 否则将ThisBinding设置为thisArg。
- 让localEnv成为调用NewDeclarativeEnvironment的结果 传递[[Scope]]的值 F的内部属性为 参数。
- 将LexicalEnvironment设置为localEnv。
- 将VariableEnvironment设置为localEnv。
- 让代码为F的[[Code]]内部属性的值。
- 使用功能代码执行声明绑定实例化 代码和argumentList,如10.5
中所述 醇>
其中就是摩擦(看看粗体部分)。如果从非对象上下文调用函数,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
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) !== 5
和new 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) === 50
,true
使用您的方法制作(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;
};
当然,这假设您只使用整数。