this指向看完就忘?那是你没理解深透!

219 阅读3分钟

我们都知道this关键字是JavaScript中非常重要的机制,面试也经常问到,于是内卷阅读相关this讲解文档,但是看的时候能理解,看完过一段时间就全忘了,如果你也有这样的问题,那么就继续看下去。

我们来看这么一道题:

var name = '轩小浅'var a = {
    name: '默认用户123',
    say: function () {
        console.log(this.name);
    }
}
​
var fun = a.say
fun()   // 此处会输出
a.say()  // 此处会输出var b = {
    name: '这个人很懒没有名字',
    say: function (fun) {
        fun()
    }
}
​
b.say(a.say)  // 此处会输出
b.say = a.say
b.say()  // 此处会输出

上面代码是比较基础的this指向相关题,如果你还是不能说出正确答案,请务必花5分钟时间看完这篇文章

我们先从最基础的看起:

function fun(name) {
    console.log(name);  // 轩小浅
}
​
fun('轩小浅')

你可能会问这不是很简单的函数调用吗?其实函数即对象,有对象就有方法

function fun(name) {
    console.log(name);  // 轩小浅
}
​
fun.call(window,'轩小浅')

第一种调用其实是第二种调用的简写,先记住这个我们接着往下看

函数作为对象的方法被调用时,谁调用我,我就指向谁

var obj = {
    name:'轩小浅',
    fun:function (hobby) {
        console.log(`我的名字叫${this.name},我的兴趣爱好是${hobby}`);
    }
}
​
obj.fun('下棋')   // 等价于obj.fun.call(obj,'下棋')

我们将上面改成这样:

var name = '默认用户123'var obj = {
    name:'轩小浅',
    fun:function (hobby) {
        console.log(`我的名字叫${this.name},我的兴趣爱好是${hobby}`);
    }
}
​
var run = obj.fun
run('乒乓球')

可能看到这里你就迷糊了,但是你忽略倒数第二行代码直接看最后一行你就会发现这不就是我们一开始说到的函数调用吗?是的,这里最后一行代码等价于 fun.call(window),打印结果是默认用户123

看到这里,你现在再回去看我们一开始出的题目就会发现so easy

var name = '轩小浅'var a = {
    name: '默认用户123',
    say: function () {
        console.log(this.name);
    }
}
​
var fun = a.say
fun()   // fun.call(window)     log:轩小浅
a.say() // a.say.call(a)    log:默认用户123var b = {
    name: '这个人很懒没有名字',
    say: function (fun) {
        fun()   // flag: 调用的地方在这里,等价于 fun.call(window)    
    }
}
​
b.say(a.say)    // flag: 这里直接看调用的地方     log:轩小浅
b.say = a.say
b.say()     // b.say.call(b)    log:这个人很懒没有名字

是不是非常简单?小技巧:只要是通过xxx()大括号直接调用的this指向一律为window

箭头函数的this指向

  1. 箭头函数中的this是在定义函数的时候绑定,而不是在执行的时候绑定

    例如:

    var name = '轩小浅'var obj = {
        name: '默认用户123'
    }
    ​
    ​
    var fun = () => {
        console.log(this.name);
    }
    ​
    ​
    fun()   // 轩小浅fun.call(obj)   // 无效,打印结果也是轩小浅
    
  2. 箭头函数中this执行很固定,并不是因为箭头函数内部有绑定this的机制,实际原因是因为箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。

    例如:

    var name = '轩小浅'var obj = {
        name: '默认用户123',
        fun:()=>{
            console.log(this.name);
        }
    }
    ​
    ​
    obj.fun()   // 轩小浅
    

    你是不是以为它会打印默认用户123?那么恭喜你,你有认真在看,只是被误解了。

    var name = '轩小浅'// 这里才是外层代码块var obj = { 
        // 这是fun箭头函数的内层代码块
        name: '默认用户123',
        fun:() => console.log(this.name)    // 这是一个函数表达式
    }
    ​
    ​
    obj.fun()   // 轩小浅
    

我们来做这么一道题

var obj = {
    name:'轩小浅',
    fun:function () {
        var a = this.name;  
        console.log(a); // 轩小浅
​
        var run = () => console.log(this.name);
​
        return run()
    }
}
​
obj.fun()   // obj.fun.call(obj)    log:轩小浅

关于let和const声明的变量不在window上

看这段代码

let name = '默认用户123'    // 注意这里是let声明而不是var声明var obj = {
    name:'轩小浅',
    fun:function (hobby) {
        console.log(`我的名字叫${this.name},我的兴趣爱好是${hobby}`);
    }
}
​
var run = obj.fun
run('乒乓球')  // 我的名字叫,我的兴趣爱好是乒乓球

ES6规定,var命令与function命令声明的全局变量,依旧是顶层对象的属性,但let命令,const命令、 class命令声明的全局变量,不属于顶层的属性。

let a1 = 1;
const a2 = 12;
var a3 = 123;
debugger

JavaScript的作用域为:

image.png