那是因为options
是类的属性(在其原型上),而不是对象。
通过将其添加到第二个示例的底部来验证它:
console.log( p.options == p2.options ); // true
解释:
使用抽象层时,记住底层原理非常重要,这样您就不会被抽象的泄漏所困扰。
你的第一个例子:
让我们用常规的原型继承重写你的类定义:
var Person = function (options) {
if (options) {
this.options = options;
}
};
Person.prototype.options = {value: 2};
var john = new Person();
john
现在将是一个新实例,并且Person
没有属性options
:
john.hasOwnProperty('options'); // false
尝试访问options
viajohn.options
时,您将从{value: 2}
原型链中获得 。
但是,如果您要通过向构造函数提供您来创建这个新Person
对象:options
var michael = new Person({value:5});
michael
将有一个options
属性:
michael.hasOwnProperty('options'); // true
这是一个比较两者的简单测试:
john.options == Person.prototype.options // true
michael.options == Person.prototype.options // false
你的第二个例子:
现在考虑你的第二个例子,用原生原型继承编写:
var Person = function (options) {
if (options) {
for (var name in options) {
this.options[name] = options[name];
}
}
};
Person.prototype.options = {value: 2};
不管你是否传入options
构造函数,你的新对象永远不会有自己的options
属性。你所做的只是options
在原型上增加:
var john = new Person();
john.options // {value:2}
john.hasOwnProperty('options'); // false
john.options == Person.prototype.options // true
var michael = new Person({value:5});
michael.options // {value:5}
michael.hasOwnProperty('options'); // false
michael.options == Person.prototype.options // true
john.options // {value:5}
// Why? Because they share the same `options` property from the prototype
john.options == michael.options // true
如果您随后将新对象分配给john
,则不会影响options
原型上的 :
john.options = {value:10};
john.options // {value:10}
john.options == Person.prototype.options // false
michael.options // {value:5}
michael.options == john.options // false
michael.options == Person.prototype.options // true
解决方案:
要在第二个示例中获得所需的功能,您必须执行以下步骤:
options
从构造函数(init
方法)中创建一个新属性。
- 复制所有属性
Person.prototype.options
。
- 最后,复制
options
参数中的所有属性。
您可以这样做:
var Person = Class.extend({
options: {value: 2},
init: function(options) {
if (options) {
var name, prototypeOptions = Person.prototype.options;
this.options = {};
for (name in prototypeOptions) {
this.options[name] = prototypeOptions[name];
}
for (name in options) {
this.options[name] = options[name];
}
}
}
});
如果你使用jQuery或underscore,你可以使用他们的extend
方法,这使得这一切变得微不足道:
var Person = Class.extend({
options: {value: 2},
init: function(options) {
if (options) {
this.options = $.extend({}, Person.prototype.options, options);
}
}
});
更简单的解决方案:
根据您的需要,您甚至可能一开始就不需要options
在原型上。只需将它添加到构造函数(init
方法)中的对象中,然后完成它:
var Person = Class.extend({
init: function(options) {
this.options = {value: 2};
if (options) {
for (var name in options) {
this.options[name] = options[name];
}
}
}
});
再一次,如果您使用 jQuery 或下划线,这将变得更加简单:
var Person = Class.extend({
init: function(options) {
this.options = _.extend({value: 2}, options);
}
});