一网打尽 this,对执行上下文说 Yes

image.png

事实上,调用函数会创建新的属于函数本身的执行上下文。
执行上下文的调用阶段回决定this的指向。
到此,我们可以得出结论: this 的执向,是在调用函数时根据执行上下文所动态确定的。
具体环节和规则,可以先“死记硬背”以下几条规律,后面再慢慢一一分析:

  • 在函数体中,简单调用该函数时(非显式/隐式绑定下),严格模式下 this 绑定到 undefined,否则绑定到全局对象 window/global;
  • 一般构造函数 new 调用,绑定到新创建的对象上;
  • 一般由 call/apply/bind 方法显式调用,绑定到指定参数的对象上;
  • 一般由上下文对象调用,绑定在该对象上;
  • 箭头函数中,根据外层上下文绑定的 this 决定 this 指向。

    全局环境的this

    这种情况下相对简单直接,函数在浏览器全局环境中被简单调用,非严格模式下 this 指向 window。
    在 use strict 指明严格模式的情况下就是 undefined。
    1. function f1 () {
    2. console.log(this)
    3. }
    4. function f2 () {
    5. 'use strict'
    6. console.log(this)
    7. }
    8. f1() // window
    9. f2() // undefined

    变种

    1. const foo = {
    2. bar: 10,
    3. fn: function() {
    4. console.log(this)
    5. console.log(this.bar)
    6. }
    7. }
    8. var fn1 = foo.fn
    9. fn1()
    this 仍然指向的是window。虽然 fn 函数在 foo 对象中作为方法被引用,但是在赋值给 fn1 之后,fn1 的执行仍然是在 window 的全局环境中

    上下文对象调用的this

    1. const person = {
    2. name: 'Lucas',
    3. brother: {
    4. name: 'Mike',
    5. fn: function() {
    6. return this.name
    7. }
    8. }
    9. }
    10. console.log(person.brother.fn())
    在这种嵌套的关系中,this 指向 最后 调用它的对象,因此输出将会是:Mike。

    bind/call/apply改变this指向

    一句话总结,他们都是用来改变相关函数 this 指向的,但是 call/apply 是直接进行相关函数调用;bind 不会执行相关函数,而是返回一个新的函数,这个新的函数已经自动绑定了新的 this 指向,开发者需要手动调用即可。再具体的 call/apply 之间的区别主要体现在参数设定上 ``` const target = {} fn.call(target, ‘arg1’, ‘arg2’)

const target = {} fn.apply(target, [‘arg1’, ‘arg2’])

const target = {} fn.bind(target, ‘arg1’, ‘arg2’)()

  1. **对 call/apply/bind 的高级考察往往会结合构造函数以及组合式实现继承。**
  2. <a name="IE3MM"></a>
  3. ### 构造函数和this
  4. <a name="XvBBY"></a>
  5. #### new 操作符调用构造函数,具体做了什么
  6. - 创建一个新的对象;
  7. - 将构造函数的 this 指向这个新对象;
  8. - 为这个对象添加属性、方法等;
  9. - 最终返回新对象。

function Foo(){ this.user = “Lucas” const o = {} return o } const instance = new Foo() console.log(instance.user)

function Foo(){ this.user = “Lucas” return 1 } const instance = new Foo() console.log(instance.user)

  1. **结论:** 如果构造函数中显式返回一个值,且返回的是一个对象,那么 this 就指向这个返回的对象;如果返回的不是一个对象,那么 this 仍然指向实例
  2. <a name="hEWVk"></a>
  3. ### 箭头函数中的this指向
  4. **结论:** 箭头函数使用 this 不适用以上标准规则,而是根据外层(函数或者全局)上下文来决定。

const foo = {
fn: function () {
setTimeout(function() {
console.log(this) }) }
}
console.log(foo.fn())

  1. this出现在setTimeout()中的匿名函数里,因此this指向window对象。

const foo = {
fn: function () {
setTimeout(() => {
console.log(this) }) }
} console.log(foo.fn())

// {fn: ƒ}

  1. <a name="G9pmf"></a>
  2. ### this优先级相关
  3. 把通过 call、apply、bind、new 对 this 绑定的情况称为显式绑定;根据调用关系确定的 this 指向称为隐式绑定。<br />call apply 的显示绑定一般来说优先级更高。<br />**new 绑定修改了 bind 绑定中的 this,因此 new 绑定的优先级比显式 bind 绑定更高。**<br />**箭头函数的绑定无法被修改**

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

const obj1 = { a: 2 }

const obj2 = { a: 3 }

var bar = foo.call(obj1) console.log(bar.call(obj2)) ``` 使用 const 声明的变量不会挂载到 window 全局对象当中。因此 this 指向 window 时,自然也找不到 a 变量了