为了账号安全,请及时绑定邮箱和手机立即绑定

prototype的动态修改问题

prototype的动态修改问题

繁星coding 2019-03-14 17:15:17
函数对象的Prototype对象是所有实例共享的,New一个对象a出来的时候建立了一个引用,让它的a.__proto__指向了函数对象的prototype但是,如果动态改变函数的prototype,假如让它变成空{}这时再new一个对象b出来的时候,它的b.__proto__也指向了函数对象prototype,但是却是空而之前的a.__proto__的属相好像没有变化?这是说明a和b的proto引用的不是同一块内存?这个跟实例共享prototype是不是矛盾了?
查看完整描述

6 回答

?
蛊毒传说

TA贡献1895条经验 获得超3个赞

哪里有矛盾? 继续new b2出来的时候 b2 和 b的原型就是同一个对象了

Javascript中 var a = new A();执行完毕后,a和A就不再有任何的强绑定关系了,只有a.__proto__ === A.prototype这个弱关系(而且还不一定成立!),你覆盖掉了A.prototype之后,自然a和A就不再有任何关系

https://img1.sycdn.imooc.com//5cb0134c0001c4f905770123.jpg

var a = new A() 大致等价于下面的代码

var a = (function() {

    var context = Object.create(A.prototype);

    var ret = A.call(context);

    return ret !== null && typeof ret === 'object' ? ret : context;

})()


查看完整回答
反对 回复 2019-04-12
?
aluckdog

TA贡献1847条经验 获得超7个赞

假设有这样的代码:


function Test() {}

Test.prototype = {x: 1};

var a = new Test();

Test.prototype = {y: 2};

var b = new Test();

console.log(a.x); // 1

console.log(b.y); // 2

为什么a.__proto__没跟着变?


首先,要了解清楚,a与b共享的只是Constructor.prototype的指向,而不是内存,也就是每次new一个Constructor的时候,js都会new一个object,假设为ref,然后把ref的__proto__指向Constructor.prototype,这是每次创建一个实例都需要经过的步骤,如果你在new之前改变prototype,ref.__proto__指向的将是不同的东西!


为什么a与b共享的proto引用不是同一块内存?


原因就是你把prototype指向了一个新的对象,破坏了引用。(指向了一个空对象,这会重新分配内存,原有内存空间还在,只不过现在不能通过Test.prototype来访问而已)


类似的还有函数形参等情况:


function test(obj) {

   // case 1:

   // 在函数里面重新赋值了,obj指向了新的内存空间,不再与temp有关联

   obj = {x: 1};

   // case 2:

   // 这里不重新分配内存空间,只是为obj添加属性的话,就会同时更新外部的temp对象

   // obj.y = 3;

   console.log(obj);

}

var temp = {y: 2};

test(temp);

// 如果test函数中没有破坏temp引用的话,temp就不会受到影响

console.log(temp);

更经典的还有nodejs的exports与module.exports。


查看完整回答
反对 回复 2019-04-12
?
拉风的咖菲猫

TA贡献1995条经验 获得超2个赞

一楼答案的例子已经可以说明这个现象的原因了,我这里补充一下。

理解这个现象,首先要了解JS里面new操作符执行的几个动作,也就是当new Foo()执行的时候发生了什么事情,我这里简单概括一下:

  1. 首先创建一个空对象,这个空对象的类型是Foo,并且空对象的隐式属性__proto__指向了Foo.prototype所引用的对象;

  2. 调用构造函数,进入上下文,执行上下文的thisValue,也就是this的值指向刚才创建的对象,然后函数代码执行;

  3. 隐式返回刚才创建的对象(如果函数里面没有显式返回值得话);

理解了这个过程之后,题主的现象就很容易解释了,当你创建实例a的时候a.__proto__指向了Foo.prototype引用的对象Foo {},当你给Foo.prototype赋值为{}的时候,Foo.prototype就指向了你创建的这个空对象,原理类似于:

var foo = {x: 10},

    bar = {y: 10};


var w = foo,

    z = w,

    w = bar;


console.log(b); // foo {x: 10}

Foo的实例a相当于例子中的z(可能有点绕),例子中w指向了另外的对象,但是z还是指向原来的对象,就像你的Foo.prototype指向了另外一个对象,但是a.__proto__却还是指向原来的那个对象。


这时候当你再次执行var b = new Foo()时,还是执行上述的过程,b.__proto__指向了Foo.prototype引用的对象,也就是你赋值的那个对象,明显这个对象和a.__proto__引用的不是一个对象。


还有就是你提到的


实例共享prototype


这句话有点断章取义了,而且现在很多技术用语不是很严谨,更不能像记口诀一样去学习知识,我们需要了解他的本质过程。


希望我的回答对你有帮助!


查看完整回答
反对 回复 2019-04-12
?
子衿沉夜

TA贡献1828条经验 获得超3个赞

简而言之,就是b.prototype只是一个指针,它一开始和a.prototype指向同一个对象,但后来你把它指向了另一个对象,如此而已。


查看完整回答
反对 回复 2019-04-12
?
温温酱

TA贡献1752条经验 获得超4个赞

没矛盾的,对象是引用传递,当你给实例赋新值的时候,它引用的就会是内存中重新分配一个新地址,跟之前的那个引用已经脱离关系,所以你更改当前的任何属性和方法都不会对之前的应用有任何改变。


查看完整回答
反对 回复 2019-04-12
  • 6 回答
  • 0 关注
  • 861 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信