js——this
每个函数的this是在调用时绑定的,完全取决于函数的调用位置
1. 绑定规则总结
一般情况下,按下列顺序从下至上来判断this的绑定对象(绑定的优先级从下至上递减)
- 默认:在严格模式下绑定到undefined,否则 绑定到全局对象
- 隐式:由上下文对象调用?绑定到对应的上下文对象
- 显示:由call或apply或bind调用?绑定到指定的对象
- new:由new调用?绑定到新创建的对象
2. 绑定规则说明
- 默认情况
- 规则:非strict mode时,绑定到全局;strict mode时,绑定到undefined
- 适用情况:当其它三种规则不适用时使用
- 例
var a = 2; function f1(){ alert(this.a); } function f2(){ var a = 3; f1(); } f2();//输出为2,全局定义的
- 绑定到上下文对象(隐式绑定)
- 函数作为对象的一个属性,则该对象就是该函数的上下文对象
function foo(){ alert(this.a); } var obj2 = { a:42, foo:foo//foo作为obj2的属性 }; var obj1 = { a:2, obj2: obj2 }; obj1.obj2.foo();//输出obj2中的42,obj2是foo对象属性引用链中的最后一层
-
- 隐式绑定丢失:函数作为对象的属性不代表函数属性完全属于该对象,它还是独立的。当直接引用函数时,它会用默认绑定方式(全局或undefined)
var obj = { a:"obj", foo:function(){ alert(this.a); } } var a = "global" var bar = obj.foo;//bar直接引用函数 bar();//输出"global"
- 显式绑定
- 函数不属于一个对象的属性,可利用call、apply、bind函数让this绑定到该对象上
- foo.call(obj, param):call函数会把第一个变量obj绑定到foo函数的this上
function foo(){ alert(this.a); } var obj = {//对象中没有foo属性 a:"obj" }; foo.call(obj);//输出obj
-
- foo.apply(obj, param):apply函数的效果和使用与call相似
- 硬绑定方法bind:newFoo = foo.bind(obj); 将foo的this绑定到obj上,并返回相应的新函数,这样就不会发生绑定丢失了
function foo(){ alert(this.a); } var obj = { a:"obj" }; var obj2 = { a:"obj2" }; var bar = foo.bind(obj);//bind把foo的this绑定到obj对象,并返回这个函数 bar();//输出"obj" bar.call(obj2);//仍然输出"obj",硬绑定不会被修改
-
- 自定义一个bind函数:对apply、call函数进行封装,并返回一个新函数(已经绑定好对象)
function foo(){ alert(this.a); } //对apply函数进行封装,让绑定在bind内部完成,并返回一个函数 //这样,就不能通过封装后的函数修改绑定 function bind(fun, obj){ return function(){ //apply函数返回值为undefind fun.apply(obj, arguments); }; } var obj = { a:"obj" } var bar = bind(foo, obj); bar();//输出"obj" bar.apply(window);//仍然输出"obj"
- new绑定
- new foo(); 用new调用一个函数时,它会把foo的this绑定到创建的新对象上
function foo(a){ this.a = a; } var bar = new foo(2); alert(bar.a);//输出 2
3. 特殊情况
- 把null和undefined传给call、apply、bind时,使用默认绑定规则。在做柯里化时可以用到
- 为了不让这种情况下的this绑定到全局(从而影响全局的值),可以自定义一个空对象,并将它作为这几个函数的第一个参数
- 软绑定:如果this绑定到全局或undefined,那就让它绑定到给定的对象,否则不变
- 箭头函数:箭头函数的this绑定对象与其外层作用域是一致的
参考:
1. 《你不知道的javascript》上卷