片段 1:
let Foo = function Foo(){};
Foo.prototype= {x:1};
let FooSon = new Foo();
console.log(FooSon.x); //输出:1
Foo.prototype.x =2;
console.log(FooSon.x); //输出:2
片段 2:
let Con = function Con(){}
Con.prototype.x =2;
let ConSon = new Con();
console.log(ConSon.x); //输出:2
Con.prototype= {x:1};
console.log(ConSon.x); //输出:2
let QonSon = new Qon();
console.log(QonSon.x); //输出:1 =>引用了最新原型
问题是看不懂为什么先 prototyp={},再 prototype.x 方式时候后面的实例能够继承到最新的原型,反过来就不可以?这里面牵涉到了什么高深知识点,万能的 v 友久久我。
可以看出 prototype 本质上是一个指针。
我给了你一张纸条,纸条上写着我家的地址,这个地址就叫指针。
当我把我家玻璃砸碎,你通过这个地址来到我家,你就能看到玻璃已被砸碎。
然后我把你手里的纸条撕碎,给了你一张新纸条,纸条上写着我刚买的毛坯房地址。
现在我把我原来家的玻璃修好。
你顺着纸条找过来,目光所及没有修好的玻璃,只有空空如也的房子。
建议先看看红宝书再来思考这个问题。这里给一点参考,prototype={}已经改写了原型对象了,这时候再 prototype.x 是在这个改写后的对象上的修改,这里不是你说的`继承到最新的原型`;反过来的话,就更好理解了,因为你先 prototype.x 赋值,再改掉这个 prototype 的整个对象,这时候原型链已经“丢失”了。
想了一下
原型链其实继承的是对象
Foo.prototype= {x:1}; 这里是表示 new Foo 创建的对象要继承于匿名的{x:1}对象
Foo.prototype= {x:2}; 这时候就继承于另外一个新创建的匿名对象{x:2}了,不过因为原来的{x:1}还能通过你之前 new 的 Foo 的原型来获取,所以不会被回收
修正
原来的{x:1}还能通过 Object.getPrototypeOf 获取
不知道你能不能理解这个最基本的引用问题:
let A = { x: 1 };
let B = A;
A.x = 2;
请问现在 B.x = ?
let A = { x: 2 };
let B = A;
A = { x: 1 };
请问现在 B.x = ?
你的例子就是上面的复杂版,没有高深的知识点,只是“原型链”三个字把你吓着了。
我是这么理解原型链的,就两条:
1.实例化时,自动给实例添加一个__proto__的属性,其值为类(或函数)的 prototype 属性
2.从对象查找属性时,如果找不到则自动往__proto__上递归查找
let ConSon = new Con(); // ConSon.__proto__ = Con.prototype
Con.prototype= {x:1}; // Con.prototype 重新赋值,但是 ConSon.__proto__ 仍指向旧的值
另外本质上,new 可以大致等同于以下操作
let foo = Object.create(Foo.prototype);
Foo.call(foo)
这里就只是用了一些 Foo 的原型链指向的一个对象,然后再拿 Foo 作为普通函数调用一下。可以说构造完的对象和 Foo 这个函数没什么关系了
嗯嗯,这个我理解了。但是这里还有个奇怪的问题,在先 prototype.x 赋值,再通过 prototype={..} 覆盖掉当前实例的原型后,再使用 prototype.x 赋值。此时输出的值仍然还是第一次 prototype.x 的值。这里是不符合前面 “ 再 prototype.x 是在这个改写后的对象上的修改 ”的逻辑的呀
第一个是引用,值跟着变;第二个不太懂,用浏览器输出了一下 B.x=2,猜想 A={..}的时候重写地址发生了改变,B 还是指向原来 A 的地址,所以还是 2
索性这样,单纯只考虑原型链的话
我把 foo = new Foo()替换成
foo = {}
Object.setPrototypeOf(foo, Foo.prototype)
Foo.call(foo)
接下来我把 Foo.prototype 换个写法
let obj = {x:1}
Foo.prototype = obj
foo = {}
Object.setPrototypeOf(foo, Foo.prototype)
Foo.call(foo)
然后我等价代换一下
let obj = {x:1}
Foo.prototype = obj
foo = {}
Object.setPrototypeOf(foo, obj)
Foo.call(foo)
问此时 foo 这个对象和 Foo.prototype 还有什么关系
你的猜想是对的
理解一下把 new 的过程实现一遍清楚了
看这个,图文并茂深入浅出
https://javascript.info/function-prototype
你的猜想是对的,把 A 换成 Con.prototype,B 换成 ConSon.__proto__ 就是你的问题了
这篇文章写的很清楚:
https://blog.sylingd.com/archives/345.html
一张图表示: https://i.loli.net/2020/07/06/LnlXHqVa43CBfJD.jpg
这里只看懂到
Object.setPrototypeOf(foo, obj) => foo.prototype=obj 。Foo.call(foo)这一步不懂,大佬能给解释一下不