彻底搞懂Js中this指向,Js中this通俗易懂讲解

静态作用域与动态作用域

Javascript 采用的是词法作用域(静态作用域),也就是说函数的作用域(可以访问到的变量)在函数定义的时候就确定了。

与之相反的是动态作用域,即函数的作用域在函数调用时才确定。

下边的代码可以很好的说明Js是一个静态作用域语言,如果函数的作用域是在运行时确定的话,运行foo函数时, 从 foo 函数内部没有找到局部变量 value后,会从调用函数的作用域,也就是 bar 函数内部查找 value 变量,那么会打印 2。

Js引擎底层的实现为:函数在定义的时候,会把其所属环境(全局环境)的变量生成一个变量对象放入到函数的scope属性,调用函数时,会生成执行环境并创建一个作用域链,即先把函数scope属性中的变量对象放到作用域链中,再利用函数参数和内部变量生成一个活动对象,并放入作用域链的前端。

var value = 1;
function foo() {
    console.log(value);
}
function bar() {
    var value = 2;
    foo();
}
 
bar(); // 1  

this 关键字是 JS 中的动态作用域机制,是为了在 JS 中加入动态作用域而做的努力,因为this指向的对象是在函数调用时绑定的。

在任何函数中,this的指向都不是静态的(static)。它总是在你调用一个函数,但尚未执行函数内部代码前被指定。即this的指向与函数被调用的方式(语法)有关

下边的代码可以很好的说明这一点

var o = {
    a: 10,
    b: {
        fn: function() {
            console.log(this);
        }
    }
}
o.b.fn(); //指向o中的对象b
var j = o.b.fn;
j(); //指向全局对象

上述代码的执行结果为
在这里插入图片描述

可以看到,函数内部的this指向和其调用方式有关,和函数本身的定义方式无关

绑定规则

this对象有四种绑定规则,优先级有高到低分别如下:

  1. 构造绑定:通过new关键字调用构建函数。此时会生成一个实例对象,并且this指向这个实例对象。这种方式实际上是new的底层实现修改了this指向

    var savedThis;
    function Constr() {
        // 保存构造函数中的this
        savedThis = this;
    }
    // 通过new关键字执行构造函数
    var inst = new Constr();
    
    // 构造函数中的this指向的就是新创建的对象实例inst
    console.log(savedThis === inst); // true
    
  2. 显式绑定:apply()、call()、bind()三个方法改变函数的调用对象(this对象)

  3. 隐式绑定:某个上下文对象中调用函数。比如使用 obj.foo() 这样的语法来调用函数,函数 foo 中的 this 绑定到 obj 对象

    //对象的方法
    var o = {
        a:10,
        b:{
            fn:function(){
                console.log(this.a); //undefined,this指向b对象
            }
        }
    }
    o.b.fn();
    
    // 事件处理函数
    function doAlert() { 
        alert(this); 
    } 
    doAlert(); // 全局对象
    var myElem = document.getElementById('test'); 
    myElem.onclick = doAlert; 
    myElem.onclick(); // 指向myElem元素
    
  4. 默认绑定:不符合上述三种情况,在一个函数中使用了 this,但是没有为 this 绑定对象。这种情况下,严格模式this绑定到undefined,非严格模式this绑定到全局对象(Node 环境中的 global,浏览器环境中的window)

    var o = {
        a:10,
        b:{
            a:12,
            fn:function(){
                console.log(this.a); //undefined
                console.log(this); //window
            }
        }
    }
    var j = o.b.fn;
    j();
    

对于3、4两点,可以用一个简单的规则去判断

当一个函数被调用时,应该立马看()左边的部分。

  • 如果()左边是一个引用(reference),那么函数的this指向这个引用所属的对象(隐式绑定)
  • 否则this指向的就是全局对象或者undefined(默认绑定)

上边代码中fn是一个引用,属于b这个对象,所以this指向b;j不是引用,所以this指向window

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值