详解JavaScript中this指向的优先级(三)

·  阅读 278
详解JavaScript中this指向的优先级(三)

「这是我参与2022首次更文挑战的第12天,活动详情查看:2022首次更文挑战

上篇文章中:bind\call\apply、构造函数、箭头函数中的this指向(二),我们通过call、apply、bind方式对this指向进行绑定称为显式绑定,而根据调用关系确定this的指向称为隐式绑定。

那么显式绑定和隐式绑定的优先级谁更高呢?让我们看看今天的实例

this优先级

示例1

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

const obj1 = {
  a: 1,
  foo: foo
}

const obj2 = {
  a: 2,
  foo: foo
}

obj1.foo.call(obj2) // ?
obj2.foo.call(obj1) // ?
复制代码

上面的代码将分别输出2、1,也就是call、apply的显式绑定的优先级要更高。

示例2

function foo (a) {
  this.a = a
}

const obj1 = {}

let bar = foo.bind(obj1)
bar(2)
console.log(obj1.a) // ?
复制代码

上面的代码先通过bind将foo函数中的this绑定到obj1对象,然后返回新的函数bar,执行bar(2)后,由于this绑定的对象为obj1,所以obj1.a为2。所以这道题目将输出2

示例3

function foo (a) {
  this.a = a
}

const obj1 = {}

let bar = foo.bind(obj1)
let baz = new bar(3)
console.log(baz.a) // ?
复制代码

这道题目的输出为3

当使用bar作为构造函数调用时,bar本身是foo函数通过bind将函数内this绑定为obj1对象,但当我们使用new操作符调用时,返回的实例已经和obj1解绑了。也就是说,new操作修改了bind绑定的this指向,所以new的绑定this优先级要比bind绑定的更高。

示例4

function foo () {
  return a => {
    console.log(this.a)
  }
}

const obj1 = {
  a: 2
}

const obj2 = {
  a: 3
}

const bar = foo.call(obj1)
console.log(bar.call(obj2))
复制代码

上面的这道题又结合了箭头函数,所以看起来可能会有一些绕,没关系,我们来一步步的来梳理。

首先foo.call(obj1)将foo函数内的this绑定为obj1对象,然后返回的是一个箭头函数bar。

重点来了,箭头函数bar中的this是外层函数foo内的this指向决定的。

然后bar.call(obj2)尝试去修改箭头函数bar内的this指向,这里要记住箭头函数的this指向无法被修改。

所以箭头函数内的this指向仍是foo函数内的this也就是,被call修改成的obj1对象。

所以这道题目将输出2

记住:

在箭头函数中,this的指向是由外层函数或者全局作用域来决定。箭头函数的this指向无法被修改。

示例5

var a = 123
const foo = () => a => {
  console.log(this.a)
}

const obj1 = {
  a: 2
}

const obj2 = {
  a: 3
}

let bar = foo.call(obj1)
console.log(bar.call(obj2)) // ?
复制代码

这道题目考察的也是箭头函数的this指向问题。

根据箭头函数的特性

在箭头函数中,this的指向是由外层函数或者全局作用域来决定。箭头函数的this指向无法被修改。

上面的两次call函数都是无法修改箭头函数内的this指向。根据箭头函数的特性,是由其外层函数的作用域this决定。所以箭头函数bar中的this.a就会向上层去函数作用域去寻找,它的上层是箭头函数foo,所以还要向上层进行寻找,再上层就是全局作用域,所以最终this指向为window,在全局作用域中有一个变量a为123。

所以这道题将输出123

示例6

这道题和上面的一样,只是将变量a的声明方式从var变成了const,那么结果是什么呢?

const a = 123
const foo = () => a => {
  console.log(this.a)
}

const obj1 = {
  a: 2
}

const obj2 = {
  a: 3
}

let bar = foo.call(obj1)
console.log(bar.call(obj2)) // ?
复制代码

答案是undefined,因为const或者let声明的变量不会被挂载到window对象上。所以this指向window对象时,也找不到a变量。

通过今天的这六个实例,相信大家对this指向的理解,又更上一层楼了。

欢迎我的公众号【小帅的编程笔记】,让自己和他人都能有所收获!

分类:
前端
收藏成功!
已添加到「」, 点击更改