【问题标题】:How to pass extra arguments into JS Array.forEach()如何将额外的参数传递给 JS Array.forEach()
【发布时间】:2020-03-15 08:07:12
【问题描述】:

只是想分享一个小技巧,我学会了将变量传递到 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);

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

我还没有看到这个堆栈溢出解决方案,它不适合我能找到的任何问题。

回答如下:

【问题讨论】:

  • “无法从循环内访问数据集。”,不确定您的意思,dataset 应该在 forEach 回调中可见,因为它位于更高的作用域,较高作用域的变量对较低作用域的代码可见

标签: javascript arrays json iteration parameter-passing


【解决方案1】:

如果您有超出某些数据范围的函数但需要访问它,您可以使用一个柯里化函数,该函数将该数据集作为第一个参数,并且仍然可以在整个过程中正常使用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() 和 curried 函数。很酷。
【解决方案2】:

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

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

From MDN Web Docs:

箭头函数没有自己的 this。的这个值 使用封闭词法范围;箭头功能遵循正常 变量查找规则。所以在搜索这个不是 存在于当前范围内,箭头函数最终会找到 this 从它的封闭范围。

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

【讨论】:

  • 非常好,我更喜欢这个。会偷的。
  • @NoahGary 如果它对你有用,如果你标记我的答案,我会很高兴......
  • 这让我在代码中所做的事情变得更容易了,谢谢。我为此投了赞成票。但我真的想问一个完全不同的问题。将变量传递给超出范围的函数。
【解决方案3】:

解决方案是将 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});

【讨论】:

  • 您没有在代码中的任何地方使用this,即使您将其传入。但是您引用了将附加到this 的属性,而无需通过它。 dataset 只能工作,因为它与外部范围的匹配 - var dataset。但是,_self 没有引用 this._self。但是,我不确定它的意义是什么 - 如果您想要更通用,使用箭头函数和/或柯里函数似乎更容易。
  • documentation 中提到了这一点,并在 SO 上的很多答案中使用,此外,您必须使用 this._self 而不仅仅是 _self
  • @VLAZ 这只是我完整代码的一部分,它更多地只是为了让其他人理解的概念证明。请发布您的箭头函数解决方案!我很想看看。
  • 那么你有一个_self 变量设置在更高的范围内。 thisarg 设置函数的执行上下文(this 关键字将引用的内容)它不会将变量引入回调范围。
  • 如果 someFunctionReference 是一个未在同一范围或更低范围中定义的函数,其中定义了 dataset,那么您将需要最后的 {dataset:dataset} 参数,然后访问它在函数中使用this.dataset
【解决方案4】:

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 现在可以使用了。
猜你喜欢
  • 2018-10-07
  • 1970-01-01
  • 1970-01-01
  • 2012-09-01
  • 1970-01-01
  • 2020-07-19
  • 2016-02-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多