JS中的this

前言

🤟先来了解一下this的起源:

写函数时,在还不知道对象的名字(对象还没有声明)时拿到一个对象的属性,可以怎么做呢? 第一种:使用形式参数,调用函数的时候再传入 ,python使用了这个方法

let person = {
  name: 'moji',
  sayHi(p){
    console.log(`你好,我叫` + p.name)
  }
}
person.sayHi(person) 

这显然和 JS 中对象调用函数的方式不一样,JS中是直接person.sayHi()

第二种:JS解决方法是,在每个函数里加入了this,可以使用this来调用还不知道名字的对象的属性值,在被对象调用时,this里的值就是对象的地址,使用this来获取对未知对象的引用。

let person = {
  name: 'moji',
  sayHi(this(省略)){
    console.log(`你好,我叫` + this.name)
  }
}
person.sayHi()

person.sayHi()会隐式地把 person(person 是个地址) 作为 this 传给 sayHi,这样,每个函数都能用 this 获取一个未知对象的引用了。

🤏简单来说,this就是最终调用函数的对象

ps:函数里不给其他条件,this默认指向window,箭头函数自己没有this,函数外面的this就函数里调用的this,call也无法使用

如何确定this

最重要的是this实际上是在函数被调用时发生的绑定,它指向什么完全取决于函数在哪里被调用!

方法一:转换代码

参考博客

把函数调用的方式变为使用call调用的方式

func.call(context, p1, p2)

this,就是上面代码中的 context,它是执行上下文的一个属性。执行上下文是当一个函数被调用时,被创建用于记录函数在哪里调用(调用栈),函数的调用方式,传入的参数等信息。

例如:

func(p1, p2) 等价于
func.call(undefined, p1, p2)

obj.child.method(p1, p2) 等价于
obj.child.method.call(obj.child, p1, p2)

如果传的 context 是 null 或 undefined,那么 window 对象就是默认的 context(严格模式下默认 context 是 undefined)

方法二:使用《你不知道的JavaScript(上)》中的准则

  • 首先,需要找到这个函数的直接调用位置
  • 找到之后就可以顺序应用下面四条规则来判断this的绑定对象
  1. 由new调用——绑定到新创建的对象
  2. 由call、apply、bind调用——绑定到指定的对象
  3. 由上下文对象调用——绑定到那个上下文对象(可以通过上面的转换代码的方式判断上下文对象)
  4. 默认:在严格模式下绑定到undefined,否则绑定到全局对象

一些特例

[ ] 语法

function fn (){ console.log(this) }
var arr = [fn, fn2]
arr[0]() // 这里面的 this 又是什么呢?

我们可以把 arr[0]() 想象为arr.0(),虽然后者的语法错了,但是形式与转换代码里的 obj.child.method(p1, p2) 对应上了,于是就可以愉快的转换了:

        arr[0]() 
假想为    arr.0()
然后转换为 arr.0.call(arr)
那么里面的 this 就是 arr 了 :)

箭头函数

箭头函数里并没有 this,箭头函数会继承外层函数调用this绑定,如果在箭头函数里看到 this,直接把它当作箭头函数外面的 this 即可。

call()、apply()、bind()用法

可以使用call / apply / bind 来强制指定 this 的值

call()和apply()

call 方法第一个参数也是作为函数上下文的对象,后面传入的是一个参数列表,而不是单个数组。

apply 方法传入两个参数:一个是作为函数上下文的对象,另外一个是作为函数参数所组成的数组。

作用:

  • 改变this的指向

  • 调用函数

    person.sayHi()=person.sayHi.call(person) ,不需要传this时,使用undefined来占位

bind()

它和 call 很相似,接受的参数有两部分,第一个参数是是作为函数上下文的对象,第二部分参数是个列表,可以接受多个参数。使用bind来绑定this,让this不再改变

面试题

参考

关于this的两道面试题和三篇文章

this 的值到底是什么?一次说清楚

你怎么还没搞懂 this?

JS 里为什么会有 this