先看这道练习题
function fun(){
this.a=0;
this.b=function(){
alert(this.a);
}
}
fun.prototype={
b:function(){
this.a=20;
alert(this.a);
},
c:function(){
this.a=30;
alert(this.a)
}
}
var my_fun=new fun();
my_fun.b();
my_fun.c();
下面用画图的方式来讲解这道题,省略了栈内存只画了堆内存
遇到这类题首先要画图,图出来了基本上答案也就出来了:结合上图来分析一下:
代码执行前浏览器先形参全局的执行上下文EC(G),EC(G)中的VO(G)用来保存全局变量;遇到function和var进行变量提升,function提前声明加定义,var只提前声明;
- 先画函数fun的堆,在这个堆内存中有代码字符串还有自己的属性,比较重要的属性有prototype和__proto__,prototype指向堆fun.prototype,fun.prototype这个类的原型属性是一个对象有一个属性constructor指向所属类fun,还有一个属性__proto__(原型链属性),所有的对象都有这个属性,当某个对象不是new出来时,这个对象就是Object的实例,__proto__指向Object,prototype。
- 变量提升后执行代码,第一步在变量提升阶段已经做了。第二步等号赋值的时候先创建右边的值,再创建左边的变量,最后两者关联在一起。先创建值再关联。先自己创建对象【绿色的堆】,然后让fun.prototype重新定向,指向这个新创建的堆,重定向原型指向的时候之前原型上的内容会丢失,包括constructor,所以为了保证结构的完整性,我们一般要手动设置constructor。fun.prototype之前指向的那个堆内存没有被占用后会被释放掉。