一文搞定JavaScript的this指向问题

Posted 忘忘碎斌bin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一文搞定JavaScript的this指向问题相关的知识,希望对你有一定的参考价值。


代码执行时this在内存中的位置

注意:this的绑定是在代码执行时动态绑定上去的,与函数定义的位置是无关的,而与函数调用的方式和调用的位置有关。

this绑定规则

规则一:默认绑定(独立函数调用)

一个函数经过其他操作,函数直接被调用,并没有进行任何的对象关联

规则二:隐式绑定

通过某个对象发起的函数调用

规则三:显示绑定

明确的给函数指定上一个对象(手动指定)

规则四:new 绑定

JavaScript中的函数可以当做类的构造函数来使用,也就是使用new关键字。

使用new关键字调用函数时,会进行以下操作:

  • 创建一个对象
  • 修改创建对象的原型(prototype)指向
  • 修改创建函数内的this指向
  • 返回创建的对象

系统API中的this指向

  • 定时器

  • DOM事件

  • 数组方法

多个绑定优先级的比较

结论: new绑定 > 显示绑定( apply | call | bind ) > 隐式绑定(对象.函数名()) > 默认绑定(独立函数调用)

1、默认绑定的优先级是最低的

2、显示绑定的优先级高于隐式绑定

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

obj.foo(); // {name: 'obj', foo: ƒ}

// 1、call/apply的显示绑定高于隐式绑定
obj.foo.call("fzb"); // String {'fzb'}
obj.foo.apply("fzb"); // String {'fzb'}

// 2、bind的显示绑定高于隐式绑定(两个列子,第二个比较更明显)
var bar = obj.foo.bind("fzb");
bar(); // String {'fzb'}

function foo() {
  console.log(this);
}
var info = {
  name: "info",
  foo: foo.bind("fzb"),
};

info.foo(); // String {'fzb'}

3、new绑定的优先级高于隐式绑定

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

var s = new obj.foo(); // foo {}

4、new绑定优先级高于显示绑定

// call/apply一使用就会是函数指向,不能和new绑定比较
function foo() {
 console.log(this);

}

var fn = foo.bind("fzb");
var s = new fn(); //foo {}

特殊绑定

忽略显示绑定

理论上来说,显示绑定传入指定的对象,那么函数内的this指向应该指向这个对象,如果传入的是undefined和null呢?
apply、bind的结果也一样的

function foo() {
  console.log(this);
}

var obj = {
  name: "obj",
  foo: foo,
};

foo.call(null); // window
foo.call(undefined); // window
obj.foo.call(null); // window
obj.foo.call(undefined); // window

对于数组方法呢?

[1, 2, 3, 4].forEach(function (item) {
  console.log(this); // window
}, null);

间接函数引用

var obj1 = {
  name: "obj1",
  foo: function () {
    console.log(this);
  },
};

var obj2 = {
  name: "obj2",
};
obj2.foo = obj1.foo;
obj2.foo(); // {name: 'obj2', foo: ƒ}
// 这时一个赋值语句,会将foo函数单独拿出来执行,是一个独立函数调用。
(obj2.foo = obj1.foo)(); // window

this规则之外-箭头函数

this的四条规则对箭头函数是没有用的,箭头函数本身不绑定this,是由外层作用域来决定的。

var name = "window";
var obj = {
  name: "obj",
  foo: () => {
    console.log(this.name);
  },
  bar: function () {
    return () => {
      console.log(this.name);
    };
  },
};
obj.foo(); // window
obj.bar()(); // obj

面试题练习

面试题一:

面试题二:

面试题三:

面试题四:

以上是关于一文搞定JavaScript的this指向问题的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript专题专栏目录

一文帮你搞定90%的JS手写题

一文梳理JavaScript中的this

一文搞懂this指向

JavaScript中的this指向问题

一文搞定 Flink Checkpoint Barrier 全流程