复制自己的对象而不是引用(更新的帖子,不同的Q)

时间:2014-02-28 12:41:16

标签: javascript oop

溶液

我仍然掌握它,以及它对你们很多人的概率逻辑。但是我已经更新了帖子,告诉我如何使用它,有些人可能会通过搜索来到这里。

声明:

var test=Element({"id" : 1, "name" : "wrapper"}).
      append(Element({"id" : 2, "name" : "elm A"}),
             Element({"id" : 3, "name" : "elm b"})
      );

alert(test.getInfo("name"));
alert(test.aArguments["children"][1].getInfo("name"));

'类':

var Element = function ($aPassArguments) {
    aArguments: {
            "id" : false,
            "name" : false,
            "type" : false,
            "title" : false, 
            "style" : false,
            "action" : [],
            "parent" : false,
            "children" : []
        };
    for (var prop in this.aArguments)
            if (prop in $aPassArguments) 
                this.aArguments[prop] = $aPassArguments[prop];
    return {
        append: function () {
            $argList = arguments;
            for ($i = 0; $i < $argList.length; $i++)
                if (typeof $argList[$i]=="string")
                    this.setChild(this.importDB($argList[$i],true));
                else
                    this.setChild($argList[$i]);
        },
         setChild: function($oChild) {
            this.aArguments["children"][this.aArguments["children"].length]=$oChild; 
        }
    };
};

............................................... ..............

以前的编辑

我不知道javascript中的新对象实例是引用而不是副本。现在我想拥有自己的对象元素的副本。显然(感谢@blurd)我希望它成为工厂混合体:  http://javascript.info/tutorial/factory-constructor-pattern

感谢@blurd的帮助和我定义了一些问题,我想出了如下的解决方案:

(但我不满意下面的使用声明)

我最终获得了Element对象的副本而不是引用。下面的好答案并没有完全解决我的问题。但这是由于我对问题的澄清和理解不足

解决方案

var Element = function (initialConfig) {

    return {
        aArguments: {
            "id" : false,
            "name" : false,
            "type" : false,
            "title" : false, 
            "style" : false,
            "action" : [],
            "parent" : false,
            "children" : [],
        },


        create:function ($aPassArguments) {
            for (var prop in this.aArguments)
                if (prop in $aPassArguments) 
                    this.aArguments[prop] = $aPassArguments[prop];
        },
        append: function () {
            $argList = arguments;
            for ($i = 0; $i < $argList.length; $i++)
                if (typeof $argList[$i]=="string")
                    this.setChild(this.importDB($argList[$i],true));
                else
                    this.setChild($argList[$i]);
        },
         setChild: function($oChild) {
            this.aArguments["children"][this.aArguments["children"].length]=$oChild; 
        }
    };
};

使用

var test=Element();
test.create({"id" : 1, "name" : "wrapper"});
var test2=Element();
test2.create({"id" : 2, "name" : "elm A"});
test3.create({"id" : 3, "name" : "elm B"});
test.append(test2,test3);

alert(test.aArguments["name"]);
alert(test.aArguments["children"][0].aArguments["name"]);

现在我对使用非常不满意,我希望它是一行并再次使用构造函数。这是可能的,并且......经过一些更多的自学,我将很快解决它。但是现在我已经完成了它:P刚刚更新了我的帖子。当我再次到达并有一个beter声明时,我会再次更新它。也许有人可能会分享一种方式(更好的方式)来做到这一点。最终有这样的事情:

var test=new Element({"id" : 3, "name" : "wrapper"})
           .append( new Element{"id" : 3, "name" : "elm A"}), 
                    new Element({"id" : 3, "name" : "elm B"}) 
                  );

............................................... ..............................................

旧帖子

我在这里拉我的头发,我搜索的关于javascript和对象的一切告诉我相同,这还不够,因为我无法弄清楚为什么下面的代码不能正常工作:

例如,我正在创建一个这样的对象:

var Element = {
    aArguments: {                                                       //set Default arguments
        "id" : false,
        "name" : false,
        "type" : false,
        "title" : false, 
        "style" : false,
        "action" : [],
        "parent" : false,
        "children" : {},
    },
    create:function ($aPassArguments) {
        for (var prop in this.aArguments)
            if (prop in $aPassArguments) 
                this.aArguments[prop] = $aPassArguments[prop];
        return this;
    },
    append: function () {
        $argList = arguments;
        for ($i = 0; $i < $argList.length-1; $i++)
            if (typeof $argList[$i]=="string")
                this.setChild(this.importDB($argList[$i],true));
            else
                this.setChild($argList[$i]);
        return this;
    },
    setChild: function($oChild) {
        this.aArguments["children"][this.aArguments["children"].length-1]=$oChild; 
    },
    getInfo: function($sKey) {
        return this.aArguments[$sKey];
    }
};

