在 JS 对象的不同实例之间正确隔离数据
Isolating data correctly between different instances of JS objects
直到今天我才知道这个问题,我想知道解决这个问题的最佳方法是什么。问题是,当您从同一构造函数实例化两个不同的对象时,它们共享相同的原型,这意味着如果一个对象设置了该原型,则所有其他对象也将更改。
例如:
function A(obj) {
}
A.prototype = {
events: {
one: 1
}
};
var b = new A();
console.log(b.events);
var c = new A();
console.log(c.events);
b.events.x = 2;
console.log(b.events);
console.log(c.events); //whoops, c also got b's event x
什么鬼?解决这个问题的最佳方法是什么?
这就是我想出的,但我想知道是否有更好的方法?
var _ = require('underscore');
function A(obj) {
if (obj == null) {
obj = {};
}
if(obj.events == null){
obj.events = {};
}
this.events = _.extend(obj.events, A.prototype.events);
}
A.prototype = {
events: {
one: 1
}
};
var b = new A({events:{three:3}});
console.log(b.events);
var c = new A({events:{four:4}});
console.log(c.events);
b.events.x = 2;
console.log(b.events);
console.log(c.events); //now it's better...(this is crazy)
正如您所发现的,原型在给定对象的所有实例之间共享。 这样做有几个原因,包括存储效率。 因此,您应该只将打算在所有实例之间相同共享的内容放在原型中。
如果您希望某些内容成为实例变量,该变量可以为每个单独的实例具有唯一值,则它不属于原型。 它属于实例变量,通过this
指针设置。
因此,如果您的 event
属性旨在成为每个实例可能不同的实例变量,请在构造函数中初始化它,它对于每个单独的实例都是唯一的。
function A(obj) {
this.events = {one: 1};
}
并将其从原型中删除。 请记住,原型是为给定类型对象的所有实例之间相同共享的内容而设计的。 这就是为什么它非常适合方法,很少用于可修改的数据。
工作代码示例:
function A() {
this.events = {one: 1};
}
var x = new A();
var y = new A();
log(x.events);
log(y.events);
log("--------------");
x.events.one = 2;
y.events.one = 3;
log(x.events);
log(y.events);
function log(x) {
var d = document.createElement("div");
if (typeof x === "object") {
x = JSON.stringify(x);
}
d.textContent = x;
document.body.appendChild(d);
}
为什么这么复杂?
function A(obj) {
this.events = {
one: 1
};
}
你不应该在原型中保存变量,而应该在你的构造函数中使用它。在您的情况下,解决方案将是:
function A(obj) {
this.events = {
one: 1
};
}
var b = new A();
console.log(b.events);
var c = new A();
console.log(c.events);
b.events.x = 2;
console.log(b.events);
console.log(c.events);
第一步是学习原型遗传。
所有原型继承都是对值的实时引用......
而在被子里,
A.prototype.method = function foo () { };
var a = new A();
a.__proto__.method === a.constructor.prototype.method;
a.__proto__ === A.prototype;
除非您将".prototype"的值更改为新对象......然后,旧实例将指向旧原型对象,新实例将指向新原型对象。
这是基本的深拷贝与浅拷贝,价值与参考的东西。私有变量没有Java/C#继承,除了通过闭包(看起来不像Java/C#)。
如果你要把东西放在原型上,它们应该只是方法,以及每个实例静态可用的常量/枚举(因为在创建实例时对.constructor.prototype
的值的实时引用)。
实际上,除非你处于核心内存池优化模式,否则在 ES6 类可用之前(人们理解它们---它们只是.prototype
的包装器),这是比它的价值更精神上的麻烦,并且通常(尽管并非总是)更雄辩地简单地构建你需要的东西,或使用 mixins,而不是瞄准看起来像 Java 的 JS(但行为非常, 非常不同)。
- 函数参数中的数据与指定变量之间的任何性能差异
- 全局变量和全局对象的属性之间有什么区别吗
- java.net和javascript之间正则表达式的差异
- JavaScript中的函数和对象之间没有区别吗?
- 获取@ResponseBody的一部分作为主干和Spring MVC控制器之间的参数
- Jquery在函数之间传递表行
- 根据某些条件在视图之间切换
- 在控制器和数据对象之间同步数据
- 如何使用ngrepeat和双向绑定获得指令的隔离范围
- d3中堆栈函数和嵌套函数之间的差异
- JQuery:在页面之间滑动
- 如何使用JavaScript查找1和N之间的所有数字的总和
- 从控制器继承了隔离的作用域以生成可重用的指令
- 操作放置在画布上的元素之间的连接
- 在下划线中使用_(obj).map(callback)和_.map(obj,callback)之间的区别
- 隔离作用域+绑定名称和仅在AngularJS中的隔离作用域之间的差异
- AngularJS:在两个具有隔离作用域的指令之间共享一个控制器作用域
- 在隔离作用域指令中,在作用域上定义变量和在控制器上定义变量之间有什么区别吗?
- AngularJS:如何在两个隔离的控制器和一个共享服务之间创建一个双向数据绑定
- 在 JS 对象的不同实例之间正确隔离数据