修改数组.forEach自动将上下文设置为调用者

Modifying Array.forEach to Automatically Set the Context to be the Caller

本文关键字:上下文 设置 调用者 数组 forEach 修改      更新时间:2023-09-26

是否可以创建Array的替代品?forEach自动将上下文"this"设置为与调用方法时相同的上下文?

例如(不工作,不知道为什么):

Array.prototype.each = function(fn) {
    return this.forEach(fn, arguments.callee.caller);
}

function myFunction() {
    this.myVar = 'myVar';
    [1,2,3].each(function() {
        console.log(this.myVar); // logs 'myVar'
    });
}

数组。forEach已经接受了一个上下文参数作为可选的最后一个参数

(function() {
    this.myvar = "myvar";
    [1,2,3,4].forEach(function(v) {
        console.log("v:"+v);
        console.log("myvar="+this.myvar);
    }, this);
})();

参见MDN forEach

同样,上面的例子(如果我们不处理关于this的实例上的方法)在不使用bindforEach的可选上下文参数的情况下也可以工作,以下内容也可以正常工作:

function myFunction() {
    this.myVar = 'myVar';
    [1,2,3].forEach(function() {
        console.log(this.myVar); // logs 'myVar'
    });
}
myFunction();

因为javascript是函数作用域,所以匿名函数可以使用this访问父函数的作用域,并正确记录日志。this只有在处理实例方法时才真正成为问题。

答案是否定的,JavaScript函数不能确定调用者中的this的值。

可以将传递的函数与当前对象绑定,如下所示

function myFunction() {
    this.myVar = 'myVar';
    [1,2,3].forEach(function() {
        console.log(this.myVar); // logs 'myVar'
    }.bind(this));
}

在ECMA Script 6中,您可以使用箭头函数,如下所示

[1,2,3].forEach(() => {
    console.log(this.myVar); // logs 'myVar'
});

在传递回调函数时,另一种方法是将this变量弄乱,您可以将this赋值给一个新变量,以便子范围函数可以访问它:

Array.prototype.each = function(fn) {
    return this.forEach(fn, arguments.callee.caller);
}

function myFunction() {
    var me = this;
    me.myVar = 'myVar';
    [1,2,3].each(function() {
        console.log(me.myVar); // logs 'myVar'
    });
}

现在你不必记得传递this作为第二个参数

首先,必须指出myFunction是一个构造函数。但是,标识符中的第一个字母不是大写的。请称之为MyFunction

如果没有new操作符调用构造函数,则this绑定到全局对象,即浏览器中的window。这使得大写约定成为我们发现此类错误的唯一方法。

下面的代码行演示了这一点:
// After the original code...
myFunction();
console.log(window.myVar); // logs "myVar"
其次,为了能够在任何数组上应用函数,而不是更改Array.prototype,请考虑以下事项:
var utils = {array: {}};  // utils.array is a container for array utilities.
utils.array.each = function (array, func) {
    var i;
    for (i = 0; i < array.length; i += 1) { func(array[i]); }
};
utils.write = function (s) { 
    console.log(s); // Alternatively, document.write(s);
};
utils.array.each([1, 2, 3], utils.write); // prints 1 2 and 3 (on separate lines)

注意我们没有使用thisnew。它们使JavaScript看起来像Java,除此之外,它们很少有什么有用的用途。

虽然库可以修改Object.prototypeArray.prototype,但最终开发人员不应该这样做。

同时,我们应该(理想情况下)能够这样做:

  • utils.array.each([1, 2, 3], console.log);
  • utils.array.each([1, 2, 3], document.write); .

但是大多数浏览器不允许。

希望有帮助。

如果我正确理解您的需求,那么您正试图覆盖"this"。我想这对你有帮助。