在调用 .create()时将 $ aPassArguments this.Arguments 合并(我无法想象它可以使用'__constructor “)。在 aArguments中替换给定的proparties。

.append 的传递对象添加到 aArguments [“childeren”]

但是当我这样称呼对象时:

$set=(Element.create({"id": 1, "name" : "wrapper"})).
     append(Element.create({"id" : 3, "name" : "elm A"}));
alert($set.getInfo("name"));

它会提醒我“榆树A”而不是“包装”。

我认为这是因为我没有创建Element的新对象,而是在处理同一个对象。现在对我来说逻辑解决方案并开始写:

$set=(new Element.create({"id": 1, "name" : "wrapper"})).
     append(new Element.create({"id" : 3, "name" : "elm A"}));
alert($set.getInfo("name"));

但我收到错误: TypeError :(中间值).append不是函数

为什么我的代码不能像我想象的那样工作? 是否有可能,如果是这样,我如何向对象添加构造函数?所以我可以跳过调用.create并使用:

 $set=new Element({"id": 1, "name" : "wrapper"}).
     append(new Element({"id" : 3, "name" : "elm A"}));

2 个答案:

答案 0 :(得分:1)

你是对的,你应该使用new运营商。除此之外,看起来你正在努力使这种类型的factory混合。我建议如下。

使用构造函数

包含可在创建对象时使用的可选配置。

var Element = function (initialConfig) {
    if (initialConfig) {
        this.create(initialConfig);
    }
};

添加到原型

所有共享的Element成员都应该成为prototype

的成员
Element.prototype = {
    aArguments: {
        "id" : false,
        "name" : false,
        "type" : false,
        "title" : false, 
        "style" : false,
        "action" : [],
        "parent" : false,
        "children" : {},
    },
    create:function ($aPassArguments) {
        for (var prop in this.aArguments)
            if (prop in $aPassArguments) 
                this.aArguments[prop] = $aPassArguments[prop];
        return this;
    },
    append: function () {
        $argList = arguments;
        for ($i = 0; $i < $argList.length-1; $i++)
            if (typeof $argList[$i]=="string")
                this.setChild(this.importDB($argList[$i],true));
            else
                this.setChild($argList[$i]);
        return this;
    },
    setChild: function($oChild) {
        this.aArguments["children"][this.aArguments["children"].length-1]=$oChild; 
    },
    getInfo: function($sKey) {
        return this.aArguments[$sKey];
    }
};

实施例

您的示例现在应该按预期工作。请注意,您无法调用new Element.create(),因为它会将Element.create视为构造函数。相反,将初始值传递给构造函数。

$set = new Element({"id": 1, "name" : "wrapper"}).
     append(new Element({"id" : 3, "name" : "elm A"}));

alert($set.getInfo("name"));

小心

您没有在循环中检查自己的属性,省略{},我发现至少有一个隐含的全局属性。如果你不小心,JavaScript会咬你。考虑使用JSLintJSHint来帮助您发现这些问题。

答案 1 :(得分:1)

您的create函数不会创建任何对象,而是更改Element. aArguments对象的位置。可能会有任何奇怪的事情发生 无论如何,只需要一个干净简单的原型继承方案,不要使用$,记得总是声明你的变量,并保持简单:

function Element(initialValues) {
    this.id = this.prototype.id++;
    this.name = null;
    this.type = null;
    this.title = null;
    this.style = null;
    this.action = [];
    this.parent = null;
    this.children = [];
    for (var prop in initialValues)
        if (this[prop] != undefined) this[prop] = initialValues[prop];
}

Element.prototype = {
    append: function () {
        for (var i = 0; i < arguments.length - 1; i++) {
            var thisElement = arguments[i];
            if (typeof thisElement == "string") this.setChild(this.importDB(thisElement, true));
            else this.setChild(thisElement);
        }
        return this;
    },
    setChild: function (child) {
        this.children.push(child);
        return this;
    },
    getInfo: function (key) {
        return this[Key];
    },
    id: 0
};