简体   繁体   English

Javascript:通过遍历数组创建对象方法/属性

[英]Javascript: Create object methods/properties by looping over an array

What I'm really looking for is code like the following: 我真正在寻找的是如下代码:

var painter = {}; // An object to hold methods
var colors = ['blue', 'red', 'green', 'yellow']; // The names of methods to be defined
colors.forEach( function(color) {
    painter.defineMethod(color, function(){ console.log(color); });
});

painter.blue() // writes blue
painter.red() // writes red
etc.

the painter.defineMethod() is the key. painter.defineMethod()是关键。

I have to define several (upwards of 40) methods to an object and they are all basically the same, with minor but predictable changes that really all call another method. 我必须为一个对象定义几个(最多40个)方法,它们基本上是相同的,但有微小但可预测的更改,实际上所有这些都称为另一个方法。 For example: 例如:

painter.blue = function(tool) {
   painter.draw('blue', tool); // Would paint blue with a brush or pencil or whatever.
}

Is something like this possible, or am I stuck defining all these properties explicitly? 是否可能发生这种情况,还是我坚持明确定义所有这些属性? Is there any performance benefit to one way or the other? 一种或另一种方式对性能有好处吗?

What would be easy in a language that has variable variables or magic methods is proving difficult (or impossible) in Javascript. 在具有可变变量或魔术方法的语言中,用Java证明是困难的(或不可能的)。 Though I admit that javascript is not my forte. 尽管我承认javascript不是我的强项。

Thanks! 谢谢!

Your instinct is correct, you can indeed automate this: 您的直觉是正确的,您确实可以自动化:

colors.forEach( function(color) {
    painter[color] = function(tool) {
        painter.draw(color, tool);
    };
});

There are two things at work here: 这里有两件事在起作用:

  1. In JavaScript, you can access (get or set) a property either using dot notation and a property name literal ( obj.foo ), or by using brackets notation and a property name string ( obj["foo"] ). 在JavaScript中,可以使用点表示法和属性名称文字obj.foo ),也可以使用方括号表示法和属性名称字符串obj["foo"] )访问(获取或设置)属性。 In the latter case, the string can be the result of any expression, including a variable lookup. 在后一种情况下,字符串可以是任何表达式的结果,包括变量查找。 So painter[color] = ... assigns to a property whose name comes from the color argument. 因此painter[color] = ...分配给名称来自color参数的属性。

  2. Then we're using the fact that the function we're creating is a closure over the call to the iteration function we give forEach , and so we can use the color argument in that function. 然后,我们利用这样一个事实,即我们正在创建的函数是对给forEach的迭代函数的调用的封闭,因此我们可以在该函数中使用color参数。 Even though the call to the iteration function returns, because we created a function within the call and kept a reference to it, that function keeps a reference to the context (it's a closure over the context), and so we can rely on the color argument being there. 即使返回迭代函数的调用返回了,因为我们在调用中创建了一个函数并保留了对它的引用,所以该函数仍保留了对上下文的引用(这是对上下文的封闭 ),因此我们可以依靠color争论在那里。 More about closures (on my blog): Closures are not complicated 有关闭包的更多信息(在我的博客上): 闭包并不复杂

But since painter.draw takes the color as its first argument and the tool as its second, there's a second way you could do it if you like, though: You can " curry " the color argument into the method using Function#bind (an ES5 feature that can be shimmed on the increasingly-small number of old engines that don't have it) on painter.draw : 但由于painter.draw需要的颜色作为第一个参数和工具作为其第二个,还有如果你喜欢,你可以做第二道,但:你可以在“ 咖喱使用”色彩的说法入法Function#bind (一ES5功能可以在painter.draw上越来越少的没有它的旧引擎上进行painter.draw

colors.forEach( function(color) {
    painter[color] = painter.draw.bind(painter, color);
});

Function#bind returns a function that, when called, calls the original function with the given this value ( painter in the example above) and any further arguments you supply to bind , followed by any arguments given to the original. Function#bind返回一个函数,该函数在调用时将使用给定的this值(在上面的示例中为painter )以及您提供给bind所有其他参数,然后是给定原始参数的任何原始函数调用原始函数。 A simple example may make that clearer: 一个简单的例子可以使这一点更加清楚:

 function func(a, b) { snippet.log("this.name = " + this.name); snippet.log("a = " + a); snippet.log("b = " + b); } var o1 = { name: "o1" }; var o2 = { name: "o2" }; var o1boundfoo = func.bind(o1, "foo"); var o2boundbar = func.bind(o2, "bar"); o1boundfoo("nifty"); // Shows: // this.name = o1 // a = foo // b = nifty o2boundbar("nifty"); // Shows: // this.name = o2 // a = bar // b = nifty 
 <!-- Temporary snippet object, see http://meta.stackexchange.com/a/242144/134069 --> <script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM