this是js中的一个关键字,它代表当前作用域的上下文环境,而且随着上下文的改变而动态变化。
this指当前的上下文环境,在不经意间容易改变:
1 var info = "This is global info"; 2 var obj = { 3 info: 'This is local info', 4 getInfo: getInfo 5 } 6 function getInfo() { 7 console.log(this.info); 8 } 9 obj.getInfo() //This is local info 10 11 getInfo() //This is global info 当前上下文环境被修改了 12
这个例子告诉我们:
1、同一个函数,调用的方式不同,this的指向就会不同,结果就会不同
2、对象内部的属性的值为引用类型时,this的指向不会一只绑在原对象上。
其次,还有不经意间丢失this的情况:
1 var info = "This is global info"; 2 var obj = { 3 info: 'This is local info', 4 getInfo: function getInfo() { 5 console.log(this.info); 6 7 var getInfo2 = function getInfo2() { 8 console.log(this.info); 9 } 10 getInfo2(); 11 } 12 } 13 obj.getInfo(); 14 15 //This is local info 16 //This is global info
上面代码中,对象obj中定义了一个getInfo方法,方法内又定义了一个新的函数,也希望拿到最外层的该对象的info属性的值,但事与愿违,函数内部的this被错误地指向了window对象,这就导致了错误。
this实际上是在函数被调用时发生的绑定,它指向什么完全取决于函数在哪被调用。
this的绑定一共有四种绑定:1、默认绑定(即没有明确的调用对象)
2、隐性绑定(即作为对象方法调用,this会被绑定到该对象)
3、显性绑定(使用call()、apply()调用,两个方法的第一个参数为一个对象,this被绑定到该对象)
4、new绑定(使用new来调用函数,会构造一个对象,并把this绑定到该对象)
一、默认绑定(即没有明确的调用对象)
1 function foo(){ 2 var a = 1 ; 3 alert(this.a); 4 } 5 var a = 2; 6 foo(); // 2 (非严格模式下)
上面代码中,foo是在全局环境被调用的,所以this被绑定到window。但前提是非严格模式下,如果在严格模式下,this被绑定到undefined。
二、隐性绑定(即作为对象方法调用,this会被绑定到该对象)
1 function foo(){ 2 var a = 1; 3 alert(this.a); 4 } 5 var obj = { 6 a:2, 7 foo:foo 8 }; 9 obj.foo(); // 2
上面代码中,obj对象调用foo函数,因此this被绑定到obj。
对象属性引用链中只有最后一层会影响调用位置。
1 function foo(){ 2 alert(this.a); 3 } 4 var obj2 = { 5 a:2, 6 foo:foo 7 }; 8 var obj1 = { 9 a:1, 10 obj2:obj2 11 }; 12 obj1.obj2.foo(); //2
上面代码中,obj1和obj2两个对象连续调用,this会被绑定到最后一个对象,即obj2,所以输出2
三、显性绑定(使用call()、apply()调用,两个方法的第一个参数为一个对象,this被绑定到该对象)
1 function foo(){ 2 alert(this.a); 3 } 4 var obj = { 5 a:1 6 }; 7 foo.call(obj); // 1
call方法的参数若为空,默认调用window对象
硬绑定——显示绑定的一种变形
优点:可以解决丢失绑定问题
缺点:硬绑定后不能再修改它的this
1 function foo(){ 2 alert(this.a); 3 } 4 var obj = { 5 a:2 6 }; 7 var bar = function(){ 8 foo.call(obj); 9 }; 10 bar(); // 2 11 setTimeout(bar,100); // 2 12 bar.call(window); // 2
ES5中提供了内置方法Function.prototype.bind
1 function foo(something){ 2 alert(this.a, something); 3 return this.a + something; 4 } 5 var obj = { 6 a:2 7 }; 8 var bar = foo.bind(obj); 9 var b = bar(3); // 2 3 10 alert(b); // 5
bind()会返回一个硬编码的新函数,它会把参数设置为this的上下文并调用原始函数
四、new绑定(使用new来调用函数,会构造一个对象,并把this绑定到该对象)
1 function foo(a){ 2 this.a = a; 3 } 4 var bar = new foo(2); 5 alert(bar.a); // 2
上面代码中,bar对象是由foo函数创建得,因此继承了foo函数的属性和方法。
综上,this绑定的优先级为:new绑定 > 显示绑定 > 隐式绑定 > 默认绑定
前端面试中经常会问到一个问题:new操作符都干了些什么,回答的时候可以回答一下几点:
1、创建了一个空对象,并用this引用该对象,同时还继承了该函数的原型
2、属性和方法被载入到该函数的原型中
3、新创建的对象由this引用,并且最后隐式地返回this
1 var obj = {}; 2 obj.__proto__ = Base.prototype; 3 Base.call(obj);