彻底搞懂浏览器和node.js中的this指向问题!
彻底搞懂JavaScript中的this指向问题!
之前遇到this指向问题总是一知半解,今天花了一些时间深入了解了一下,接下来我会把我的理解通俗易懂的讲出来,希望以后大家都能明白this指向。
首先搞明白this的定义:this为代码运行时所处的环境!本质上所有的函数都是通过对象调用,所以最终是谁调用的函数,函数内部的this就是谁。
this在浏览器中的指向
node.js中大部分的指向和普通运行环境一致,所以此处先说明大部分情况,最后node.js差异部分单独说明。
1.普通函数的this指向他的调用者
let name='window'
let obj={
name:'obj'
getName:function()
{
console.log('getName:',this.name)
}
}
obj.getName() //getName:obj
2.箭头函数的this:箭头函数没有自己的this,所以指向定义时所在环境
var name='window'
let obj={
name:'obj',
getName:()=>
{
console.log('getName:',this.name)
}
}
obj.getName() //getName:window
可以看到此处getName声明为箭头函数,函数体中的this定义时的调用者环境,即obj所处环境的this(window对象),可以简单理解为:对比普通函数来说,箭头函数指向他外层的this(普通函数的this的外一层this)。
3.定时任务,setTimeout,无论是否为箭头函数,this都指向的是window,因为定时任务是浏览器调用的,所以指向最顶层的window对象。
let name='window'
setTimeout(function() {
console.log('getName:',this.name) //getName:window
}, 200);
let name='window'
setTimeout(()=> {
console.log('getName:',this.name) //getName:window
}, 200);
4.构造函数的this指向他的构造对象
function user()
{
this.name='name'
this.id=00000000
}
let lucy=new user();
console.log('name:',this) //name: user {name: 'name', id: 00000000}
值得注意的一点是:如果构造函数返回体中return非对象类型,则构造函数创建的实例对象不变,否则会发生改变
function user()
{
this.name='name'
this.id=00000000
return 1
}
let lucy=new user();
console.log('name:',lucy) //name: user {name: 'name', id: 00000000}
function user()
{
this.name='name'
this.id=00000000
return {}
}
let lucy=new user();
console.log('name:',lucy) //name: {}
this在node.js中的指向
我们知道,在node.js中全局对象为global对象,所以我们理所当然的认为node只是把浏览器中的全局对象windows替换成了global对象,所以我们运行以下代码
global.name = 'node.js'
function getName(){
console.log(this.name); //输出“node.js”
}
getName()
结果确实如我们所料,跟windows中的预期一样,但是真的是看起来这么简单吗?
但是答案是:node.js中其实不是单单把windows替换成global这么简单。
如果我们运行如下代码会发现:
console.log(this); //输出 {}
this.name = 'test'
console.log(this === global); //输出 false
function test(){
console.log(this === global); //输出 true
console.log(this.name); //输出 undefined
}
test();
在本来应该相等的第三行却不相等,第六行也没有得到我们想要的name字段!
也就是说,最外层的this不等于global,但是test函数的this指向了global,所以结论是第二行的this也就是最外层的this并不指向global,而是指向了{}这个对象。
所以我们得到最终的结论:
1.Node在执行js文件中的代码的时候,并不是放在全局环境中执行的。而是把js文件外面又包了一层成“模块”(module.exports),再把这个“模块”放到了全局变量中执行。所以,最外层的this,指的是包含这个js文件的“模块”。
2.Node中的全局对象是global,但是不在最外层,当调用函数时,函数中的this指向的是global。
3.如果想获取全局变量中的this,可以使用globalThis属性。