说明
浏览器工作原理与实践专栏学习笔记
为什么需要 this
在对象内部的方法中使用对象内部的属性是一个非常普遍的需求。但是 JavaScript 的作用域机制并不支持这一点,基于这个需求,JavaScript 又搞出来另外一套 this 机制。
作用域链和 this 是两套不同的系统,它们之间基本没太多联系。
JavaScript 中的 this 是什么
执行上下文中的 this:this 是和执行上下文绑定的,每个执行上下文中都有一个 this。
执行上下文主要分为三种,那么 this 也只有这三种
- 全局执行上下文----全局执行上下文中的 this
- 函数执行上下文----函数中的 this
- eval 执行上下文----eval 中的 this
全局执行上下文中的 this
全局执行上下文中的 this 是指向 window 对象的。
这也是 this 和作用域链的唯一交点,作用域链的最底端包含了 window 对象,全局执行上下文中的 this 也是指向 window 对象。
我们可以打开控制台输入 console.log(this)
函数执行上下文中的 this
例子:
function foo(){ console.log(this) } foo()
打印出来发现还是指向 window 对象,说明在默认情况下调用一个函数,其执行上下文中的 this 也是指向 window 对象的。
改变 this 指向
设置函数执行上下文中的 this 值的三种方式
1. 通过函数的 call、bind 和 apply方法设置
以 call 为例:下面的 this 指向 obj 对象
let obj = { myName : "kaimo", } function foo(){ this.myName = "凯小默" } foo.call(obj) console.log(obj) console.log(myName)
2. 通过对象调用方法设置
例子:this 指向了 myObj
var myObj = { name : "凯小默", showThis: function(){ console.log(this) } } myObj.showThis()
可以认为 JavaScript 引擎在执行 myObject.showThis()
时,将其转化为了 myObj.showThis.call(myObj)
使用对象来调用其内部的一个方法,该方法的 this 是指向对象本身的。
改造一下代码:this 又指向了 window 对象
var myObj = { name : "凯小默", showThis: function(){ this.name = "kaimo" console.log(this) } } var foo = myObj.showThis foo()
在全局环境中调用一个函数,函数内部的 this 指向的是全局变量 window。
通过一个对象来调用其内部的一个方法,该方法的执行上下文中的 this 指向对象本身。
3. 通过构造函数中设置
例子:
function CreateObj(){ this.name = "凯小默" } var myObj = new CreateObj()
当执行 new CreateObj()的时候,JavaScript 引擎做了如下四件事:
首先创建了一个空对象 tempObj
调用 CreateObj.call 方法,并将 tempObj 作为 call 方法的参数,这样当 CreateObj 的执行上下文创建时,它的 this 就指向了 tempObj 对象
执行 CreateObj 函数,此时的 CreateObj 函数执行上下文中的 this 指向了 tempObj 对象
最后返回 tempObj 对象
大致就是:
var tempObj = {} CreateObj.call(tempObj) return tempObj
更多 new 的知识点可以查看【new 运算符】
this 的设计缺陷以及应对方案
1. 嵌套函数中的 this 不会从外层函数中继承
例子:
var myObj = { name : "凯小默", showThis: function(){ console.log(this) function bar(){console.log(this)} bar() } } myObj.showThis()
解决方法一:声明一个变量用来保存 this,其本质就是把 this 体系转换为了作用域的体系
var self = this; function bar(){ self.name = "kaimo" }
解决方法二:使用 ES6 中的箭头函数来解决这个问题
因为 ES6 中的箭头函数并不会创建其自身的执行上下文,所以箭头函数中的 this 取决于它的外部函数。
var bar = ()=>{ this.name = "kaimo" console.log(this) }
2. 普通函数中的 this 默认指向全局对象 window
可以通过设置 JavaScript 的“严格模式”来解决。在严格模式下,默认执行一个函数,其函数的执行上下文中的 this 值是 undefined
注意点
当函数作为对象的方法调用时,函数中的 this 就是该对象
当函数被正常调用时,在严格模式下,this 值是 undefined,非严格模式下 this 指向的是全局对象 window
嵌套函数中的 this 不会继承外层函数的 this 值
箭头函数没有自己的执行上下文,所以箭头函数的 this 就是它外层函数的 this。