this是运行时进行绑定的,并不是在编写时绑定,它的上下文取决于函数调用时的各种条件。this的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式。它既不指向函数自身也不指向函数的词法作用域。
函数调用时,会创建一个活动记录(有时也称为执行上下文) ,这个上下文中会记录包含函数在哪里被调用(调用栈)、函数的调用方法、传入的参数等信息。this是其中的一个属性。
1. 默认绑定
this指向全局对象。
示例:
function foo(){ console.log(this.a); } var a=2; foo();//2
这里的this.a的this指向了window。
2. 隐式绑定
调用位置是否有上下文对象,或者说是否被某个对象拥有或者包含。
示例:
function foo(){ console.log(this.a); } var obj={ a:2, foo:foo }; obj.foo();//2
foo函数严格来说并不属于obj对象,但调用位置会使用obj上下文来引用函数,因此可以说函数被调用时obj对象“拥有”或者“包含”它。
隐式丢失
被隐式绑定的函数会应用默认绑定,把this绑定到全局对象或者undefined上(跟严格模式有关)。
示例:
function foo(){ console.log(this.a); } var obj={ a:2, foo:foo } var a="gloal"; var bar=obj.foo; bar();//gloal
这个时候的bar其实是函数foo的引用,此时的bar是不带任何修饰的函数调用。
传入回调函数时,也会发生此种情况。示例:
function doFoo(fn){ fn(); } function foo(){ console.log(this.a); } var obj={ a:2, foo:foo } var a="gloal"; doFoo(obj.foo);//gloal
传入内置的函数结果是一样的。示例:
function foo(){ console.log(this.a); } var obj={ a:2, foo:foo } var a="gloal"; setTimeout(obj.foo,100);//gloal
setTimeout的源代码与下面代码类似:
function setTimeout(fn,delay){ fn(); }
上面的例子可以稍稍修改下,this的指向就改变了,可以先想想要怎么去改?
改完之后
function foo(){ console.log(this.a); } var obj={ a:2, foo:foo } var a="gloal"; setTimeout(function(){obj.foo();},100);//2
3. 显示绑定
call([thisObj[,arg1[, arg2[, [,.argN]]]]])
apply([thisObj[,argArray]])
它们第一个参数是一个对象,会把这个对象绑定到this。这两个函数的区别在于参数,call的其它参数直接传递,apply则以数组的形式传递给函数。
硬绑定
ES5提供了两个内置的方法,Function.prototype,bind。
用法如下:
4. new绑定
使用new来调用函数,会执行下面的操作。
1. 创建(构造)一全新的对象。
2. 这个对象会被执行原型连接。
3.这个对象会绑定到函数调用的this。
4.如果函数没有返回其它对象,new的函数调用机会自动返回这个新对象。
function foo(a){ this.a=a; } var bar=new foo(2); console.log(bar.a);//2
用new来调用foo(...)时,会构造一个新对象并把它绑定到foo(...)调用中的this上。
被忽略的this
null或者undefined作为this的绑定对象传入call 、apply、或者bind时,应用的是默认绑定规则。
检测题:
function Foo(){ this.a=1; this.param={ "name":this.a }; } var bar= new Foo(); bar.name=2; alert(bar.param.name);
答案是:1 。
注意此处是构造函数。