思考题: 以下这段代码打印输出是什么?
let bar = {
myName: "www.cctalk.com",
printName: function () {
console.log(myName)
}
}
function foo() {
let myName = "沪江教育"
return bar.printName
}
let myName = "享互"
let _printName = foo()
_printName()
bar.printName()
this 介绍:
this 是和执行上下文绑定的,执行上下文主要分为三种——全局执行上下文、函数执行上下文和 eval 执行上下文,所以对应的 this 也只有这三种——全局执行上下文中的 this、函数中的 this 和 eval 中的 this。
由于eval 执行上下文使用不多,故先了解:全局执行上下文中的 this、函数中的 this:
一、 全局执行上下文中的 this:
全局执行上下文中的 this 是指向 window 对象的。
可以在全局环境下使用 console.log(this) 进行验证,确认 this 是否打印输出 window 对象
二、 函数中的 this
function foo1 (){
console.log(this)
}
foo1()
在 foo 函数内部打印出来 this 值,执行这段代码,打印出来的也是 window 对象,
这说明在默认情况下调用一个函数,其执行上下文中的 this 也是指向 window 对象的。
那能不能设置执行上下文中的 this 来指向其他对象呢?
答案是肯定的。通常情况下,有下面三种方式来设置函数执行上下文中的 this 值。
- 通过函数的 call 方法设置, 其实除了 call 方法,你还可以使用 bind 和 apply 方法来设置函数执行上下文中的 this
let bar11 = {
myName : "享互",
test1 : 1
}
function foo11(){
this.myName = "沪江"
}
foo11.call(bar11)
console.log(bar11) // bar11 = { myName: '沪江', test1: 1 }
console.log(myName) // undefined
- 通过对象调用方法设置
使用对象来调用其内部的一个方法,该方法的 this 是指向对象本身的。
let myObj = {
name : "沪江",
showThis: function(){
console.log(this)
}
}
myObj.showThis()
可以认为 JavaScript 引擎在执行 myObj.showThis()时,将其转化为了
myObj.showThis.call(myObj)
稍微改变下调用方式,把 showThis 赋给一个全局对象,然后再调用该对象,代码如下所示:
let myObj111 = {
name : "极客时间",
showThis: function(){
this.name = "极客邦"
console.log(this)
}
}
let foo111 = myObj111.showThis
foo111()
结论:
通过一个对象来调用其内部的一个方法,该方法的执行上下文中的 this 指向对象本身。 在全局环境中调用一个函数,函数内部的 this 指向的是全局变量 window。
- 通过构造函数中设置
function CreateObject(){
this.name = "极客时间"
}
let myObject = new CreateObject()
其实,当执行 new CreateObject() 的时候,JavaScript 引擎做了如下四件事:
1、首先创建了一个空对象 tempObj;
2、接着调用 CreateObject.call 方法,并将 tempObj 作为 call 方法的参数,这样当 CreateObject 的执行上下文创建时,它的 this 就指向了 tempObj 对象;
3、然后执行 CreateObject 函数,此时的 CreateObject 函数执行上下文中的 this 指向了 tempObj 对象;
4、最后返回 tempObj 对象。
let myObject1 = (function () {
let tempObj = {}
CreateObject.call(tempObj)
return tempObj
})()
this 的设计缺陷以及应对方案:
一、嵌套函数中的 this 不会从外层函数中继承
函数 bar 中的 this 指向的是全局 window 对象,而函数 showThis 中的 this 指向的是 myObj1111 对象。
let myObj2 = {
name : "沪江",
showThis: function(){
console.log(this)
function bar(){
console.log(this)
}
bar()
}
}
myObj2.showThis()
解决方法:1、声明一个变量 self 用来保存 this
这个方法的的本质是把 this 体系转换为了作用域的体系。
let myObj3 = {
name : "沪江",
showThis: function(){
console.log(this)
var self = this
function bar(){
self.name = "享互"
}
bar()
}
}
myObj3.showThis()
console.log(myObj3.name)
console.log(window.name)
解决方法:2、使用 ES6 中的箭头函数来解决这个问题
因为 ES6 中的箭头函数并不会创建其自身的执行上下文,所以箭头函数中的 this 取决于它的外部函数。
let myObj4 = {
name : "极客时间",
showThis: function(){
console.log(this)
var bar = ()=>{
this.name = "极客邦"
console.log(this)
}
bar()
}
}
myObj4.showThis()
console.log(myObj4.name)
console.log(window.name)
二、普通函数中的 this 默认指向全局对象 window
在默认情况下调用一个函数,其执行上下文中的 this 是默认指向全局对象 window 的。
不过这个设计也是一种缺陷,因为在实际工作中,我们并不希望函数执行上下文中的 this 默认指向全局对象,因为这样会打破数据的边界,造成一些误操作。
如果要让函数执行上下文中的 this 指向某个对象,最好的方式是通过 call 方法来显示调用。
这个问题可以通过设置 JavaScript 的“严格模式”来解决。在严格模式下,默认执行一个函数,其函数的执行上下文中的 this 值是 undefined,这就解决上面的问题了。
总结
首先,在使用 this 时,为了避坑,要谨记以下三点:
1、当函数作为对象的方法调用时,函数中的 this 就是该对象;
2、当函数被正常调用时,在严格模式下,this 值是 undefined,非严格模式下 this 指向的是全局对象 window;
3、嵌套函数中的 this 不会继承外层函数的 this 值。
网友评论