说明
浏览器工作原理与实践专栏学习笔记
为什么需要 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。