JS 作用链,箭头函数 this 取值

  通俗地讲,当声明一个函数时,局部作用域一级一级向上包起来,就是作用域链。

  1.当执行函数时,总是先从函数内部找寻局部变量。

  2.如果内部找不到(函数的局部作用域没有),则会向创建函数的作用域(声明函数的作用域)寻找,依次向上。

  比如在闭包中可以直接使用外部函数内定义的变量,这也是闭包的本质:闭包函数的定义基于外部函数的执行。

function outer(){
    let outerSay= 'i am outer';
    function inner(){
        console.log(outerSay);
    }
    return inner;
}

outer()();

  运行结果:

  闭包函数访问到了外层函数定义的变量。也就是声明闭包函数时的外层作用域中的变量。

  以另一个例子作对比:

var name = "windowName";

function f1() {
    var name = "f1Name";
    console.log("f1 say : ",name);
    f0();
}


function f0() {
    console.log("f0 say :",name);
}

f1();

  运行结果:

  对于 f1 而言,在其内部声明了 name 变量,所以首先会找到函数内部定义的变量。而对 f0 而言,函数内部没有定义内部变量,需要从函数定义时的外层环境寻找,也就是全局变量 name 。而不是 f1 中定义的局部变量内部, f1 的环境是调用 f0 的外部环境,而不是声明 f0 的外部环境。

  相对于变量的取值取决于函数定义时的环境,this 的取值正相反,取决于函数运行时的上下文。this是使用call方法调用函数时传递的第一个参数,它可以在函数调用时修改,在函数没有调用的时候,this的值是无法确定。对于函数的调用:

const obj = {
    name: 'Jerry',
    greet: function() {
        console.log(this.name)
    }
}
obj.greet()  //第一种调用方法
obj.greet.call(obj) //第二种调用方法

  对于函数的调用,第一种方式只是第二种方式的语法糖。函数在调用时需要传入调用对象。当使用第一种方法调用普通函数时,有以下规则:

  1. 一般方法中,this代指全局对象 window

  2. 作为对象方法调用,this代指当前对象

  3. 作为构造函数调用,this 指代new 出的对象()

  4. 调用方法的apply和call方法,可以改变函数的调用对象/作用域

  而对于箭头函数来说,箭头函数本身是没有 this 的,call 传入的第一个参数会被忽略。在严格模式下,this 为 undfined,否则为 window。箭头函数的 this 取决于执行上下文中的 this 。当作为闭包函数时,执行上下文中有外层函数的 this ,在箭头函数中使用 this 会直接使用外层函数的 this。闭包函数的定义取决于外部函数的执行。

  其他情况下箭头函数的 this 均指向 undfined(严格模式)或 window。

  对于普通函数来说,做为闭包函数时,其 this 指向的是 window 对象。因为其并没有被作为对象的方法调用,call 方法传入的第一个方法为 window 。

  可以说闭包函数的 this 是一个特例,其忽略了 call 中传入的第一个参数,不可人为指定 this,this 只会从执行上下文中去寻找。

  举个例子:

var name = 'windowName';
var obj = {
    name: 'outerName',
    inner0: function() { console.log('inner0 say : ', this.name); },
    inner1: () => { console.log('inner1 say : ', this.name) }
}
obj.inner0();
obj.inner1();

var name = 'windowName';
var obj = {
    name: 'outerName',
    inner0: function() {
        setTimeout(function() {
            console.log('inner0 say : ', this.name);
        }, 10)

    },
    inner1: function() {
        setTimeout(() => {
            console.log('inner1 say : ', this.name);
        }, 10)
    }
}
obj.inner0();
obj.inner1();

  

  

 

 

 

 

posted @ 2020-12-27 18:50  牛有肉  阅读(354)  评论(0编辑  收藏  举报