JS中this到底指向谁

看了很多地方,在以前学JAVA的时候,就对this没怎么学习了解,仅仅知道它经常是this这个类的实例。但JS里的this根据不同情况有好几种指向,就不能打马虎眼得仔细学习一下了。

this是在函数调用的时候就已经确定了,它是根据不同的调用方式指向不同的地方。
它在“调用”这个行为的同时,已经确定好了,并不是执行到它的时候它才去查找的。

有四种函数调用方法
1.函数调用模式 Function Invocation Pattern
用fun()直接调用的时候,this指向的是全局变量Global,在浏览器中就是window对象。(如果是严格模式this就是undefined)

2.方法调用模式 Method Invocation Pattern
fun.a()fun[a]作为属性来调用的时候,这个’['或 '.'之前的fun就是this所指向的对象。

3.构造器调用模式 Constructor Pattern
经常用的new fun()就是,这里的this指向new fun()返回的对象。

4.Apply调用模式 Apply Pattern
像fun.call(),fun.bind(),fun.apply()等方法,一般传入的第一个参数就是函数内this所指向的对象,如果传入的是null或undefined,则this指向global。

一些特殊情况

1.回调函数

一旦跟回调函数扯上关系,就会觉得有点复杂
这里有个例子

var user = {
    data: [
        {name: "hahaha"}
    ],
    clickHandler: function(event) {
        console.log(this.data[0].name);
    }
}
// 下面这行会输出 undefined 因为 button 对象没有 data 属性
$("button").click(user.clickHandler);

这里的$("button")是一个对象,我们把user.clickHandler 作为一个回调函数传入它的 click() 方法,这时候user.clickHandler方法里面的 this 指向的就不是 user 对象了。
this 是定义在 user.clickHandler 方法里的,它现在指向调用了 user.clickHandler 的对象。而那个对象就是 button 对象,所以user.clickHandler 将会在 button 对象的 click 方法中被执行,而$("button")里没有data属性,自然就是输出undefined了。

解决办法:
如果想特定的指向user,可以用call,bind,apply等方法手动绑定。

2.闭包调用

在使用闭包的时候,要注意闭包不能直接通过使用 this 来访问外层函数的this变量,因为 this变量只有当前函数本身可以访问,而其内层函数是访问不到的

var user = {
    tournament: "The Masters",
    data: [
        {name: "hahaha"}
    ],

    clickHandler: function() {
        // 在这里使用 this.data 是可以的,因为 this 指向 user 对象,而 data 是 user 对象的一个属性
        this.data.forEach(function() {
            // 但是在内层匿名函数中(就是我们传给 forEach 方法的函数),this 就不再指向 user 对象了
            console.log(this); //全局对象
            console.log(this.tournament);//输出undefined
        });
}
}
user.clickHandler();

匿名函数内部的this不能获取外层函数this的值,尽管看起来外层的this指向user,就好像user又调用了这个函数,但内部的this并没有指向外层this,而是由于未明确定义所以指向了全局对象上。(如果使用严格模式,this就是undefined)

解决办法:
提前把this变量存起来:var that = this;通常我们是用that

var user = {
    tournament: "The Masters",
    data: [
        {name: "hahaha"}
    ],

    clickHandler: function() {
         // 在this还指向 user 对象时,把它的值保存到另一个变量中
        var that=this;
          // 在这里使用 this.data 是可以的,因为 this 指向 user 对象,而 data 是 user 对象的一个属性
        this.data.forEach(function() {
            //输出的是user对象的属性了
            console.log(that); //全局对象
            console.log(that.tournament);//undefined
        });
}
}
user.clickHandler();

很多人用的是that,但是我们也可以更规范的写成theUserObj,这样可以让我们在使用的时候,能清楚知道他是个什么变量。

3.this方法赋给变量调用

当我们把一个对象里使用了this的方法赋给一个变量调用时,它指向的是全局对象而不是上一级
看一下例子就理解了(由于是node.js,无法直接在最外层定义全局变量,所以这里我采用了不声明直接赋值的方法定义全局变量,如果是浏览器的JS,就可以直接在函数外var data=[…]定义全局变量了)


data={name: "全局变量"};

var user = {
    tournament: "The Masters",
    data: [
        {name: "hahaha"}
    ],
	
    show:function() {
        console.log(this.data);
    }
}
var showUserData = user.show;
// 当我们执行 showUserData 函数的时候,打印在 console 中的值来自于全局的 data 数组,而不是 user 对象的 data 属性
showUserData();

我的理解是赋值的时候把要执行的函数赋给了变量,再调用的时候就相当于全局对象直接调用那个方法了
另外如果是严格模式,指向的就不是全局对象了
解决办法:
如果我们依旧想让this指向user而不是全局对象,可以用bind绑定到user对象上

var showUserData = user.show.bind(user);
showUserData();

注意如果用的是call或apply,那它在赋值之前就已经执行了方法了,而没有返回值的函数赋给showUserData的值是undefined。所以这里最好用bind。

4.当this碰到return

当函数有返回值的时候,this的指向又会产生变化

//1.返回对象
function fn1()  
{  
    this.user = 'hahaha';  
    return {user:xixixi};  
}
//2.返回函数对象
function fn2()  
{  
    this.user = 'hahaha';  
    return function(){};  
}//3.返回基本类型(数字,字符,布尔型,undefined等)
function fn3()  
{  
    this.user = 'hahaha';  
    return 1;
}//4.无返回值
function fn4()  
{  
    this.user = 'hahaha';  
    return;  
}
//分别创建对象
var fn1 = new fn1();  
var fn2 = new fn2();  
var fn3 = new fn3();  
var fn4 = new fn4();  
//调用
console.log(fn1.user); //xixixi
console.log(fn2.user); //undefined
console.log(fn3.user); //hahaha
console.log(fn4.user); //hahaha

发现区别了吗,当返回的是对象类型的时候,this指向的就是那个返回的对象。而如果是基本类型或空或无返回值的时候就还是指向函数的实例
另外虽然null也是对象,但返回它的时候指向的还是函数实例,因为它比较特殊

总结

总的来说,this还是更贴近指向调用它的上一级对象,这种情况比较多
严格模式下,未定义的this都是undefined,而非严格模式下一般指向全局对象

参考:
https://code.mforever78.com/translation/2015/05/19/understand-javascripts-this-with-clarity-and-master-it/#javascript-this-

https://www.cnblogs.com/pssp/p/5216085.html

猜你喜欢

转载自blog.csdn.net/weixin_38958597/article/details/85304240