我理解的this

  • this的设计跟JS的内存结构有关,对象的属性可以是函数,而函数也是对象,是单独存储的,所以函数的运行环境是可变的,没有办法在定义的时候知道谁会调用它,便设计了this来代替那个未来调用这个函数的对象。
  • 不管什么场合使用this,this一定指代某个对象或运行环境
  • this的指向不清楚,跟函数的调用方式有直接的关系,函数调用默认使用隐式传递this,大部分时候可以这样传递,但是不便于理解this,建议用call的方式去显示的绑定this。
    var A = {
    name: '张三',
    describe: function () {
      return '姓名:'+ this.name;
    }
    };
    显示传递this
    A.describe.call(A) 
    隐式传递this
    A.describe()

绑定this

  • function.call(this,arg1,arg2,..)
    call后面括号的第一个参数是什么,this就是什么,不传或者传入undefined、null,则默认为全局对象。
    看一些例子
    var n = 123;
    var obj = { n: 456 };
    function a() {
    console.log(this.n);
    }
    a.call() // 123
    a.call(null) // 123
    a.call(undefined) // 123
    a.call(window) // 123
    a.call(obj) // 456
  • function.apply(this,[arg1,arg2,...])
    apply的第一个参数是绑定的this对象,第二个参数是一个数组,对数组进行操作时用apply很方便。
  • bind
    bind方法和上面两个不同,它将this绑定到一个对象上以后不会执行该函数而是返回一个新的函数

    几个要注意的地方

    1. bind()函数每次执行一次就会返回一个函数
    2. 在map,forEach等有回调函数的方法里使用时使用bind绑定this
      示例:
      var obj = {
      name: '张三',
      times: [1, 2, 3],
      print1: function () {
      this.times.forEach(function (n) {
      console.log(this.name);
      }.bind(this));
      },
      print2: function () {
      this.times.forEach(function (n) {
      console.log(this.name);
      });
      }
      };
      obj.print2() //没有任何输出
      obj.print1() //'张三'*3
    3. 结合call使用
      var slice = Function.prototype.call.bind(Array.prototype.slice);
      slice([1, 2, 3], 0, 1) // [1]
      相当于Array.prototype.slice.call([1, 2, 3], 0, 1) 
      更骚的写法
      function f() {
      console.log(this.v);
      }
      var o = { v: 123 };
      var bind = Function.prototype.call.bind(Function.prototype.bind);
      bind(f, o)() // 123

使用this要避免的一些情况

  • 多层this
    var o = {
    f1: function () {
    console.log(this);
    var f2 = function () {
     console.log(this);
    }();
    //使用call绑定
    var f3 = function () {
     console.log(this);
    }.call(this);
    //使用bind绑定
    var f4 = function () {
     console.log(this);
    }.bind(this)();
    }
    }
    o.f1()
    // {f1: ƒ}
    // Window
    // {f1: ƒ}
    // {f1: ƒ}
  • 数组方法中的this
    var o = {
    v: 'hello',
    p: [ 'a1', 'a2' ],
    f1: function f() {
    var that = this;
    this.p.forEach(function (item) {
     console.log(that.v+' '+item);
    });
    },
    //在回调函数中传入第二参数绑定this
    f2: function f() {
    this.p.forEach(function (item) {
     console.log(that.v+' '+item);
    },this);
    }
    }
    o.f1()
    // hello a1
    // hello a2
    o.f2()
    // hello a1
    // hello a2