JS—this指向问题

再写this学习内容之前,先补充一个小知识点:在函数中变量没有声明直接赋值后,这个变量会成为全局变量

外面是可以访问到函数内的值的。

什么是this?

this是 JavaScript 语言的一个关键字。它是函数运行时,在函数体内部自动生成的一个对象,只能在函数体内部使用。

那么,this的值是什么呢?函数的不同使用场合,this有不同的值。总的来说,this就是函数运行时所在的环境对象(重点理解这句话)。

this的用法

分四种情况详细讨论

情况一:纯粹的函数调用

var a = 2;
        function test() {
            console.log(this.a); // 2
        }
        test(); 

 这是函数的最通常用法,属于全局性调用,this指向的是全局对象window。如果严格模式,this为undefined。需要了解严格模式,可以戳这javascript严格模式

 请看下面这种情况
 

var a = 1;
        function test() {
            a=2;
            console.log(this.a); // 2
        }
        test();

这里的this依然指向window,但是值为什么是2?我在文章最上面做出了解释 ,函数体里面的a也是全局变量同名被覆盖。

情况二:作为对象方法的调用

 函数还可以作为某个对象的方法调用,this指向这个上级对象(这个上级对象一定是“亲爸爸”)。

var a = 1
        var b = {
            a: 2,
            fn: function () {
                console.log(a) //1
                console.log(this.a) //2
            }
        }
        b.fn()

注意a和this.a的区别:a会向外层作用域找,找到全局对象上的a(如果全局对象上没有就会报错) ,此时this指向对象b。

修改一下:

var a = 1;
        var b = {
            a: 2,
            c: {
                a:3,
                fn: function () {
                    console.log(this) // {a: 3, fn: ƒ}
                    console.log(this.a) //3
                }
            }

        }
        b.c.fn();

 b调用c,c调用fn,所以this指向直接调用这,也就是c,所以结果为3。

 下面再看:

 var a = 1
        var b = {
            a: 2,
            fn: function () {
                console.log(this.a) //1
            }
        }
        var fn1=b.fn//b对象将fn方法赋值给fn1变量,那么此时fn方法并没有被任何人调用,只是单纯的赋值。执行fn1方法之后,fn方法才算真正被调用
        fn1()

 这里只是将fn方法赋值给fn1变量,并没有执行。执行fn1时,fn方法才算调用执行,此时fn1是挂载再window对象上的,此时this指向window。

再看

var a = 1
var b = {
    a : 2,
    fn : function(){
        setTimeout(function() {
            console.log(this.a) //1
        },100)
    }
}
b.fn()

从上述中可以看到b.fn()里面执行了setTimeout函数,setTimeout内的this是指向了window对象,这是因为setTimeout()调用的代码运行在与所在函数完全分离的执行环境上。熟知EventLoop的人员应该明白,setTimeout函数其实调用的是浏览器提供的其他线程,当JS主线程走完之后,会调用任务队列的函数,也即是setTimeout函数,此时setTimeout是在window上调用的,那么this自然指向了window。不了解可以看浏览器的运行机制—3.浏览器的渲染进程

此时是否觉得:this指向就是那个对象调用函数,函数里面的this指向那个对象。

不急,继续往下看。 

情况三 作为构造函数调用

所谓构造函数,就是通过这个函数,可以生成一个新对象(object)。这时,this就指这个新对象。如果不使用new调用,则和普通函数一样。

function A() {
            this.a = 0
        }
        A.prototype = {
            a: 1,
            get() {
                console.log(this.a)
            }
        }
        var a = new A()
        console.log(a);//A
        a.get()//0

this指向a,a调用get方法,a对象上有a属性,值为0  

情况四 apply和call 调用

 apply和call函数都可以改变this指向。它的第一个参数就表示改变后的调用这个函数的对象。因此,此时this指的就是这第一个参数。


var x = 0;
function test() {
 console.log(this.x);
}

var obj = {};
obj.x = 1;
obj.m = test;
obj.m.apply() // 0

当apply函数的参数为空时,默认调用全局对象。因此,这时的运行结果为0,this指的是全局对象window。

箭头函数的this指向(ES6)

在前面,曾说过:this指向就是那个对象调用函数,函数里面的this指向那个对象(适用于es5的写法)

这里并不适用 ,箭头函数中的this指向是固定的,箭头函数根本没有自己的this,它只会从自己的作用域链的上一层继承this。正是因为它没有this,所以箭头函数也就不能用作构造函数,并且也就不能用call()、apply()、bind()这些方法去改变this的指向(改变无效,输出的仍是作用域链的上一层)。

var a = 1
var b = {
    a: 2,
    fn:()=>{
        console.log(this.a); //1
    }
}
b.fn()

箭头函数会继承作用域链中的上一层this指向,这里指向window对象。

 const obj = {
    a: function () {
        console.log(this)
    },
    b: {
        c: ()=>{
            console.log(this);
        },
        d:function(){
            return ()=>{
                console.log(this);
            }
        }
    }
}
obj.b.c() //window
obj.b.d()() //b
  • 执行obj.b.c(),因为c是箭头函数写法,所以this指向上层作用域链,作用域包括函数(局部)作用域和全局作用域。因为上层没有函数作用域,所以指向全局作用域window
  • 执行obj.b.d()(),相当于执行d返回的是箭头函数,所以里面的this指向上层作用域链,也就是d。因为d是es5写法,依据谁调用指向谁此时d中的this指向b。所以输出为b。

总的来说,this就是函数运行时所在的环境对象(重点理解这句话)。

参考文章:

javascript中的this指向 - 简书

JavaScript 的 this 原理 - 阮一峰的网络日志


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值