[英]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: 这里有两件事在起作用:
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
参数的属性。
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.