JS进阶之this、执行上下文

248 阅读3分钟

-----------------------这一行就是标题,我不知道怎么把它变成正文,干脆不管了

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情 >>

一、this

this 表示指向当前。默认情况下指向 window 全局对象。

let a = '我是全局变量 a'

let obj = {
    a: '我是局部变量 a',
    b: function(){
        console.log(a)
    }
}

// 以下代码会输出什么?
console.log(a)

console.log(obj.a)

obj.b()

这三个 log 在输出变量时都做了什么操作?

输出:
我是全局变量 a
我是局部变量 a
我是全局变量 a

为什么会这样输出?因为 js 中对象及变量的调用,永远指向当前环境(作用域),如果没有在当前环境中找到对应变量则会往上去找,至到全局环境 windows(全局作用域)。

  • 其中第一个 log 在执行时:查找当前作用域(windows)--> 获取当前作用域下的变量 a --> 输出。

  • 第二个 log :查找作当前作用域(windows)--> 获取变量 a,发现这个变量指向了对象 obj 的属性 a --> 输出 obj 中的属性 a。

  • 第三个 log:查找当前作用域(obj)--> 获取变量 a,发现没有指向 --> 往上层作用域中查找变量 a --> 在全局环境中找到 --> 输出全局变量中的 a。

    var a = '我是全局变量 a' var b = '我是全局变量 b'

    var obj = { a: '我是局部变量 a', b: function(){ console.log(a) }, c: function(){ console.log(this.a) }, d: function(){ console.log(b) this.b() } }

    console.log(a)

    console.log(obj.a)

    obj.b()

    obj.c()

    obj.d()

输出:

我是全局变量 a
我是局部变量 a
我是全局变量 a
我是局部变量 a
我是全局变量 b
我是全局变量 a

为什么会这样输出?obj 中的 c() 和 d() 方法在调用的时候执行了什么?

  • obj.c():在全局调用这个函数后,js 会在 windows 的下面创建一个 obj 执行上下文,然后在这个上下文中执行 c() 函数。在执行函数中的 log 时候,js 发现你在变量的前面加上了 this,js 就知道你想调用的是当前这个上下文中的属性 a,而不是全局环境中的变量 a。于是输出:我是局部变量 a。

  • obj.d():同理,调用 obj.d() 函数的时候:

  • log b 变量这一行,因为没有明确指向,所以 js 默认会将这个变量指向全局,即输出:全局变量 b。

  • 调用函数 b() 这一行,有了 this 这个指向,明确表示在当前上下文中执行这个 b(),也就是调用一遍 obj.b()。

1. this 的绑定规则。

在 JavaScript 中,this 指向的绑定规则有以下四种:

  1. new 绑定:函数被 new 调用,this 指向由 new 新构造出来的这个对象。
  2. 显式绑定:函数通过 call()、apply()、bind()调用,this 指向被绑定的对象。
  3. 隐式绑定:如果函数调用时,前面存在调用它的对象,那么 this 就会隐式绑定到这个对象上。
  4. 默认绑定:非严格模式情况下,this 指向 window, 严格模式下,this 指向 undefined。

2. this 绑定的优先级

this 绑定的优先级:new 绑定 > 显式绑定 > 隐式绑定 > 默认绑定。

二、执行上下文(Execution Context)

执行上下文可以理解为当前代码的执行环境。

执行上下文与作用域的区别:

  1. 执行上下文在代码运行时确定,随时会改变。
  2. 而作用域在定义时确定,永远不会改变。

1. 执行上下文的类型

  1. 全局执行上下文(windows)。
  2. 函数执行上下文(function)。
  3. eval 执行上下文(evla())。