this和执行上下文

201 阅读2分钟

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

this和执行上下文

我们先来看段代码:

var bar = {
  myName:"juejin.cn",
  printName: function () {
    console.log(myName)
  }
}
function foo() {
  let myName = "掘金"
  return bar.printName
}
let myName = "稀土"
let _printName = foo()
_printName() // 稀土
bar.printName() // 稀土

两次执行printName方法打印的结果都是稀土,也就是全局变量。

这与我们的直觉不同,特别是第二条语句,直接执行的bar.printName(),不应该是返回bar对象内变量myName的值吗?只能说在有的语言中是这样的,取当前对象的变量值。但JavaScript中不是这样。这就很奇怪了。在对象内取不到对象内的属性值。为此,JavaScript就搞出来了我们要说的this。

对上面代码略作修改:

var bar = {
  myName:"juejin.cn",
  printName: function () {
    console.log(this.myName)
  }    
}

这样执行bar.printName(),返回的结果就是bar对象的myName变量值了。

JavaScript中this和执行上下文到底是什么关系

首先,执行上下文里面包含有之前说的变量环境、词法环境和外部环境,还有this也属于执行上下文中。可以这么理解,每一个执行上下文都绑定有一个this。

image.png

然后,在JavaScript中有几种执行上下文呢?这个与作用域就有一定关系。作用域在ES6之后总共有三种:全局作用域、函数作用域和块级作用域。而执行上下文呢?也是三种,但不是一一对应的关系。

  • 全局执行上下文
  • 函数执行上下文
  • eval函数(尽量少用)

我们常用的一般是全局执行上下文和函数执行上下文两种。

设置this指向

全局执行上下文指向的是window对象。

函数执行上下文this指向函数内部的上下文环境。当然我们可以手动执行来设置或者改变this指向某个对象,一般有三种常用方式:

call/apply

这两个方法的用法基本相同,只是传参方式略有差别。

let bar = {
  myName : "Lilei",
  test1 : 1
}
function foo(){
  this.myName = "Jim"
}
foo.call(bar)
console.log(bar) // {myName: 'Jim', test1: 1}

通过call方法已经改变了bar对象myName属性的值。

通过对象调用

这个很好理解。如下代码,输出的this指向的执行上下文。

var myObj = {
  name : "Lilei", 
  showThis: function(){
    console.log(this)
  }
}
myObj.showThis()
构造函数
function CreateObj(){
  this.name = "constructor"
}
var myObj = new CreateObj()

构造函数其实返回的也是一个对象,并且this通过内部call方法指向的是新创建的对象。