var bar = {
myName:"a",
printName: function () {
console.log(myName)
}
}
bar.printName()
// 在js中没有办法像c++,那样可以直接在方法里面访问成员属性。作用域链不支持,所以又搞出了一套this的机制。
作用域链和this是完全两套不同的系统不要搞混了。 他们之间基本上没有任何联系。
看一下执行上下文的结构图 上下文outer相关的文章 zhuanlan.zhihu.com/p/302840261
变量环境(outer) 词法环境
this 可以看到this的是执行上下文绑定的
因为this是执行上下文绑定,执行上下文有三种对应的this就有三种 全局this、函数this、eval this。eval用的比较少一些所以就不介绍了着重聊聊 全局上下文this和函数this.
全局执行上下文this?
你可以在控制台中输入console.log(this)来打印出来全局执行上下文中的this,最终输出的是window
对象。所以你可以得出这样一个结论:全局执行上下文中的this是指向window对象的。这也是this和作用域链的唯一交点,作用域链的最底端包含了window对象,全局执行上下文中的this也是指向window对象
函数执行上下文this?
function foo(){
console.log(this)
}
foo()
// 我们在foo函数内部打印出来this值,执行这段代码,打印出来的也是window对象,这说明在默认情况下调用一个函数,其执行上下文中的this也是指向window对象的。
改变this的指向
1.通过函数的call方法设置 2.bind 3.apply 4.通过对象方法调用xxx.xxx(); 使用对象来调用其内部的一个方法,该方法的this是指向对象本身的 xxx.xxx() 可以理解为 xxx.xxx.call(xxx);
var myObj = {
name : "极客时间",
showThis: function(){
this.name = "极客邦"
console.log(this)
}
}
var foo = myObj.showThis
foo()
// myObj.showThis给到了foo foo 是在全局执行的所以this被指向了window,可以理解 foo.call(window);
在全局环境中调用一个函数,函数内部的this指向的是全局变量window
通过一个对象来调用其内部的一个方法,该方法的执行上下文中的this指向对象本身
5.通过构函数设置this
function a(){this.a = 1};
var b = new a();
// new xx 首先创建了一个空对象tempObj;
// 接着调用a.call方法,并将tempObj作为call方法的参数,这样当a的执行上下文创建时,它的this就指向了tempObj对象;
// 然后执行a函数,此时的a函数执行上下文中的this指向了tempObj对象;
// 最后返回tempObj对象
// 拆分流程
var tempObj = {};
a.call(tempObj)
return tempObj;
这样,我们就通过new关键字构建好了一个新对象,并且构造函数中的this其实就是新对象本身
this的设计缺陷以及应对方案
1.嵌套函数中的this不会从外层函数中继承
var myObj = {
name : "极客时间",
showThis: function(){
console.log(this)
function bar(){console.log(this)} // 指向了window
bar()
}
}
// 会发现函数bar中的this指向的是全局window对象,而函数showThis中的this指向的是myObj对象函数
// 解决方案上下文存一个_self=this 或者直接箭头函数搞定。
// ES6中的箭头函数并不会创建上下文 所以它的this就是外部的集成过来的。
通过上面的讲解,你现在应该知道了this没有作用域的限制,这点和变量不一样,所以嵌套函数不会从调用它的函数中继承this,这样会造成很多不符合直觉的代码。要解决这个问题,你可以有两种思路。
第一种是把this保存为一个self变量,再利用变量的作用域机制传递给嵌套函数
第二种是继续使用this,但是要把嵌套函数改为箭头函数,因为箭头函数没有自己的执行上下文,所以它会继承调用函数中的this。
普通函数this指向window 可以使用js中写入"use strict" 来阻断 this指向window这个时候this就是undefined.