如何将额外的参数传递给JS Array.forEach()函数?

3

我想分享一个小技巧,可以将变量传递到JS Array.forEach()方法的作用域中。我遇到了这样的情况:我需要使用forEach循环来构建数据集。但是同时我也需要访问当前作用域中的变量(我需要能够在循环中引用this)。

我所处的情况如下:

var dataset = {
    data: [],
    backgroundColor:[],
};

items.forEach(function (item) {

    dataset.data.push(item.age);

    if (item.age < 2) {
        dataset.bgColor.push(this.green);
    } else if (item.age < 5) {
        dataset.bgColor.push(this.yellow);
    } else {
        dataset.bgColor.push(this.red);
    }

}, this);


this.refreshGraph(dataset);

循环内部无法访问数据集。那么我们在迭代时如何访问它?

我在stack overflow上没有看到这个解决方案,也没有适合的问题。

答案如下:


4
“Dataset isn't accessible from within the loop.”意思是“循环内无法访问数据集。”不确定您的意思,“dataset”应该在forEach回调函数中可见,因为它在较高的作用域中,较高的作用域变量对较低作用域代码可见。 - Patrick Evans
5个回答

2

如果您有一个超出某些数据范围但需要访问它的函数,可以使用柯里化函数,将该数据集作为第一个参数,并且仍然可以正常使用 this

//curried function that uses `dataset` and `this` but it is not 
//in the context where the iteration happens 
function makeLoopCallback(dataset) {
  return function(item) {
    dataset.data.push(item.age);

    if (item.age < 2) {
        dataset.bgColor.push(this.green);
    } else if (item.age < 5) {
        dataset.bgColor.push(this.yellow);
    } else {
        dataset.bgColor.push(this.red);
    }
  }
}

//object to serve as `this` context for a function
var obj = {
  green: "Green",
  yellow: "Yellow",
  red: "Red",
  doSomething: function(items) {
    var data = {
        data: [],
        bgColor:[],
    };
  
    items.forEach(makeLoopCallback(data), this);
  
    return data;
  }
}

//set up some dummy data
var input = [ { age: 1 }, { age: 2 }, { age: 3 }, { age: 4 }, { age: 5 }, { age: 6 } ];

//call the function
console.log(obj.doSomething(input))

一种替代方法是使用Array#reduce而不是使用带有直接接受两个参数的函数的Array#forEach。由于.reduce不能设置this上下文,您可以使用Function#bind来实现:

//external function that uses `dataset` and `this` but it is not 
//in the context where the iteration happens
function external(dataset, item) {
    dataset.data.push(item.age);

    if (item.age < 2) {
      dataset.bgColor.push(this.green);
    } else if (item.age < 5) {
      dataset.bgColor.push(this.yellow);
    } else {
      dataset.bgColor.push(this.red);
    }

    return dataset;
}

//object to serve as `this` context for a function
var obj = {
  green: "Green",
  yellow: "Yellow",
  red: "Red",
  doSomething: function(items) {
    var data = {
        data: [],
        bgColor:[],
    };

    return items.reduce(external.bind(this), data);
  }
}

//set up some dummy data
var input = [ { age: 1 }, { age: 2 }, { age: 3 }, { age: 4 }, { age: 5 }, { age: 6 } ];

//call the function
console.log(obj.doSomething(input))


这是一个很好的解释。我今天学到了bind()和柯里化函数。非常酷。 - Noah Gary

2

使用es6的能力,如果您使用箭头函数,则this将被取自

items.forEach(item => {
// You can use this as out of the forEach scope
});

来源:MDN Web Docs:

箭头函数不会有它自己的 this。它使用封闭词法作用域中的 this 值;箭头函数遵循常规变量查找规则。因此,当在当前范围内未找到 this 时,箭头函数就会从其封闭的作用域中找到 this。

另一个很好的解释: https://hackernoon.com/javascript-es6-arrow-functions-and-lexical-this-f2a3e2a5e8c4


1
非常好,我喜欢这个更多。我要借鉴一下。 - Noah Gary
@NoahGary 如果这个解决方案适用于您,我会很高兴如果您标记我的答案... - Rami Loiferman
这让我在代码中的操作变得更容易了,所以谢谢你。我为此点了赞。但是我真正想问的是完全不同的问题。即将一个超出作用域的变量传递给函数。 - Noah Gary

1
我找到了一个简单的方法,如果你不需要上下文,你可以直接使用它来传递任何你想要的东西。
response.services.forEach(function(service) {

   //code

},undefined, <whatever i want to pass>);

刚刚在第二个参数中传递了一个未定义的值,并且在第三个参数中将额外的参数传递给了JS的Array.forEach()方法。
简短示例:
[1,2,3].forEach(myCallback, undefined, 'additionalFoo'); #ref

0
解决方案是将一个JSON对象作为this参数传递。因此,在此之前,我们有:
Array.forEach(function(){}, this) 
// "this" is just an object ^^^^ just like anything else in JavaScript

现在我们有:

Array.forEach(function(){}, {_self: this, dataset: dataset}) 

// you can access _self and dataset just as if they were in scope

现在,您可以使用匿名函数在迭代时进行数据更改 :)

完整示例:

var dataset = {
    data: [],
    backgroundColor:[],
};

items.forEach(function (item) {

    dataset.data.push(item.age);

    if (item.age < 2) {
        dataset.bgColor.push(_self.green);
    } else if (item.age < 5) {
        dataset.bgColor.push(_self.yellow);
    } else {
        dataset.bgColor.push(_self.red);
    }
}, { _self: this , dataset: dataset});

2
你的代码中没有使用 this,即使你将其传递进去。然而,你引用了将附加到 this 上的属性,而不经过它。dataset 只能工作是因为它与外部作用域中的 var dataset 匹配。然而,_self 并不引用 this._self。我不确定它的目的是什么,但如果你想更通用,似乎更容易使用箭头函数和/或柯里化函数。 - VLAZ
2
然后你在更高的作用域中设置了一个 _self 变量。thisarg 设置函数的执行上下文(this 关键字将引用什么),它不会将变量引入回调作用域。 - Patrick Evans
@Titus,感谢您帮助我建立连接。我无法从文档中建立该连接。 - Noah Gary
谢谢大家的帮助。我将删除这篇帖子。不过这有助于进一步巩固我的理解。所以并非完全没有收获!哈哈 - Noah Gary
1
如果someFunctionReference是在定义dataset的作用域之外或更低的作用域中未定义的函数,则您需要在末尾使用{dataset:dataset}参数,然后在函数内部使用this.dataset访问它。 - Patrick Evans
显示剩余8条评论

0

Array.prototype.forEach(callbackFun, ?this)

您可以将 dataset 作为此参数传递给 forEach

var dataset = {
data: [],
backgroundColor:[],
};

items.forEach(function (item) {

this.dataset.data.push(item.age);

if (item.age < 2) {
    this.dataset.bgColor.push(this.tempThis.green);
} else if (item.age < 5) {
    this.dataset.bgColor.push(this.tempThis.yellow);
} else {
    this.dataset.bgColor.push(this.tempThis.red);
}

}, {tempThis:this,dataset:dataset});


this.refreshGraph(dataset);

但现在你没有访问 this.green 的权限,例如。 - VLAZ
@VLAZ 现在已经可用。 - Akshay Bande

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接