一、this

this的四种绑定方式:隐式绑定显式绑定window绑定new绑定

隐式绑定:使用对象来调用其内部的一个方法,该方法的this是指向对象本身的,this永远指向最后调用它的那个对象。

显式绑定:通过call来设置函数执行上下文的this指向。

window绑定:在ES5严格模式中,JavaScript不会默认this指向window对象,而会正确地把this保持为underfined。

new绑定:用new调用函数时,JavaScript解释器都会在底层创建一个全新地对象并把这个对象当做this

改变this指向:

  • 使用ES6箭头函数

  • 在函数内部使用_this = this

  • 使用apply、call、bind

  • new一个实例化对象

  1. this的指向

    1. 作为对象方法调用

      当函数作为对象地方法被调用时,this指向该对象

      var obj = {
      a: 1,
      getA: function(){
      alert(this === obj); // true
      alert(this.a); // 1
      }
      }
      obj.getA();
    2. 作为普通函数调用

      作为普通函数调用,this指向全局对象

      window.name = 'globalName';
      var getName = function(){
      return this.name;
      }
      console.log(getName());

      或者

      window.name = 'globalName';
      var myObject = {
      name: 'seven',
      getName: function(){
      return this.name;
      }
      };
      var getName = myObject.getName;
      console.log(getName());

      箭头函数注意:

      1. 函数体内this就是定义时所的对象,而非调用时的所在对象,和普通函数相反

      2. 箭头函数无法用做构造器,即不能使用new调用

      3. 不能使用arguments对象,不存在

      4. 不可以使用yield命令,即无法用做Generator命令

    3. 构造器调用

      JavaScript中没有类,但是可以从构造器中创建对象,同时也提供了new运算符,使得构造函数看起来更像一个类。

      除了宿主提供的一些内置函数,大部分JavaScript函数都可以当作构造器使用。构造器的外表跟普通函数一摸一样,它们的区别在于被调用的方式。当用new运算符调用函数时,该函数总是返回一个对象,通常情况下,构造器里的this就指向返回的这个对象。

    4. Function.prototype.callFunction.prototype.apply调用

      跟普通函数相比,用 Function.prototype.callFunction.prototype.apply可以动态地改变传入函数地this。

      var obj1 = {
      name:'sven',
      getName: function(){
      return this.name;
      }
      };
      var obj2 = {
      name: 'anne'
      };
      console.log(obj1.getName()); // sven
      console.log(obj1.prototype.call(obj2)); // anne
  2. 丢失的this

    var obj = {
    myName: 'sven',
    getName: function(){
    return this.myName;
    }
    };
    console.log(obj.getName()); // sven
    var getName2 = obj.getName;
    console.log(getName2()); // underfined

    当调用obj.getName时,getName方法是作为obj对象地属性被调用时,此时的this指向obj对象,所以obj.getName()输出sven。

    当另外一个变量getName2来引用 obj.getName,并且调用getName2时,此时时普通函数调用方式,this是指向全局window的,所以程序执行结果是underfined。

二、call 和 apply

bind是创建一个新对象

  • call和apply是立即执行,bind则是返回了一个绑定的this的新函数,只有调用了这个新函数才真正的调用了目标函数。

  • bind函数存在多次绑定问题,如果多次绑定this,则以第一次为准

  • bind函数实际上是显式绑定(call、apply)的一个变种,称为硬绑定,ES5中提供了内置的方法 Function。prototype.bind

  1. call和apply的区别

    apply接受两个参数,第一个参数指定了函数体内的this对象的指向,第二个参数为一个带下标的集合,这个集合可以为数组,也可以为类数组,apply方法把这个集合中的元素作为参数传递给被调用的函数。

    call传入的参数量不固定,跟apply不同的是,第一个参数也是代表函数体内的this指向,从第二个参数往后,每个参数被依次传入函数。

    当使用call或者apply的时候,如果我们传入的第一个参数为null,函数体内的this会指向默认的宿主对象,在浏览器中则是window。

    但如果是在严格模式下,函数体内的this还是为null

  2. call和apply的用途

    1. 改变this指向

      call和apply最常见的用途是改变函数内部的this指向

      在实际开发中,经常会遇到this指向被不经意改变的场景,比如有一个div节点,div节点的onclick事件中的this本来是指向这个div的:嵌套中的this不会从外层函数中继承

      document.getElementById('div1').onclick = function(){
      alert(this.id); // div1
      }

      假如该事件函数中有一个内部函数func,在事件内部调用func函数时,func函数体内的this就指向window,而不是我们预期的div:

      document.getElementById('div1').onclick = function(){
      alert(this.id); // div1
      var func = function(){
      alert(this.id); // underfined
      }
      }

      这时候我们用call来修正func函数内的this,使其依然指向div:

      document.getElementById('div').onclick = function(){
      var func = function(){
      alert(this.id);
      }
      func.call(this);
      }
    2. Function.prototype.bind

      大部分高级浏览器都实现了内置的 Function.prototype.bind,用来指定函数内部的this指向

    3. 借用其他对象的方法

      我们知道,杜鹃既不会筑巢,也不会孵椆,而是把自己的蛋寄托给云雀等其他鸟类,让它们代为孵化和养育。