Javascript 定义一个函数,扩展函数原型,创建两个实例,原型是否被修改?
有人能告诉我为什么结果是这样,而不是我所期望的那样吗。这简直快把我逼疯了Javascript 定义一个函数,扩展函数原型,创建两个实例,原型是否被修改?,javascript,function-prototypes,Javascript,Function Prototypes,有人能告诉我为什么结果是这样,而不是我所期望的那样吗。这简直快把我逼疯了 var f = function(b){ console.log(this.config); this.config.b = b; } f.prototype.config = { a: 'a', b: 'b' }; var f1 = new f('bb'); var f2 = new f('bbb'); // logs // { a: 'a', b: 'b' } // { a: 'a'
var f = function(b){
console.log(this.config);
this.config.b = b;
}
f.prototype.config = {
a: 'a',
b: 'b'
};
var f1 = new f('bb');
var f2 = new f('bbb');
// logs
// { a: 'a', b: 'b' }
// { a: 'a', b: 'bb' }
// expected
// { a: 'a', b: 'b' }
// { a: 'a', b: 'b' }
被修改的不是原型,而是您放在原型上的
config
对象。这是正确的行为,创建新实例时不会复制原型引用的对象f1.config===f2.config
,它们指向同一个对象
原型链用于get
操作的方式如下:
this.config
config
,因此我们继续下一步undefined
set
操作的工作方式不同;set
操作始终会更新或在其所设置的对象上创建属性,而不会在原型链的下方(向上?])
因此,在您的例子中,由于您的实例没有config
属性,因此我们转到原型。因为原型确实有一个config
属性,所以使用它。属性的值是一个对象引用,因此,如果更改对象(通过指定给其属性之一),该对象将被更改,并且任何其他使用该对象的对象都将看到更改
另一种方法是绘制图表:
+------+ +------+
| f1 | | f2 |
+------+ +------+
| |
+------+-------+
|
v
+--------------------+ +--------+
| [[Proto]] assigned | | config |
| via `new f` |------>| object |
+--------------------+ +--------+
|
+-------+-------+
| |
V v
+------------+ +------------+
| a property | | b property |
+------------+ +------------+
这是通过new f()
在封面下发生的真实情况。您不能直接访问指向原型的f1
和f2
实例的属性(规范称之为[[Proto]]]
属性),但它是真实的,而且确实存在。[FYI:ECMAScript规范允许我们直接使用[[Proto]]
属性执行一些操作,例如使用特定的[[Proto]]]
创建原始对象(无需通过函数),但仍然不允许我们直接访问属性本身。]
很多时候,您希望所有实例共享同一个对象(例如函数对象!),因此原型是这些对象引用的正确位置;但是,如果希望每个实例都有自己的对象副本,则需要在构造函数中创建该对象。就你而言:
var f = function(b){
this.config = {
a: 'a',
b: b
};
}
var f1 = new f('bb');
console.log(f1.config);
var f2 = new f('bbb');
console.log(f2.config);
//日志
//{a:'a',b:'bb'}
//{a:'a',b:'bbb'}
(注意,我移动了
console.log
语句,因此我们在末尾看到的是结果,而不是中间状态。)下面是一个很好的coffeescript示例,说明了问题:
Person = class
config:
name: "sin nombre"
constructor: (config={}) ->
@config.name = config.name if config.name?
getName: -> @config.name
Human = class extends Person
ben = new Human(name: 'Ben')
sonny = new Human()
alert ben.getName()
alert sonny.getName()
解决方案是:
Person = class
config:
name: "sin nombre"
constructor: (config={}) ->
@config = {}
@config[key] = value for own key, value of Person::config
@config.name = config.name if config.name?
getName: -> @config.name
Human = class extends Person
ben = new Human(name: 'Ben')
sonny = new Human()
alert ben.getName()
alert sonny.getName()
Person = class
config:
name: "sin nombre"
constructor: (config={}) ->
@config.name = config.name if config.name?
getName: -> @config.name
Human = class extends Person
ben = new Human(name: 'Ben')
sonny = new Human()
alert ben.getName()
alert sonny.getName()
Person = class
config:
name: "sin nombre"
constructor: (config={}) ->
@config = {}
@config[key] = value for own key, value of Person::config
@config.name = config.name if config.name?
getName: -> @config.name
Human = class extends Person
ben = new Human(name: 'Ben')
sonny = new Human()
alert ben.getName()
alert sonny.getName()