一文搞懂this指向

1、this的默认绑定

this 默认指向了 window

// 1、全局环境下的this指向了window
  console.log(this);

  // 2、函数独立调用,函数内部的this也指向了window
  function fn() {
    console.log(this);
  }
  fn();

  // 3、被嵌套的函数独立调用时,this默认指向了window
  var a = 0;
  var obj = {
    a: 2,
    foo: function () {
      // 函数当作对象的方法调用时,this指向了obj
      var that = this;  // obj
      function test() {
        console.log(that.a); // window
      }
      test();
    }
  }
  obj.foo();

  // 4、IIFE 自执行函数中内部的this指向了window
  var a = 10;
  function foo() {
    console.log(this);
    (function test(that) {
      console.log(that.a);
    })(this)
  }
  var obj = {
    a: 2,
    foo: foo
  }
  obj.foo();

  (
    function () {
      console.log(this);  //window
    }
  )()

  // 5、闭包中的this默认指向了window
  var a = 0;

  var obj = {
    a: 2,
    foo: function () {
      var c = this.a;
      return function test() {
        console.log(this);  //window
        return c;
      }
    }
  }

  var fn = obj.foo();
  fn();

2、this的隐式绑定

// 当函数当作方法来调用,this指向了直接对象
  function foo() {
    console.log(this.a);
  }
  var obj = {
    a: 1,
    foo: foo,
    obj2: {
      a: 2,
      foo: foo
    }
  }
  // foo()函数的直接对象是obj,this的指向指向了直接对象
  obj.foo();
  // foo()函数的直接对象是obj2,this的指向指向了直接对象
  obj.obj2.foo();

3、this的显示绑定

// call()、apply()、bind()把对象绑定到this上,叫做显式绑定
  var a = 0;
  function foo() {
    console.log(this.a);
  }
  var obj = {
    a: 2
  }
  foo(); //0
  foo.call(obj);  //2
  foo.apply(obj); //2
  var fn = foo.bind(obj);
  fn(); //2

  // 2、硬绑定,是显式绑定的一个变种,使得this不能再被改变
  var a = 0;
  function foo() {
    console.log(this.a);
  }
  var obj = {
    a: 2
  }
  var bar = function () {
    foo.call(obj);
  }
  bar();  //2
  setTimeout(bar, 1000);  //2
  bar.call(window); //2

  // 3、数组的forEach(fn,对象)、map()、filter()、some()、every()
  var id = 'window';
  /* function fn(el) {
    console.log(el, this.id);
  } */
  var obj = {
    id: 'fn'
  }
  var arr = [1, 2, 3];
  // this 指向了 obj
  arr.forEach(function (el, index) {
    console.log(el, index, this);
  }, obj)

4、new关键字绑定

function fn() {
    // 1、如果是new关键字来执行函数,相当于构造函数来实例化对象,那么内部的this指向了当前实例化的对象
    console.log(this);
  }
  var fn1 = new fn();
  console.log(fn1);

  // 2
  function fn2() {
    // this还是指向了当前的对象
    console.log(this);
    // 使用return来返回对象的时候,实例化出来的对象是当前的返回对象
    return {
      name: '张三'
    }
  }
  var fn2 = new fn2();
  console.log(fn2);

  // 3
  var person = {
    fav:function(){
      return this;
    }
  }
  var p = new person.fav();
  console.log(p,p === person);  //fav,false

  // 实例化出来的对象内部的属性constructor属性指向了当前的构造函数
  console.log(p.constructor === person.fav);  //true

5、隐式丢失this的5种情况

隐式丢失就是指被隐式绑定的函数丢失了绑定对象,从而默认绑定到了window,这种情况非常容易出错且又非常常见。

// 1、隐式丢失,函数别名
  var a = 0;
  function foo() {
    console.log(this.a);
  }
  var obj = {
    a: 1,
    foo: foo
  }
  // 把obj.foo()赋值给变量bar,造成隐式丢失的情况,因为只是把obj.foo赋值给了bar变量,
  // 而bar与obj毫无关系
  var bar = obj.foo;
  bar();

  // 2、参数传递
  var a = 0;
  function foo() {
    console.log(this.a);
  }
  function bar(fn) {
    fn();
  }
  var obj = {
    a: 1,
    foo: foo
  }
  // 把obj.foo当作参数传递到bar函数中,有隐式的函数赋值 fn=obj.foo,只是把foo函数赋值给了fn,而fn函数与obj对象毫无关系,所以当前foo函数内部的this指向了window
  bar(obj.foo);

  // 3、内置函数,setTimeout()和setInterval()第一个参数的回调函数中的this,默认指向了window,跟第2种情况是类似的
  var a = 0;
  function foo() {
    console.log(this.a);
  }
  var obj = {
    a: 1,
    foo: foo
  }

  setTimeout(obj.foo, 1000);

  // 4、间接调用
  var a = 0;
  function foo() {
    console.log(this.a);
  }
  var obj = {
    a: 1,
    foo: foo
  }
  var p = { a: 2 };
  // 隐式绑定,函数当作对象的方法来使用,内部的this指向了obj
  obj.foo();  //1
  // 将obj.foo函数对象赋值给了p.foo()函数,然后立即执行,相当于仅仅是foo()函数的立即调用,内部的this默认指向了window
  (p.foo = obj.foo)();  //0
  p.foo = obj.foo
  p.foo();  //2

  // 5、其他情况,指向了window的特殊情况
  var a = 0;
  function foo() {
    console.log(this.a);
  }
  var obj = {
    a: 1,
    foo: foo
  }
  (obj.foo = obj.foo)();  //0
  (false || obj.foo)(); //0
  (1,obj.foo)();  //0

6、严格模式下的this指向

// 1、严格模式下,独立调用的函数内部的this指向了undefined
function fn(){
  'use strict'
  console.log(this);
}
fn();

// 2、严格模式下,函数apply()和call()内部的this始终是他们的第一个参数
var color = 'red';
function showColor(){
  'use strict'
  console.log(this);  //null
  console.log(this.color);  //报错
}
showColor.call(null);

7、总结

1、默认绑定

2、隐式绑定

3、显示绑定

4、new绑定

分别对应函数的四种调用:

-独立调用

-方法调用

-间接调用

call()、apply()、bind()

-构造函数调用

隐式丢失:

1、函数别名

2、函数当作参数传递

3、内置函数

4、间接调用

5、其他情况,指向了window的特殊情况

文章最后:更多精彩文章和资源,欢迎参观我的公众号:小笑残虹。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值