关于this

前端中this是个老生常谈的问题,总是说不清道不明,看这里。
this只能用在函数里面,相信全世界的人都知道。
this就是函数在被执行的时候,产生的执行上下文(context)。
this的大致用法,相信接触过前端的同学都知道,无非以下5种。

1、 function test(){
       console.log(this);
    }
    test(); //不是对象的属性,直接执行
    
2、 var object = {
       test: test() {
          console.log(this);
       }
    }
    object.test(); //作为对象的属性被调用
    
3、 test.call(object); // apply用法差不多

4、 Function test() {
       this.name = test;
   }

5、箭头函数中的this

其中第4种构造函数没什么可说的,构造出了谁,谁就是this。
平常用的最多的也就是前3种,先说第3种情况。最后说第5种。

第3种情况被执行的时候,
object就是作为函数参数被传入到test()中,这个函数参数就是this
也就是说在test()被执行的时候,this就是指向object

第1种,第2种情况就是第3种情况的语法糖。

test.call(undefined);
object.test.call(object); //被谁调用指向谁
如果你传的 context 不是一个对象,那么在浏览器中默认是 window 对象。

分析下面的例子:

var name = 'hut';
var obj = {
  name : 'lucy',
  foo : function() {
     console.log(this.name);
  }
}
obj.foo(); 

var otherObj = {
  name : 'john',
  foo : obj.foo
}

obj.foo(); 
otherObj.foo();

那么obj.foo(); otherObj.foo(); 就是我们上面所说的第2种情况。

先想一下,两次执行后结果是什么。


obj.foo() 其实就是:obj.foo.bind(obj),
也就是说函数在被执行的时候,是被obj调用的,那么函数内的this就是obj

function() {
   console.log(this.name); // 输出lucy
}

执行上下文(context)中的this是指向obj

otherObj.foo() 其实就是obj.foo.bind(otherObj)
也就是说函数在被执行的时候,是被otherObj调用的,那么函数内的this就是otherObj

function() {
   console.log(this.name);  // 输出john
}

再来看一个例子:

var name = 'Bob';
var obj = {
  name = 'lucy',
  foo : function() {
     console.log(this.name);
  }
}
obj.foo(); 

var otherObj = {
  name :'john',
  foo : function() {
     var testFunc = obj.foo();
     testFunc();
  }
}

otherObj.foo();

分析:
执行otherObj.foo(); 后,接着执行obj.foo();,也就是说执行下面的函数。
那么这个函数是被谁调用的呢,谁也没有调用这个函数obj.foo()前面谁也没有。
也就是obj.foo.bind(undefined);

function() {
   console.log(this.name);  // 输出Bob
}

最后看一个例子:

var name = 'Bot';
var obj = {
  name : 'lucy',
  showName: function() {
     console.log(this.name)
  },
  foo : function() {
     (function(callback) {
       callback();
     })(this.showName)
  }
}
obj.foo(); 

分析:
执行obj.foo(); 后,this.showName中的this就是obj,
也就是将obj.showName;传给cb,由于是立即执行函数,
则执行callback();也就是执行下面的函数
那么这个函数是被谁调用的呢,谁也没有调用这个函数callback前面谁也没有。
也就是obj.showName.bind(undefined);,输出Bob。

function() {
   console.log(this.name);  // 输出Bob
}

总结:
this被谁调用指向谁,没有被调用的情况下,浏览器默认为window。

特殊情况:
setTimeout,setInterval,匿名函数执行的时候,
函数体内的this为全局对象window。

最后说第5种,箭头函数中的this。

箭头函数内部并没有实现绑定this的机制,其实箭头函数并没有自己的this,
箭头函数内部的this总是指向父级作用域。

什么意思呢,看个例子。

    var name = 'Bob';
    var obj = {
        name : 'a',
        showName: () => {
            console.log(this.name);
        }
    }
    obj.showName(); // Bob

分析:
obj.showName()是在全局作用域下被调用的,然后执行下面的函数。

() => {
         console.log(this.name);
      }

由于箭头函数中的this,总是指向父级作用域
obj.showName()是在全局作用域下被调用的,不是obj,obj啥也不是。
所以输出Bob。

call、apply和bind的区别

function add(a,b,c) {
  console.log(this);
  return a+b+c;
}

以上3个方法都是函数的方法,call和apply都可以改变函数this,传递的参数方式不同。
call一个一个传递,add.call(obj, 1,2,3);
apply以数组的方式传递,add.apply(obj, [1,2,3]);,更方便。

bind也可以改变函数内部的this,它还可以传递固定参数,
var fix = add.bind(null, 100);
函数bind后,与call,apply方法的另一个区别是,
bind便不立即执行,而apply,call会立即执行,
add.apply(obj, [1,2,3]); 会立即执行得到结果6,
但是函数bind后,var fix = add.bind(null, 100);便不会立即执行,
fix(2,3),调用后才会执行,得到结果105,
var fix = add.bind(null, 100);绑定了第一个参数为100,
相当与固定了第一个参数的值为100,fix函数被调用后,则只需要传入之后的参数即可。


成cheng
27 声望0 粉丝