Javascript调用改变类型



我想写一个函数像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版中,将undefinednull作为第一个参数传递给Function.prototype.applyFunction.prototype.call,将导致全局对象作为this值传递给间接调用的目标函数。如果第一个参数是原语值,则对原语值调用ToObject的结果作为this值传递。在版本5中,不执行这些转换,并且实际的第一个参数值作为this值传递…

和ECMAScript 5附录C(参考)ECMAScript的严格模式:

如果在严格模式代码中求值,则不会将this值强制赋给对象。如果nullundefined不转换为全局对象原语值不转换为包装器对象。通过函数调用传递的this值(包括使用Function.prototype.applyFunction.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(),它将无法看到当前对象!

相关内容

  • 没有找到相关文章