为什么第一个例子可以修改原型链中的值,而第二个不可以?
此题和下面这个链接应该是同一原理吧,可我没太看明白
关于Object.create()与原型链的面试题?
有同学回答是原型链的原因,有同学说是引用的问题,求解?
var fun = function () {
};
fun.prototype = {
info: {
name: 'peter',
age: 25
}
};
var a = new fun();
var b = new fun();
a.info.name = 'jack';
b.info.name = 'tom';
console.log(a.info.name)//tom
console.log(b.info.name)//tom
var fun = function () {
}
fun.prototype = {
name: 'peter',
age: 25
}
var a = new fun();
var b = new fun();
a.name = 'jack';
b.name = 'tom';
console.log(a.name)//jack
console.log(b.name)//tom
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号
因为第二个你实际上是在
a和b对象上都添加了name属性,你看看a.__proto__.name就知道了。第一个则是修改的prototype。读和写不是一个路线。
读会在原型链上一直找下去。
而对于要赋值的属性或者方法会先找到它所在的位置。有则赋值,无则增加。(如果路径不存在,会报错)。
也就是赋值操作(写)的最后一步是不会查找原型链的。
//
a.info.name = 'jack';
b.info.name = 'tom';
相当于name的位置是a.info和b.info上。指向了同一个原型。所以a.info.name 和b.info.name 操作的其实都是同一个原型上的值。
//
a.name = 'jack';
b.name = 'tom';
在a上找name,没找到,直接添加name属性并赋值(而不会再去原型链查找)。b同。
//
期待其他人能给个专业的文档支持
题主如果充分点理解原型链的话,这问题就不是问题了。
第一个的原型指向
当我们访问a跟b的时候,访问他们的info属性其实都是原型那边的info,即同一个;
但是第二个则不同了 ,原型链指向的是
当我们刚生成a、b时,a.name===b.name;
但是当你给他们的name赋值时,实际上,这个新的name不再是原型链的name了,而且归于各自对象实例的属性。
当然如果在第一个中,你如果给a.info = {name:'d'} ; 那a的info就是自己的属性而不是原型链上的那个对象里的info了,这时候要想访问原型链的info,就得通过a.__proto__.info访问了。
实质上应该是对象的浅引用问题,直接帮你改一下格式就看出来了。
更新,主要是补充解释一下啊。
第一段的意思是给fun的原型链覆盖了一个对象,对象中info属性为另一个对象。就像我改写的这个样子,不覆盖fun的原型链,直接添加了一个info的属性。
当你在两次new对象后,a和b都继承了原型链上info,然后去修改a和b的info.name,然后a和b上都没有info这个属性,就去原型链上找,找到了,直接指向的是info那个对象,然后分别都修改了那个对象。
所以,你两次console出来是一样的。
直接上代码证明吧:

第二段中直接给原型链添加了name属性,赋值为一个字符串,字符串不存在浅引用。字符串和数字、布尔一样,只有在操作的时候才转变成对象,操作完成就存成了相应的数据类型的数据。
在修改的时候,先找本身,是undefined,然后找原型链,是peter一个字符串,由于没有引用关系,当直接修改name属性值的时候直接从本身进行了修改。然后你console的时候,自然就是不一样的。
以下仅为个人理解。
首先对象的引用是当你调用
a.name时,会先在a对象下找,如果没找到,会去a.__proto__的对象下找,以此递归寻找。而你给
a.name赋值时,它不会修改a.__proto__上所对应的name,而是直接在a对象下新建一个name。第一个例子中你原型链上的
info并没有被改变,它的info实际上是指向这个对象的,而你用
a.info.name='jack';的时候实际上在a.__proto__上找到了info,然后在info里找到了name,info不能被修改但是info所指的对象能被修改,所以就出现了问题中的现象。你可以将a.info='jack',然后去看
fun.prototype.info,你就会发现info并没有被修改。对对象的属性进行修改,会shadow其所委托到的原型上的同名属性,就像第二个所示,但是第一个的本质不是在操作你的新对象,是在操作原型上的info属性
其实这个问题和原型链无关,和类型赋值有关。object是做一个引用的copy,基本类型是做值的copy。其实就是相当于下面的代码:
类似的,原来的代码改成这样看看:
a.name="jack"//赋值操作,a本身没有这个属性,那么创建并覆盖原型上继承的name属性
console.log(a.name)//获取属性的值,但是a身上没有的话,就往上查找
a.info.name="ww"
分为两步(a.info)//a没有,往上查找,原型上有{},获得对对象的引用
(a.info).name=""//修改这个引用的对象的值
这是我的理解。
因为a.info和b.info本身是两个东西,但是指向同一个对象,a.info.name和b.info.name修改的是那个对象的属性。
后面那个a.name和b.name也是两个东西,所以修改任意一个,不会影响另一个