我想编写一个类似jQuery的函数,并且正在使用javascript调用函数。
function each(array, callback) {
for (var i=0; i<array.length; i++) {
console.log(typeof(array[i])); // Number
callback.call(array[i]);
}
}
each([1,2,3], function() {
console.log(typeof(this)); // Object
});
问题是调用似乎是将Number类型转换为Object类型。这会导致console.log调用出现问题。任何人都可以解释为什么会发生这种情况(我的猜测是调用将参数强制转换为Object类型)。它为什么要这样做?你能想办法解决或阻止这种情况吗?
答案 0 :(得分:3)
当不在严格模式时,这是规范的要求。
如果您在代码顶部使用"use strict";
声明,那么您将获得您传递的任何实际值。
DEMO: http://jsfiddle.net/agXkZ/
"use strict";
function each(array, callback) {
for (var i=0; i<array.length; i++) {
callback.call(array[i]);
}
}
each([1,2,3], function() {
console.log(this);
});
请注意,严格模式是词法范围的,所以只有在您愿意的情况下才可以将声明添加到回调中。
DEMO: http://jsfiddle.net/agXkZ/1/
function each(array, callback) {
for (var i=0; i<array.length; i++) {
callback.call(array[i]);
}
}
each([1,2,3], function() {
"use strict";
console.log(this);
});
如果您不想使用严格模式,则可以(在本例中)使用一元+
运算符转换为基元。
DEMO: http://jsfiddle.net/agXkZ/2/
function each(array, callback) {
for (var i=0; i<array.length; i++) {
callback.call(array[i]);
}
}
each([1,2,3], function() {
console.log( +this ); // <--converts from object to primitive
});
相关信息:
15.3.4.3,15.3.4.4:在第3版中,将未定义或 null 作为
Function.prototype.apply
或Function.prototype.call
原因的第一个参数传递将全局对象作为此值传递给间接调用的目标函数。如果第一个参数是原始值,则在原始值上调用ToObject
的结果将作为此值传递。在第5版中,不执行这些转换,并将实际的第一个参数值作为此值传递...
和ECMAScript 5 Annex C (informative) The Strict Mode of ECMAScript:
如果在严格模式代码中评估此值,则此值不会强制转换为对象。此 null 或未定义的值未转换为全局对象,而原始值未转换为包装器对象。通过函数调用传递的 this 值(包括使用
Function.prototype.apply
和Function.prototype.call
进行的调用)不会将传递的 this 值强制转换为对象。
答案 1 :(得分:2)
call
方法的第一个参数是必须执行回调的范围。实际参数仅从第二个参数开始。这可以工作
function each(array, callback) {
for (var i=0; i<array.length; i++) {
console.log(typeof(array[i])); // Number
callback.call(this, array[i]);
}
}
each([1,2,3], function() {
console.log(typeof(arguments[0])); // Number
});
对于转换为Object的数字,此MDN doc有解释
第一个参数是为fun的调用提供的
this
的值。请注意,这可能 不是方法看到的实际值:如果方法是a 在非严格模式代码中,null和undefined将被替换为 全局对象和原始值将被装箱。
在这种情况下,原始数字将被加框。要查看行动中的拳击,您可以运行此代码。
function each(array, callback) {
for (var i=0; i<array.length; i++) {
console.log(typeof(array[i])); // Number
callback.call(array[i]);
}
}
each([1,2,3], function() {
console.log(typeof(this)); // Object
console.log(Number(this)); // prints 1,2 and 3
});
答案 2 :(得分:0)
this
用于引用函数所属的对象。
虽然可以像使用自由参数一样使用它,但通常最好将undefined
作为第一个参数传递给call
,并将该值作为常规参数。
没有任何内置的JavaScript迭代函数(如数组的.forEach
)设置this
,并且绑定函数对特定this
变得很普遍值,所以无论谁调用它们都可以访问它(.bind
是JavaScript 1.8.5的一部分,但是有很多第三方库都有自己的绑定实用程序,like Underscore)。如果我将绑定函数传递给each()
,它将无法看到当前对象!