我想写一个函数像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
});
问题是call似乎将Number类型转换为Object类型。这会导致console.log调用出现问题。有人能解释为什么会发生这种情况吗(我的猜测是call将参数强制转换为Object类型)。它为什么要这么做?你能想出一个办法来解决或防止这种情况吗?
当不在严格模式时,这是规范的要求。
如果您在代码的顶部使用"use strict";
声明式,您将获得您传递的实际值。
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);
});
注意严格模式是词法作用域的,所以只有在您愿意的情况下才可以将声明性添加到回调中。
演示: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);
});
如果您不想使用严格模式,您可以(在这种情况下)使用一元+
操作符转换为原语。
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
});
相关信息:
来自ECMAScript 5附录E(信息)第5版中引入与第3版不兼容的补充和更改:
15.3.4.3, 15.3.4.4:在第3版中,将undefined或null作为第一个参数传递给
Function.prototype.apply
或Function.prototype.call
,将导致全局对象作为this值传递给间接调用的目标函数。如果第一个参数是原语值,则对原语值调用ToObject
的结果作为this值传递。在版本5中,不执行这些转换,并且实际的第一个参数值作为this值传递…
和ECMAScript 5附录C(参考)ECMAScript的严格模式:
如果在严格模式代码中求值,则不会将this值强制赋给对象。如果null或undefined不转换为全局对象且原语值不转换为包装器对象。通过函数调用传递的this值(包括使用
Function.prototype.apply
和Function.prototype.call
进行的调用)不会将传递的this值强制转换为对象。
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文档有解释
第一个参数是为fun调用提供的
this
的值。请注意,这可能不是方法看到的实际值:如果方法是函数在非严格模式代码中,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
});
this
用于引用函数所属的对象。
虽然可以将其作为自由参数使用,但通常最好将undefined
作为call
的第一个参数传递,并将其值作为常规参数给出。
没有内置的JavaScript迭代函数(如Array的.forEach
)设置this
,并且将函数绑定到特定的this
值变得越来越普遍,因此无论谁调用它们都可以访问它(.bind
是JavaScript 1.8.5的一部分,但有许多第三方库具有自己的绑定实用程序,如Underscore)。如果我将绑定函数传递给each()
,它将无法看到当前对象!