This:从执行上下文的角度来理解这个。
这在全局执行上下文中
让我们首先看看这在全局执行上下文中是什么。
可以在控制台输入console.log(this)在全局执行上下文中打印出这个,最后输出的是window对象。所以你可以得出结论,这在全局执行上下文中指向窗口对象。这也是This和scope链的唯一交集。作用域链的底部包含窗口对象,在全局执行上下文中也指向窗口对象。
这是在函数执行的上下文中
既然您知道全局对象中的这个对象指向窗口对象,那么让我们在函数执行的上下文中关注这个对象。或者先看看下面的代码:
函数foo() {
console . log(this);
}
foo();
复制代码
我们在foo函数中打印出这个值,当我们执行这段代码时,我们也打印出窗口对象,这意味着当一个函数被默认调用时,它的执行上下文中也指向窗口对象。你可能很好奇,但是你能在执行上下文中设置它指向其他对象吗?答案是肯定的。通常,在函数执行的上下文中有三种方法来设置该值。
1.由函数的调用方法设置。
可以通过函数的call方法设置函数执行上下文的这个点。比如下面这段代码,我们没有直接调用foo函数,而是调用了foo的call方法,并把bar对象作为call方法的参数。
让bar = {
我的名字:“名字1”,
测试1: 1,
};
函数foo() {
this.myName = " name2
}
foo.call(酒吧);
console . log(bar);
console.log(我的名字);
复制代码
执行这段代码,然后观察输出结果,可以发现foo函数内部这个已经指向了bar对象,因为通过打印bar对象,可以看到bar的myName属性从“name1”变成了“name2”,同时在全局执行上下文中打印myName,JavaScript引擎提示这个变量是未定义的。
实际上,除了call方法之外,您还可以使用bind和apply方法在函数执行的上下文中设置它,但是语法略有不同。
2.通过对象调用方法设置。
要在函数的执行上下文中更改这一点,除了函数的调用方法之外,还可以由对象调用,如下面的代码:
var myObj = {
姓名:“姓名”,
showThis: function () {
console . log(this);
},
};
myobj . show this();
复制代码
在这段代码中,我们定义了一个由name属性和showThis方法组成的myObj对象,然后通过myObj对象调用showThis方法。执行这段代码,可以看到这个值的最终输出指向myObj。
所以,你可以得出结论,用一个对象调用它内部的一个方法,方法的this指向对象本身。
其实你也可以认为,当JavaScript引擎执行myObject.showThis()时,它被转化为:
myObj.showThis.call(myObj)
接下来,让我们稍微改变一下调用方法,将showThis赋给一个全局对象,然后调用该对象。代码如下:
var myObj = {
名称:“时间”,
showThis: function () {
this.name = " bang
console . log(this);
},
};
var foo = myObj.showThis
foo();
复制代码
执行这段代码,你会发现这又指向了全局窗口对象。
所以通过比较以上两个例子,可以得出以下两个结论:
在全局环境中调用一个函数,这个函数内部指向全局变量窗口。
在对象内部调用一个方法,这个方法的执行上下文中的this指向对象本身。
3.通过在构造函数中设置
您可以像下面这样在构造函数中设置它,如下面的示例代码所示:
函数CreateObj() {
this.name = " time
}
var myObj = new create obj();
复制代码
在这段代码中,我们使用new来创建对象myObj。你知道构造函数CreateObj中的这个指向谁吗?
实际上,当执行new CreateObj()时,JavaScript引擎会做以下四件事:
首先,一个空对象tempObj已创建;
然后调用CreateObj.call方法,使用tempObj作为调用方法的参数,这样在创建CreateObj的执行上下文时,其this指向tempObj对象;
然后执行CreateObj函数,此时CreateObj函数的执行上下文中this指向tempObj对象;
最后,返回tempObj对象。
这样,我们通过new关键字构建了一个新对象,而这个在构造函数中实际上就是新对象本身。
设计缺陷及其解决方案
个人认为这不是一个好的设计,因为它的很多使用方法冲击了人的直觉,在使用过程中也有很多漏洞。让我们来看看这些设计缺陷。
1.嵌套函数中的这一点不会从外部函数中继承。
我认为这是一个严重的设计错误,也影响了很多开发者。
至于怎么解决?你可以在函数中声明一个变量self来保存它。当然,你也可以使用ES6中的箭头功能来解决这个问题。
2.这在普通函数中默认指向全局对象窗口。
如上所述,默认情况下调用一个函数,默认情况下,这个函数在其执行上下文中指向全局对象窗口。
但这种设计也是一个缺陷,因为在实际操作中,我们并不希望函数执行的上下文中这个默认指向全局对象,因为这样会打破数据边界,造成一些误操作。如果希望在函数执行的上下文中指向一个对象,最好的方法是通过call方法显示调用。
这个问题可以通过设置JavaScript的“严格模式”来解决。在严格模式下,默认执行一个函数,在其函数的执行上下文中this的值是未定义的,解决了上述问题。
摘要
审查以下内容:
首先,在使用这个的时候,为了避免坑,你要记住以下三点:
当一个函数作为一个对象的方法被调用时,函数中的这个就是对象;
正常调用函数时,在严格模式下,this的值是未定义的,在非严格模式下,this指向全局对象窗口;;
嵌套函数中的This不继承外部函数的这个值。
最后,我们还提到了箭头函数,因为箭头函数没有自己的执行上下文,所以箭头函数的this就是它的外部函数的this。