new的运行机制
当代码new Animal("cat")
执行时:
var obj=Object.create(Animal.prototype);
传入cat参数,构造函数Animal执行。同时构造函数内部的this被指定为obj。
如果构造函数返回了一个“对象”,那么这个对象就是new出来的结果。如果构造函数没有返回对象(
即返回一个非对象值,例如数值,或者无返回值
),那么new出来的结果为obj对象。一般情况下构造函数不返回值,除非你想要覆盖正常创建的对象(即obj)。
例如:
function A(name){
this.name=name;
return 3;
}
var new1=new A("aa");
new1;//A {name: "aa"}
function B(name){
this.name=name;
return {};
}
var new2=new B("aa");
new2;//new2为一个空对象。
作用域链
JS权威指南中有一句很精辟的描述: “JavaScript中的函数运行在它们被定义的作用域里
,而不是它们被执行的作用域里。”简单来说,就是函数被调用时,它是运行在当时定义该函数时的环境中的。
定义函数
当定义函数a的时候,js解释器会将函数a的作用域链(scope chain)设置为定义a时所在的“环境”
,并为a添加scope属性,a.scope=a的作用域链。如果a定义在全局环境,那么scope chain中只有window对象。
调用函数
当函数被调用时,会创建一个活动对象(call object)(也就是一个对象), 然后把所有函数a的局部变量和函数定义添加为该活动对象的属性
, 并将该活动对象添加到a的作用域链的最顶端,此时a的作用域链包含2个对象:a的活动对象和window对象。
案例解析
为什么调用func1(10)和func2(10)时,引用到了两个不同的i?
function outerFn(i, j) {
var x = i + j;
return function innerFn(x) {
return i + x;
}
}
var func1 = outerFn(5, 6);
var func2 = outerFn(10, 20);
alert(func1(10)); //返回15
alert(func2(10)); //返回20
调用outerFn (5, 6)的时候定义了一个新的函数对象innerFn,然后该函数对象成为了outerFn函数的活动对象的一个属性。这时innerFn的作用域链是由outerFn的活动对象和全局对象组成的.。这个作用域链存储在了innerFn函数的内部属性[[scope]]中,然后返回了该函数,变量func1就指向了这个innerFn函数。
在func1被调用时,它自身的活动对象被创建,然后添加到了[[scope]]中存储着的作用域链的最前方。这时的作用域链才是func1函数执行时用到的作用域链。从这个作用域链中,可以看到变量‘i’的值实际上就是在执行outerFn(5,6)时产生的活动对象的属性i的值。下图显示了整个流程。
下图是func2执行时的情况。因为在定义func1和func2时,函数outerFn中产生过两个不同的活动对象,所以才导致调用func1(10)和func2(10)时,引用到了两个不同的i。
一个活动对象在函数执行的时候创建,同时被添加到该函数的作用域链的最前端。当函数执行完毕时,活动对象会被从该作用域链上删除。
但是该活动对象是否会被垃圾回收器销毁,还要看其他地方是否还有使用到该活动对象。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。