JS this详解

this的由来

javascript允许在函数体内,引用当前环境的其他变量

var fn=function(){
    console.log(x)
}

上面代码使用变量x,而变量x由当前的运行环境提供。
那么问题来了,函数可以在不同的运行环境下执行,所以需要一种机制,可以在函数体内内部获取当前的运行环境(context),所以this就出现了,它的作用就是在函数体内部,指代当前的运行环境。

this的几种模式

在我理解下,this分为一下几种情况:

  1. 方法调用模式下,this总是指向调用它所在方法的对象,this的指向与所在方法的调用位置有关,而与方法的声明位置无关(箭头函数特殊)。
  2. 函数调用下,this指向window,调用方法没有明确对象的时候,this指向window,,如setTimeout,匿名函数等。
  3. 构造函数调用模式下,this指向被构造的对象
  4. apply,call,bind调用模式下,this指向第一个参数。
  5. 箭头函数,在声明的时候绑定this,而非取决于调用位置,换句话说就是指向它的上一层。
  6. 严格模式下,如果this没有被执行环境(execution context)定义,那this是为undefined。

下面我们针对这几种情况,举例说明,并说明原理。

方法调用模式

        //声明位置
        var fn=function(){
            console.log(this.x)
        }    
        var x="2"
        var obj={
            x:"1",
            fn:fn
        }
        //调用位置
        obj.fn();//1
        //调用位置
        fn();//2

以上代码,可以看到,this指向调用它所在方法的对象,say方法在obj对象下,所以this指向obj,fn在window对象下,所以this指向window,也可以看出来,this和声明位置无关,和调用位置有关。

函数调用模式

        var x="2"
        //声明位置
        var fn=function(){
            console.log(this.x)
        }    
        //调用位置
        fn();//2

匿名函数,setTimeout:

         var that=this;
        (function(){
            console.log(this===that)//true
        })()
        setTimeout(() => {
            console.log(this===that)//true
        }, 0);

 可以看出以上所有情况,this指向window

call,apply,bind模式下

        var obj={
            name:'hty',
            getName:function(){
                console.log(this.name)
            }
        }
        var otherObj={
            name:'hml'
        }
        var name='upupup'
        obj.getName()//hty
        obj.getName.call();//upupup
        obj.getName.call(otherObj);//hml
        obj.getName.apply();//upupup
        obj.getName.apply(otherObj);//hml
        obj.getName.bind(this)();//upupup
        obj.getName.bind(otherObj)();//hml

 可以看出,call,apply,bind的this指向第一个参数,如果有朋友不太明白,可以看下,我上篇写的call,apply,bind的原理就明白了。

构造函数模式下

        var flag=undefined;    
        function Fn(){
            flag=this;
        }    
        var obj=new Fn()
        console.log(flag==obj)

其实,这个this指向obj,内部原理还是用apply把this指向obj的,在后续文章,我会写一个关于new的原理,大家有兴趣,可以关注下。

严格模式

        "use strict";
        var fn=function(){
            return this
        }    
        fn() ==undefined;//true

可以看出,在严格模式下,fn是被直接调用的,并没有没有被执行环境所定义,也就是说不是作为对象的属性或方法调用的(如window.fn())

箭头函数

        //声明位置
        var fn = (()=>{
            console.log(this.x)
        })  
        var x="2"
        var obj={
            x:"1",
            fn:fn
        }
        //调用位置
        obj.fn();//2
        //调用位置
        fn();//2

以上可以看出,箭头函数在定义时就绑定了this,而非取决与调用位置了,同样用call,apply,bind都无法更改this。

        var globalObject = this;
        var foo = (() => this);
        console.log(foo() === globalObject); // true
        var obj = {foo: foo};
        // 尝试使用call来设定this
        console.log(foo.call(obj) === globalObject); // true
        // 尝试使用bind来设定this
        foo = foo.bind(obj);
        console.log(foo() === globalObject); // true

  • 43
    点赞
  • 148
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值