Javascript:通过在数组上循环来创建对象方法/属性

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

本文关键字:创建对象 方法 属性 循环 数组 Javascript      更新时间:2023-09-26

我真正想要的是如下代码:

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.

画家.defineMethod()是关键。

我必须为一个对象定义几个(超过40个)方法,它们基本上都是相同的,只是有一些微小但可预测的更改,这些更改实际上都调用了另一个方法。例如:

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

这样的事情可能吗,还是我一直在明确地定义所有这些属性?以这样或那样的方式有任何性能优势吗?

在一种拥有可变变量或神奇方法的语言中,简单的事情在Javascript中被证明是困难的(或不可能的)。尽管我承认javascript不是我的专长。

谢谢!

你的直觉是正确的,你确实可以自动化:

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

这里有两件事在起作用:

  1. 在JavaScript中,您可以使用句点表示法和属性名称literalobj.foo),或者使用括号表示法和特性名称字符串来访问(获取或设置)属性(obj["foo"])。在后一种情况下,字符串可以是任何表达式的结果,包括变量查找。因此,painter[color] = ...为名称来自color参数的属性赋值。

  2. 然后我们使用这样一个事实,即我们正在创建的函数是对我们给forEach的迭代函数的调用的闭包,因此我们可以在该函数中使用color参数。即使对迭代函数的调用返回,因为我们在调用中创建了一个函数并保留了对它的引用,该函数也保留了对上下文的引用(它是上下文上的闭包),因此我们可以依赖于color参数。更多关于闭包的信息(在我的博客上):闭包并不复杂

但是,由于painter.draw将颜色作为第一个参数,将工具作为第二个参数,如果你愿意,还有第二种方法可以做到:你可以在painter.draw:上使用Function#bind(一种ES5功能,可以在越来越少的没有它的旧引擎上填充)将颜色参数"咖喱"到方法中

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

Function#bind返回一个函数,当调用该函数时,该函数调用具有给定this值(上例中为painter)的原始函数,以及提供给bind的任何其他参数,然后是提供给原始函数的任何参数。一个简单的例子可能会让这一点变得更清楚:

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>