【问题标题】:Javascript: Add method to all objects in arrayJavascript:向数组中的所有对象添加方法
【发布时间】:2014-01-08 01:45:13
【问题描述】:

想象一下下面的代码:

$.get( "ajax/getColorData.php", function( data ) {
  this.colorData = data;
});

现在设想“数据”的值是:

this.colorData = [
    {
        colorName: 'Red',
        colorIsInRainbow:true
    },
    {
        colorName: 'Orange',
        colorIsInRainbow: true
    },
    {
        colorName: 'Magenta',
        colorIsInRainbow: false
    }
];

问题 1

现在,在我下载数据后,假设我想为数组中的每个条目添加一个方法“colorStartsWithR”。我“认为”与其在数组的每个成员上定义它,不如在原型上以某种方式定义这个方法。但是,我不确定我能做到这一点,因为这些对象不是我创建的,而是由 $.get 返回的,所以我不清楚我的想法是否正确。

问题 2

更进一步,如果我想为数组的每个成员添加一个属性怎么办,具体来说:

    {
        colorName: 'Magenta',
        colorIsInRainbow: false,
        userClickedThisColor:ko.observable()
    }

这样,我可以绑定(通过 knockoutjs)列表并包含一个复选框。在这种情况下,我怀疑原型是否会派上用场,因为每个成员都应该有自己的 ko.observable 属性。一个快速的直觉是做类似的事情:

for (var i=0;i<this.colorData.length;i++)
{
 this.colorData[i].userClickedThisColor=ko.observable()
}

这很好用,但想象一下检索颜色列表的方法不止一种,或者用户可以创建新的颜色实例,而且我上面所做的自定义更复杂。我现在需要复制上面的“附加”逻辑。有没有更聪明的方法?

我大部分时间都在使用强类型语言,有时这些事情对我来说并不那么明显。感谢您的任何建议...

-本

【问题讨论】:

  • 为什么要为每个对象添加函数?只需创建一个接受对象作为参数的函数。

标签: javascript arrays function-prototypes function-constructor


【解决方案1】:

嗯,这些对象没有特殊的原型,所以你不能向它添加成员。我认为这些是替代方案:

1) 将成员添加到每个实例(我知道您不喜欢它,但这是一个选项)。我会选择这个选项

2) 只需创建一个方法,并将每个对象作为参数传递或作为thisfn.call() 传递

3) 使用添加的成员创建一个“类”,然后在构造函数中通过原始对象创建它的实例。不理想,但也许你必须这样做。

function Color(plainObj){
   this.colorName: plainObj.colorName;
   this.colorIsInRainbow: plainObj.colorIsInRainbow;

   //if you want all properties to be copied dynamically, uncomment the following:
   //for(var key in plainObj) this[key] = plainObj[key];                 

   this.userClickedThisColor = ko.observable()
   ...
}
Color.prototype.colorStartsWithR = function() {
    return this.colorName.charAt(0) == "R";
};

//etc

然后,应用它

for(var i=0; i<colorData.length; i++){
   colorData[i] = new Color(colorData[i]); //Overwrites original colorData array
}

希望这会有所帮助。干杯

【讨论】:

  • 谢谢埃德加!我只能将一个帖子标记为答案,尽管您的帖子也很有帮助。
  • 谢谢!所以,只是为了确认这一行: Color.prototype.userClickedThisColor = ko.observable();我是否正确,尽管原型中已定义,但每个实例确实会获得自己的单独副本?
  • 不,所有人都将共享相同的内容。对于每一个都有不同的,你应该把它移到构造函数中
  • 为其他人添加注释:似乎在上面的构造函数中,您可以改为动态枚举对象的所有属性以将它们复制过来。这样,如果添加或删除属性,则无需更新该部分代码。 stackoverflow.com/questions/85992/…
  • 没错。因为在这种情况下它们只有 2 个,所以我手动添加它们(更短的代码)。 4个或更多,最好自动完成
【解决方案2】:

一种选择是创建一个包装器对象并将新方法添加到包装器原型中:

var colorData = [
    {
        colorName: 'Red',
        colorIsInRainbow:true
    },
    {
        colorName: 'Orange',
        colorIsInRainbow: true
    },
    {
        colorName: 'Magenta',
        colorIsInRainbow: false
    }
];

function ColorDataWrapper(colorData){
   this.colorData = colorData;
}

ColorDataWrapper.prototype.colorStartsWithR = function(){
   return this.colorData.colorName.substring(0,1) == "R";
};

for(var i = 0; i < colorData.length; i++){
   colorData[i] = new ColorDataWrapper(colorData[i]);
}

alert(colorData[0].colorStartsWithR());
alert(colorData[1].colorStartsWithR());

JS 小提琴: http://jsfiddle.net/ywrK6/1/

另一种选择是创建一个接受对象作为参数的函数:

function colorStartsWithR(obj){
    return obj.colorData.colorName.substring(0,1) == "R";
}

【讨论】:

  • 主要为我的笔记添加评论:看起来在这个解决方案中,ColorDataWrapper 函数创建的包装器级别高于其他解决方案,这意味着不需要接受参数对于每个成员(jfriend00 的示例),或进行动态属性枚举(Edgar 的示例)。这很好,因为它很简单,但是在该方法中,您在方法 colorStartsWithR 中有一个额外的间接级别(这似乎是为了简单而付出的小代价)。只是想指出这一点(如果我理解正确的话)。
  • 如果要循环遍历数组中的所有元素,那么您只需将方法colorStartsWithR() 直接添加到数组中的每个对象即可。该方法不必在原型上 - 它可以直接添加到对象中。无需用其他类型的对象替换该对象。
【解决方案3】:

数组中的对象是Object 类型的普通对象。要将方法添加到这些对象的原型,您必须将方法添加到 Object 类型,如下所示:

Object.prototype.colorStartsWithR = function() {
    return this.colorName.substr(0,1) == "R";
}

这在这种情况下会起作用,但确实不推荐。更好的解决方案是将数组中的对象更改为具有自己的原型的不同类型的对象,您可以将colorStartsWithR() 添加到其中,或者仅使用实用程序函数来测试名称以查看是否以“R "`。

这里是例子:

function colorObj(color, inRainbow) {
    this.colorName = color;
    this.colorIsInRainbow = inRainbow;
}

colorObj.prototype.colorStartsWithR = function() {
        return this.colorName.substr(0,1) == "R";
}

this.colorData = [
    new colorObj('Red', true),
    new colorObj('Orange, true),
    new colorObj('Magenta, false)
};

那么,你可以这样做:

this.colorData[1].colorStartsWithR();

或者,只是一个实用函数:

var colorData = [
    {
        colorName: 'Red',
        colorIsInRainbow:true
    },
    {
        colorName: 'Orange',
        colorIsInRainbow: true
    },
    {
        colorName: 'Magenta',
        colorIsInRainbow: false
    }
];

function startsWithR(str) {
    return str.substr(0,1) == "R";

}

startsWithR(colorData[1].colorName);

【讨论】:

    猜你喜欢
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-09
    • 2016-08-09
    相关资源
    最近更新 更多