【前端】深入理解 JavaScript 箭头函数的 `this` 指向

06-01 1423阅读

kimi代写

在 JavaScript 的开发中,this 的指向一直是让许多开发者感到困惑的地方。尤其是当涉及到箭头函数时,其 this 的行为与普通函数大不相同。本文将通过一个具体的例子,深入探讨箭头函数的 this 指向机制,帮助你更好地理解这一特性。

问题引入

最近在调试一段代码时,我遇到了一个有趣的现象。代码如下:

var b = 1;
function a() {
    let b = 2;
    return () => {
        return () => {
            console.log(this.b);
        };
    };
}
console.log(a()()());

运行这段代码后,输出结果是:

undefined
undefined

这个结果让我感到困惑:为什么箭头函数的 this 不是指向 a 函数的 this,而是指向全局上下文的 window 呢?接下来,我们将逐步分析这个问题。

箭头函数的 this 捕获机制

在 JavaScript 中,箭头函数和普通函数在 this 的处理上有很大的不同:

普通函数的 this

普通函数的 this 是动态绑定的,取决于函数的调用方式。常见的调用方式包括:

  • 作为方法调用:this 指向调用它的对象。
    const obj = {
        name: "Kimi",
        greet: function() {
            console.log(this.name); // 输出 "Kimi"
        }
    };
    obj.greet();
    
  • 作为普通函数调用:在非严格模式下,this 指向全局对象(window),在严格模式下,this 是 undefined。
    function greet() {
        console.log(this); // 在非严格模式下输出 `window`,在严格模式下输出 `undefined`
    }
    greet();
    
  • 通过 call、apply 或 bind 调用:this 可以被显式绑定到指定的对象。
    const obj = { name: "Kimi" };
    function greet() {
        console.log(this.name);
    }
    greet.call(obj); // 输出 "Kimi"
    

    箭头函数的 this

    箭头函数没有自己的 this,它会捕获其定义时所在上下文的 this 值。换句话说,箭头函数的 this 是在其定义时就已经确定的,而不是在调用时动态绑定的。

    代码分析

    我们再来看之前的代码:

    var b = 1;
    function a() {
        let b = 2;
        return () => {
            return () => {
                console.log(this.b);
            };
        };
    }
    console.log(a()()());
    

    逐层分析

    1. 函数 a 的定义和执行:

      • a 是一个普通函数,它的 this 在调用时会根据调用方式动态绑定。
      • 当你调用 a() 时,a 是作为普通函数调用的。在非严格模式下,this 指向全局对象 window;在严格模式下,this 是 undefined。
      • 第一个箭头函数:

        • a 返回了一个箭头函数:
          () => {
              return () => {
                  console.log(this.b);
              };
          }
          
        • 这个箭头函数捕获了其定义时所在上下文的 this。由于它定义在 a 函数内部,而 a 的 this 是全局上下文的 this,因此这个箭头函数的 this 也是全局上下文的 this。
        • 第二个箭头函数:

          • 第一个箭头函数返回了另一个箭头函数:
            () => {
                console.log(this.b);
            }
            
          • 这个箭头函数同样捕获了其定义时所在上下文的 this,即全局上下文的 this。

    关键点

    • 箭头函数的 this 是在其定义时捕获的,而不是在调用时动态绑定的。
    • 在你的代码中,两个箭头函数都定义在 a 函数内部,而 a 的 this 是全局上下文的 this,因此两个箭头函数的 this 都是全局上下文的 this。

      为什么不是 a 的 this?

      箭头函数的 this 捕获机制决定了它不会绑定到其直接包含它的函数(如 a),而是绑定到其定义时所在上下文的 this。在你的代码中,a 函数的 this 是全局上下文的 this,因此箭头函数捕获的也是全局上下文的 this。

      总结

      • 普通函数的 this 是动态绑定的,取决于函数的调用方式。
      • 箭头函数的 this 是在其定义时捕获的,不会绑定到其直接包含它的函数,而是绑定到其定义时所在上下文的 this。
      • 在你的代码中,箭头函数的 this 捕获了全局上下文的 this,而不是 a 函数的 this。

        希望这篇文章能帮助你更好地理解箭头函数的 this 捕获机制。如果你还有其他疑问,欢迎在评论区留言,我们一起探讨!


        作者简介:我是 Kimi,一名热爱技术的开发者。如果你喜欢这篇文章,别忘了点赞和关注哦!

        更多

        【前端】深入理解 JavaScript 箭头函数的 `this` 指向

        特殊的this指向:

        除了上面几种this指向的规则之外,还有一些特殊的情况,他们的this指向与上述情况有所不同,下面就来看看这些情况。
        
        (1)、箭头函数
        const foo = {  
            fn: function () {  
                setTimeout(function() {  
                    console.log(this)
                })
            }  
        }  
        console.log(foo.fn())
        // window
        
        这里,this 出现在 setTimeout() 中的回调函数里,因此 **this 指向 window 对象**。如果需要 this 指向 foo 这个 object 对象,可以使用箭头函数解决:
        
        const foo = {  
            fn: function () {  
                setTimeout(() => {  
                    console.log(this)
                })
            }  
        } 
        console.log(foo.fn())
        // {fn: ƒ}
        
        (2)、数组方法
        来看下面的代码,在属性 arr 的 forEach 回调函数中输出 this,指向的是什么呢?
        
        var obj = {
          arr: [1]
        }
        obj.arr.forEach(function() {
          console.log(this)
        }) 
        

        其实输出的仍然是全局对象。

        forEach 方法语法如下:

        array.forEach(function(currentValue, index, arr), thisValue)
        

        其参数如下:

        1)function(currentValue, index, arr):必需。 数组中每个元素需要调用的函数。

        ● currentValue:必需,当前元素

        ● index:可选,当前元素的索引值

        ● arr:可选,当前元素所属的数组对象

        2)thisValue:可选,传递给函数的值一般用 “this” 值。如果这个参数为空, “undefined” 会传递给 “this” 值

        可以看到,forEach方法有两个参数,第一个是回调函数,第二个是 this 指向的对象,这里只传入了回调函数,第二个参数没有传入,默认为 undefined,所以会输出全局对象。
        除了forEach方法,需要传入 this 指向的函数还有:**every()、find()、findIndex()、map()、some()**,在使用的时候需要注意。
        
        (3)、立即执行函数

        立即执行函数就是定义后立刻调用的匿名函数:

        var name = 'hello'
        var obj = {
          name: 'world',
          sayHello: function() {
            console.log(this.name)
          },
          hello: function() {
            (function(cb) {
              cb()
            })(this.sayHello)
          }
        }
        obj.hello() // hello
        
        执行结果是 hello,是 window.name 的值。立即执行函数作为一个匿名函数,通常就是直接调用,而不会通过属性访问器(obj.fn)的形式来给它指定一个所在对象,所以它的 this 是确定的,就是默认的全局对象 window。
        
        (4)、setTimeout 和 setInterval

        setTimeout 和 setInterval 中函数的 this 指向规则是一样的:

        var name = 'hello'
        var obj = {
          name: 'world',
          hello: function() {
            setTimeout(function() {
              console.log(this.name)
            })
          }
        }
        obj.hello() // hello
        
        this.name 是在 obj.hello () 里被调用的,结果却输出了 window.name。其实,延时效果(setTimeout)和定时效果(setInterval)都是在全局作用域下实现的。无论是 setTimeout 还是 setInterval 里传入的函数,都会首先被交到全局对象手上。因此,函数中 this 的值,会被自动指向 window。
        
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

相关阅读

目录[+]

取消
微信二维码
微信二维码
支付宝二维码