【前端--JavaScript】知识点(三)——关于this你不知道的事 (二)

178 阅读3分钟

这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战**

上一篇了解了this一些常见的误区,明白了每个函数的this是在调用时候被绑定的,完全取决于函数的调用位置。

今天来研究一下this的绑定规则——

默认绑定

先看一段代码:

function foo() {
  console.log(this.a);
}
var a = 2;
foo();// 2

在这里我们可以看到在调用foo()时候,this.a被解析成了全局变量a,因为函数调用时应用了this的默认绑定this就指向全局对象。

怎么知道函数是否用的是默认绑定呢,我们能看到foo()是直接使用不带任何修饰的函数引用进行调用的,因此只能使用默认绑定,无法应用其他规则。

要注意的是,如果在严格模式下,则不能将全局对象用于默认绑定,因此this会绑定到undefined。所以说虽然this的绑定规则完全取决于调用位置,但是只有在非严格模式下默认绑定才能绑定到全局对象,在严格模式下调用foo()则不影响默认绑定。

function foo() {
  "use strict"
  console.log(this.a);
}
var a = 2;
foo(); // TypeError: this is undefined
function foo() {
  console.log(this.a);
}
var a = 2;
(function () {
  "use strict"
  foo(); // 2
}

隐式绑定

再看这段代码:

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

在这里,foo()被调用的时候,前面加上了对obj的引用,当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象,因为调用foo()this被绑定到obj,所以this.aobj.a是一样的。

显式绑定

在隐式绑定时,我们必须在一个对象内部包含一个指向函数的属性,并通过这个属性间接引用函数,从而把this间接(隐式)绑定到这个对象上。 如果我们不想在对象内部包含函数引用,想在某个对象上强制调用函数,该怎么做呢?

JavaScript中很多函数有一些有用的特性,我们可以利用这些特性来解决这个问题。比如使用函数的call(..)apply(..)方法,这两个方法的第一个参数是一个对象,是给this准备的,接着在调用函数的时候将其绑定到this,这样可以直接指定this的绑定对象,因此我们称之为显示绑定

function foo() {
 console.log(this.a);
}
var obj = {
 a: 2,
};
foo.call(obj);// 2

值得注意的是如果传入了一个原始值(字符串类型、布尔类型或者数字类型)来当作this的绑定对象,这个原始值就会被转换成他的对象模式(也就是new string(..)new Boolean(..)或者new Number(..))。这通常叫做装箱。

(从this绑定的角度来说,call(..)apply(..)是一样的,它们的区别体现在其他参数上,在这暂时不考虑。)

new绑定

看这段代码:

function foo() {
 console.log(this.a);
}
var bar = new foo(2);
console.log( bar.a )// 2

使用new来调用foo(..)时,我们会构造一个新对象并把它绑定到foo(..)调用中的this上,这种称之为new绑定