Javascript - 创建没有引用的对象
Javascript - Create object without reference
我在没有引用的情况下创建对象实例时遇到问题。
我研究发现很多人建议使用 jQuery.extend
创建没有引用的对象。
参考:
What is the most efficient way to deep clone an object in JavaScript?
但在我的案例中没有成功。
这是我的代码
JSBin
var MyModel = (function() {
MyModel = function() {};
var myModelObj = {
prop1: null,
prop2: {
sub1: null,
sub2: null
}
};
MyModel.prototype = {
getProp1: function() {
return myModelObj.prop1;
},
getSub1: function() {
return myModelObj.prop2.sub1;
},
getSub2: function() {
return myModelObj.prop2.sub2;
},
setProp1: function(val) {
myModelObj.prop1 = val;
},
setSub1: function(val) {
myModelObj.prop2.sub1 = val;
},
setSub2: function(val) {
myModelObj.prop2.sub2 = val;
},
getObj: function() {
return $.extend({}, myModelObj);
},
setObj: function(json_obj) {
myModelObj.prop1 = json_obj.prop1;
myModelObj.prop2.sub1 = json_obj.prop2.sub1;
myModelObj.prop2.sub2 = json_obj.prop2.sub2;
},
setParam: function(prop1, sub1, sub2) {
myModelObj.prop1 = prop1;
myModelObj.prop2.sub1 = sub1;
myModelObj.prop2.sub2 = sub2;
}
};
return MyModel;
}());
var model1 = new MyModel();
model1.setParam('prop1', 'sub1', 'sub2');
var model2 = new MyModel();
model2.setParam('clone-prop1', 'clone-sub1', 'clone-sub2');
console.log("object 1");
console.log(model1.getObj());
console.log("object 2");
console.log(model2.getObj());
我的预期结果是
model1 = {
prop1: 'prop1',
prop2: {
sub1: 'sub1',
sub2: 'sub2'
}
}
model2 = {
prop1: 'clone-prop1',
prop2: {
sub1: 'clone-sub1',
sub2: 'clone-sub2'
}
}
但实际上,model1
和model2
有相同的数据model2
。
谁能指出我错在哪里?
=== 更新 ===
@arcyqwerty 的解决方案帮助我解决了在没有引用的情况下创建对象的问题。
var MyModel = function() {
this.prop1 = null;
this.prop2 = {
sub1: null,
sub2: null
};
};
MyModel.prototype = {
getProp1: function() {
return this.prop1;
},
getSub1: function() {
return this.prop2.sub1;
},
getSub2: function() {
return this.prop2.sub2;
},
setProp1: function(val) {
this.prop1 = val;
},
setSub1: function(val) {
this.prop2.sub1 = val;
},
setSub2: function(val) {
this.prop2.sub2 = val;
},
getObj: function() {
return $.extend({}, this);
},
setObj: function(json_obj) {
this.prop1 = json_obj.prop1;
this.prop2.sub1 = json_obj.prop2.sub1;
this.prop2.sub2 = json_obj.prop2.sub2;
},
setParam: function(prop1, sub1, sub2) {
this.prop1 = prop1;
this.prop2.sub1 = sub1;
this.prop2.sub2 = sub2;
}
};
var model1 = new MyModel();
model1.setParam('prop1', 'sub1', 'sub2');
var model2 = new MyModel();
model2.setParam('clone-prop1', 'clone-sub1', 'clone-sub2');
console.log("object 1");
console.log(model1.getObj());
console.log("object 2");
console.log(model2.getObj());
但我还想在 OOP
中使用 encapsulation
功能。这意味着,我们只通过 get
函数获取值对象 属性。在 Javascript
上可以吗?
它解释了为什么我在模型中有一个对象(但它引用了同一个对象)
非常感谢!
试试这个
var MyModel = function() {
this.prop1 = null;
this.prop2 = {
sub1: null,
sub2: null
};
};
MyModel.prototype = {
getProp1: function() {
return this.prop1;
},
getSub1: function() {
return this.prop2.sub1;
},
getSub2: function() {
return this.prop2.sub2;
},
setProp1: function(val) {
this.prop1 = val;
},
setSub1: function(val) {
this.prop2.sub1 = val;
},
setSub2: function(val) {
this.prop2.sub2 = val;
},
getObj: function() {
return $.extend({}, this);
},
setObj: function(json_obj) {
this.prop1 = json_obj.prop1;
this.prop2.sub1 = json_obj.prop2.sub1;
this.prop2.sub2 = json_obj.prop2.sub2;
},
setParam: function(prop1, sub1, sub2) {
this.prop1 = prop1;
this.prop2.sub1 = sub1;
this.prop2.sub2 = sub2;
}
};
var model1 = new MyModel();
model1.setParam('prop1', 'sub1', 'sub2');
var model2 = new MyModel();
model2.setParam('clone-prop1', 'clone-sub1', 'clone-sub2');
console.log("object 1");
console.log(model1.getObj());
console.log("object 2");
console.log(model2.getObj());
您的原始构造函数的问题是 MyModel
的实例,尽管使用 new
关键字创建的不同对象都共享相同的 myModelObj
(仅创建一次).使用此解决方案,每次创建新的 MyModel
.
时都会创建新字段
这类似于使用 MyModel = function() { this.myModelObj = {...}; }
和使用 this.myModelObj.prop
访问字段,但此时 myModelObj
有点多余,因为您可以在 [=22= 上设置属性] 直接。
此外,使用此解决方案,您可以直接使用 model1.prop
而无需说 model1.getObj().prop
(尽管这也有效)
--
注:我看到也有点奇怪
var ClassName = (function() {
ClassName = function() { ...; };
ClassName.prototype = { ... };
return ClassName;
})();
你这样做而不是
有什么原因吗
var ClassName = function() { ... };
ClassName.prototype = { ... };
?
如果你不想用 myModelObj
污染命名空间,我想这在原始代码中是有意义的,但否则似乎没有必要。
--
编辑:封装
如果您需要通过 getters/setters 设置对象的属性,您可以尝试这样的操作:
var MyModel = function() {
var privateObject = {
prop1: null,
prop2: {
sub1: null,
sub2: null
}
};
Object.defineProperty(this, 'prop1', {
get: function() {
console.log('Getting prop1 through getter');
return privateObject.prop1;
},
set: function(value) {
console.log('Setting prop1 through setter');
privateObject.prop1 = value;
}
});
};
缺点是您将无法使用原型链共享 getter/setter 函数,这意味着您将有很多函数对象。对于少数情况,这可能很好(性能方面)。它也会影响继承,如果你的 class 有子classes.
如果您在没有 defineProperty
的平台上,您也可以通过在构造函数中保留 var privateObject
并在构造函数中使用 this.getProp1 = function() { return privateObject.prop1; }
而不是原型来复制它.净效果类似于使用 defineProperty
.
--
编辑:或使用 getter/setter syntax
注意:返回的对象是不是一个instanceof
F
.
function F() {
var fields = { prop: null };
return {
get prop() {
console.log("getter");
return fields.prop;
},
set prop(value) {
console.log("setter");
fields.prop = value;
}
};
}
f = new F
f.prop = 123
f.prop
arcyqwerty 答案的这种变体展示了对数据的更深入封装。权衡是每个实例都有自己的方法副本,而不是在 "class" 级别共享它们:
var MyModel = function() {
var prop1 = null;
var prop2 = {
sub1: null,
sub2: null
};
this.getProp1 = function() {
return prop1;
};
this.getSub1 = function() {
return prop2.sub1;
};
this.getSub2 = function() {
return prop2.sub2;
};
this.setProp1 = function(val) {
prop1 = val;
};
this.setSub1 = function(val) {
prop2.sub1 = val;
};
this.setSub2 = function(val) {
prop2.sub2 = val;
};
this.getObj = function() {
return {
prop1: prop1,
prop2: {
sub1: prop2.sub1,
sub2: prop2.sub2
}
};
};
this.setObj = function(json_obj) {
prop1 = json_obj.prop1;
prop2.sub1 = json_obj.prop2.sub1;
prop2.sub2 = json_obj.prop2.sub2;
};
this.setParam = function(_prop1, _sub1, _sub2) {
prop1 = _prop1;
prop2.sub1 = _sub1;
prop2.sub2 = _sub2;
};
};
你说,
But I wonder how we protect properties on Javascript
?
我认为这是错误的问题。 JS 是一种不同的语言,与 Java 或 Ruby 有不同的关注点。它至少与 OO 语言一样是一种功能语言。当你在做 JS 时,你可能不应该试图表现得好像你在 Java 工作,而是应该学习它的习惯。
我在没有引用的情况下创建对象实例时遇到问题。
我研究发现很多人建议使用 jQuery.extend
创建没有引用的对象。
参考: What is the most efficient way to deep clone an object in JavaScript?
但在我的案例中没有成功。
这是我的代码 JSBin
var MyModel = (function() {
MyModel = function() {};
var myModelObj = {
prop1: null,
prop2: {
sub1: null,
sub2: null
}
};
MyModel.prototype = {
getProp1: function() {
return myModelObj.prop1;
},
getSub1: function() {
return myModelObj.prop2.sub1;
},
getSub2: function() {
return myModelObj.prop2.sub2;
},
setProp1: function(val) {
myModelObj.prop1 = val;
},
setSub1: function(val) {
myModelObj.prop2.sub1 = val;
},
setSub2: function(val) {
myModelObj.prop2.sub2 = val;
},
getObj: function() {
return $.extend({}, myModelObj);
},
setObj: function(json_obj) {
myModelObj.prop1 = json_obj.prop1;
myModelObj.prop2.sub1 = json_obj.prop2.sub1;
myModelObj.prop2.sub2 = json_obj.prop2.sub2;
},
setParam: function(prop1, sub1, sub2) {
myModelObj.prop1 = prop1;
myModelObj.prop2.sub1 = sub1;
myModelObj.prop2.sub2 = sub2;
}
};
return MyModel;
}());
var model1 = new MyModel();
model1.setParam('prop1', 'sub1', 'sub2');
var model2 = new MyModel();
model2.setParam('clone-prop1', 'clone-sub1', 'clone-sub2');
console.log("object 1");
console.log(model1.getObj());
console.log("object 2");
console.log(model2.getObj());
我的预期结果是
model1 = {
prop1: 'prop1',
prop2: {
sub1: 'sub1',
sub2: 'sub2'
}
}
model2 = {
prop1: 'clone-prop1',
prop2: {
sub1: 'clone-sub1',
sub2: 'clone-sub2'
}
}
但实际上,model1
和model2
有相同的数据model2
。
谁能指出我错在哪里?
=== 更新 ===
@arcyqwerty 的解决方案帮助我解决了在没有引用的情况下创建对象的问题。
var MyModel = function() {
this.prop1 = null;
this.prop2 = {
sub1: null,
sub2: null
};
};
MyModel.prototype = {
getProp1: function() {
return this.prop1;
},
getSub1: function() {
return this.prop2.sub1;
},
getSub2: function() {
return this.prop2.sub2;
},
setProp1: function(val) {
this.prop1 = val;
},
setSub1: function(val) {
this.prop2.sub1 = val;
},
setSub2: function(val) {
this.prop2.sub2 = val;
},
getObj: function() {
return $.extend({}, this);
},
setObj: function(json_obj) {
this.prop1 = json_obj.prop1;
this.prop2.sub1 = json_obj.prop2.sub1;
this.prop2.sub2 = json_obj.prop2.sub2;
},
setParam: function(prop1, sub1, sub2) {
this.prop1 = prop1;
this.prop2.sub1 = sub1;
this.prop2.sub2 = sub2;
}
};
var model1 = new MyModel();
model1.setParam('prop1', 'sub1', 'sub2');
var model2 = new MyModel();
model2.setParam('clone-prop1', 'clone-sub1', 'clone-sub2');
console.log("object 1");
console.log(model1.getObj());
console.log("object 2");
console.log(model2.getObj());
但我还想在 OOP
中使用 encapsulation
功能。这意味着,我们只通过 get
函数获取值对象 属性。在 Javascript
上可以吗?
它解释了为什么我在模型中有一个对象(但它引用了同一个对象)
非常感谢!
试试这个
var MyModel = function() {
this.prop1 = null;
this.prop2 = {
sub1: null,
sub2: null
};
};
MyModel.prototype = {
getProp1: function() {
return this.prop1;
},
getSub1: function() {
return this.prop2.sub1;
},
getSub2: function() {
return this.prop2.sub2;
},
setProp1: function(val) {
this.prop1 = val;
},
setSub1: function(val) {
this.prop2.sub1 = val;
},
setSub2: function(val) {
this.prop2.sub2 = val;
},
getObj: function() {
return $.extend({}, this);
},
setObj: function(json_obj) {
this.prop1 = json_obj.prop1;
this.prop2.sub1 = json_obj.prop2.sub1;
this.prop2.sub2 = json_obj.prop2.sub2;
},
setParam: function(prop1, sub1, sub2) {
this.prop1 = prop1;
this.prop2.sub1 = sub1;
this.prop2.sub2 = sub2;
}
};
var model1 = new MyModel();
model1.setParam('prop1', 'sub1', 'sub2');
var model2 = new MyModel();
model2.setParam('clone-prop1', 'clone-sub1', 'clone-sub2');
console.log("object 1");
console.log(model1.getObj());
console.log("object 2");
console.log(model2.getObj());
您的原始构造函数的问题是 MyModel
的实例,尽管使用 new
关键字创建的不同对象都共享相同的 myModelObj
(仅创建一次).使用此解决方案,每次创建新的 MyModel
.
这类似于使用 MyModel = function() { this.myModelObj = {...}; }
和使用 this.myModelObj.prop
访问字段,但此时 myModelObj
有点多余,因为您可以在 [=22= 上设置属性] 直接。
此外,使用此解决方案,您可以直接使用 model1.prop
而无需说 model1.getObj().prop
(尽管这也有效)
--
注:我看到也有点奇怪
var ClassName = (function() {
ClassName = function() { ...; };
ClassName.prototype = { ... };
return ClassName;
})();
你这样做而不是
有什么原因吗var ClassName = function() { ... };
ClassName.prototype = { ... };
?
如果你不想用 myModelObj
污染命名空间,我想这在原始代码中是有意义的,但否则似乎没有必要。
--
编辑:封装
如果您需要通过 getters/setters 设置对象的属性,您可以尝试这样的操作:
var MyModel = function() {
var privateObject = {
prop1: null,
prop2: {
sub1: null,
sub2: null
}
};
Object.defineProperty(this, 'prop1', {
get: function() {
console.log('Getting prop1 through getter');
return privateObject.prop1;
},
set: function(value) {
console.log('Setting prop1 through setter');
privateObject.prop1 = value;
}
});
};
缺点是您将无法使用原型链共享 getter/setter 函数,这意味着您将有很多函数对象。对于少数情况,这可能很好(性能方面)。它也会影响继承,如果你的 class 有子classes.
如果您在没有 defineProperty
的平台上,您也可以通过在构造函数中保留 var privateObject
并在构造函数中使用 this.getProp1 = function() { return privateObject.prop1; }
而不是原型来复制它.净效果类似于使用 defineProperty
.
--
编辑:或使用 getter/setter syntax
注意:返回的对象是不是一个instanceof
F
.
function F() {
var fields = { prop: null };
return {
get prop() {
console.log("getter");
return fields.prop;
},
set prop(value) {
console.log("setter");
fields.prop = value;
}
};
}
f = new F
f.prop = 123
f.prop
arcyqwerty 答案的这种变体展示了对数据的更深入封装。权衡是每个实例都有自己的方法副本,而不是在 "class" 级别共享它们:
var MyModel = function() {
var prop1 = null;
var prop2 = {
sub1: null,
sub2: null
};
this.getProp1 = function() {
return prop1;
};
this.getSub1 = function() {
return prop2.sub1;
};
this.getSub2 = function() {
return prop2.sub2;
};
this.setProp1 = function(val) {
prop1 = val;
};
this.setSub1 = function(val) {
prop2.sub1 = val;
};
this.setSub2 = function(val) {
prop2.sub2 = val;
};
this.getObj = function() {
return {
prop1: prop1,
prop2: {
sub1: prop2.sub1,
sub2: prop2.sub2
}
};
};
this.setObj = function(json_obj) {
prop1 = json_obj.prop1;
prop2.sub1 = json_obj.prop2.sub1;
prop2.sub2 = json_obj.prop2.sub2;
};
this.setParam = function(_prop1, _sub1, _sub2) {
prop1 = _prop1;
prop2.sub1 = _sub1;
prop2.sub2 = _sub2;
};
};
你说,
But I wonder how we protect properties on
Javascript
?
我认为这是错误的问题。 JS 是一种不同的语言,与 Java 或 Ruby 有不同的关注点。它至少与 OO 语言一样是一种功能语言。当你在做 JS 时,你可能不应该试图表现得好像你在 Java 工作,而是应该学习它的习惯。