默认绑定
全局环境下的this指向是window
console.log(this);//window
独立函数中的this指向是window
function()
{
console.log(this);//window
}
函数嵌套中内层函数的函数指向是window
var obj = {
a:1,
fun:function(){
console.log(this)//obj
function sum()
{
console.log(this)//window
}
}
}
立即执行函数中的this指向是window(这个还挺重要)
(function test()
{
console.log(this);//window
})();
隐式绑定
当函数作为对象的方法的时候被调用时,函数的this指向应该是调用他的直接对象。(就是.前面的对象)
var obj = {
fun:function()
{
console.log(this);
},
obj2:{
fun:function()
{
console.log(this);
}
}
}
obj.fun()//obj
obj.obj2.fun()//obj2
隐式丢失的情况
内置函数setTimeout和setInterval的第一个参数中的this默认指向的是window
var obj =
{
a:1,
fun:function()
{
console.log(this);
}
}
setTimeout(obj.fun,1000);//obj.fun本来是指向的obj,但是由于setTimeout和setInterval的这个特性所以this的指向指向了window
给函数起别名
var obj =
{
a:1,
fun:function()
{
console.log(this);
}
}
var a = fun;//window
a和obj.fun本质上就是同一个函数。那么为什么会产生不同的结果呢?因为a是一个独立函数,没有被obj对象约束。上文所说,独立函数的调用this指向就是window。
再看另一种情况:
var obj =
{
a:1,
fun:function()
{
console.log(this)
}
}
var obj2={
}
obj2.fun = obj.fun;
obj2.fun;//obj2
我觉得关键是一句话,函数作为值赋值传递的时候,this的指向是不会传递的,是由自身决定的。如果自身是个独立函数,如情况1中的a,根据规则独立函数的this指向应该是window。如果他是某个对象的方法,比如是这里的obj2.fun,根据隐式绑定的规则,this应该是obj2。
立即执行函数的this指向默认是window
还是上一个例子:
var obj =
{
a:1,
fun:function()
{
console.log(this)
}
}
var obj2={
}
(obj2.fun = obj.fun)();//请注意对比和上一个例子的区别这里是一个立即执行函数,这个表达式obj2.fun = obj.fun的结果就是一个函数,这个函数是立即执行的,所以他的this指向应该是window。
如果这个例子有点绕那么看这个例子。
var obj= {
fun:function()
{
console.log(this);
}
}
(false||obj.fun)();//window
false||obj.fun返回的是一个函数,函数立即执行,所以这个函数的this指向应该是window。
显式绑定
通过call,apply,bind进行this指向的改变
function fun ()
{
console.log(this);
}
var obj={}
fun.call(obj);//输出obj
call,apply,bind的异同
- 都能改变函数的this指向
- bind返回的是一个被改变this指向后的函数,每次调用这个函数这个函数的this指向都是被改变了的,而call和apply更像是一个一次性用品,他是改变这次函数调用中的this指向。他返回的是一个函数的执行结果。
- call和apply参数传递上有不同,call是参数列表的形式例如,fun(obj,a,b);但是apply是参数组成的数组的形式,fun(obj,[a,b]);
tips:call/apply如果第一个参数传入的是null/undefined,则应该是指向浏览器环境window,如果是在node中则是node环境global
硬绑定
其实是情况一的变种,硬绑定就是任何情况下都不能改变这个函数的指向。其实也特别简单。就是你不想这个函数的this指向被改变。那么你可以通过把他封装到一个函数内部来实现,那么this指针永远只会改变外层函数的this指向,从而影响不到你。
var obj={}
function bar ()
{
function foo()
{
con'sole.log(this);
}
foo();
}
bar.call(obj)//window
数组的很多方法都提供了修改this指向的参数
比如forEach/map/filter/some/every方法
var arr = [1,2,3];
arr.forEach(function()
{
console.log(this);//默认情况下是arr,但是这里通过第二个参数使其this指向指向了arr所以这里输出arr
},arr)
new绑定中的this指向
首先我们要清楚new操作符究竟做了一些什么事情,以 var obj = new A();为例
- 创建了一个空对象,var obj={}
- 让这个空对象的
_proto_指向构造函数的原型(obj._proto_=A.prototype) - this指向这个空对象,执行构造函数的内容
- 隐式返回这个this
tips:如果构造函数本身return了一个对象,那么这个对象就会取代了我们要返回的this,但是如果构造函数本身return的不是一个对象, 那还是return this,此外null虽然是对象,但是如果return null 还是会返回this。
那么,new绑定中的this指向,关键是最后一句话:返回这个this。那么我们就知道这个实例化的对象实际上就是this。
function A(num)
{
this.a = num;
console.log(this);//输出的就是实例化对象
}
var fn = new A(1);
这里的this,实际上就是这个实例化对象fn。其实很好理解,return的过程就是把this赋给了实例化对象,那么this不就是实例化对象嘛
还有一种情况就是构造函数return object。那么会导致什么结果呢?其实this的指向还是没有变的,他还是构建出来的那个对象。只不过,它并没有赋值给这个实例化对象。这个实例化对象实际上是这个return 的object。