介绍:这是篇简单的文章,其实就是引用的问题,但是挺绕的。
问题:
var f=function(){this.a=1}
f.prototype.b=33
var a1=new f()
f.prototype = {
b:3
}
console.log(a1.b) //?
f.prototype.b=33
var a1=new f()
f.prototype = {
b:3
}
console.log(a1.b) //?
分析:
这里结果是33还是3呢。初看上去是3,好像3覆盖了原来的33.
如果分析一下对象生成的过程。f本身是一个对象A,new f 时。出一个新的对象C。
这个对象有一个__proto__属性链接到f.prototye对象B。现在C已经指向了B。
而后,f.prototype也就是B 又指向了D对象{b:3}。
如果分析一下对象生成的过程。f本身是一个对象A,new f 时。出一个新的对象C。
这个对象有一个__proto__属性链接到f.prototye对象B。现在C已经指向了B。
而后,f.prototype也就是B 又指向了D对象{b:3}。
所以这里一共就A,B,C,D三个对象。看下图
总结:
现在f.prototype本来是指向B对象的,现在又指向了D对象。
所以不要把f.prototype当作对象,他是指向了对象。
对象本身是没有名字。new的对象本身都是系统自带的,相同的一个。new的过程只是链接而已。
只是给加了各种属性,各种引用。
基本类型的值在内存中有固定的大小,所以保存在栈中。复制基本类型值时,会创建一个副本。
引用类型的值是对象,保存在堆中。复制引用类型值时,复制的是该对象的指针。因此两个变量指向的都是一个对象
扩展
结果a1.b=33.
如果要得到3的话,可以通过constructor引用到原函数,然后输出现在的b就行了。a1.__proto__.constructor.prototype.b =3
这里A.prototype本来引用了B对象,现在又改成引用了D对象。B对象如果没有C对象的引用,就会被垃圾收集器自动清除掉。
小题目
下面是权威指南上引用一节的题目,也是这个意思。
var a = [1,2,3];
var b = a;
a[0] = 99;
alert(b);
var b = a;
a[0] = 99;
alert(b);
不要把a当作[1,2,3]来看,看成a指向了数组[1,2,3]
b=a。b也指向了数组[1,2,3]
这样,就清楚了
题目2
这里aa.prototype.b===b.__proto__.b?
function aa(){
this.a=2;
aa = function(){
this.a=3;
}
aa.prototype.b=function(x){alert(x)};
}
var b=new aa();
alert(aa.prototype.b===b.__proto__.b);
console.log(aa.prototype,b.__proto__);
结果发现aa.prototyop!==b.__proto__ 这是为什么呢?
因为b.__proto__指向的对象是 原来的 aa.prototype。所以我们在看构造函数时,不能只看到函数本身,其实还有隐式的prototype属性