• ES6中的箭头函数详细梳理


    一、箭头函数的介绍

    1.1 什么是箭头函数

    ES6中允许使用=>来定义函数。箭头函数相当于匿名函数,并简化了函数定义。

    1.2 基本语法

    // 箭头函数
    let fn = (name) => {
        // 函数体
        return `Hello ${name} !`;
    };
    
    // 等同于
    let fn = function (name) {
        // 函数体
        return `Hello ${name} !`;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    箭头函数在语法上比普通函数简洁多。箭头函数就是采用箭头=>来定义函数,省去关键字function。

    函数的参数放在=>前面的括号中,函数体跟在=>后的花括号中

    1.3 箭头函数的参数

    ①如果箭头函数没有参数,写空括号

    //没有参数,写空括号
        let fn = () => {
            console.log('hello');
        };
    
    • 1
    • 2
    • 3
    • 4

    ②如果箭头函数有一个参数,也可以省去包裹参数的括号

    //只有一个参数,可以省去参数括号
        let fn = name => {
            console.log(`hello ${name}!`)
        };
    
    • 1
    • 2
    • 3
    • 4

    ③如果箭头函数有多个参数,将参数依次用逗号(,)分隔,包裹在括号中。

        let fn = (val1, val2, val3, val4) => {
            return [val1, val2, val3, val4];
        }
    
    • 1
    • 2
    • 3

    1.4 箭头函数的函数体

    ①如果箭头函数的函数体只有一句执行代码,简单返回某个变量或者返回一个简单的js表达式,可以省去函数体花括号{ }

    //返回某个简单变量val
    let f = val => val;
    // 等同于
    let f = function (val) { return val };
    
    
    //返回一个简单的js表达式num1+num2
    let sum = (num1, num2) => num1 + num2;
    // 等同于
    let sum = function(num1, num2) {
      return num1 + num2;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    ②如果箭头函数的函数体只有一句代码,返回的不是变量和简单的js表达式,而是一个对象。

    //错误写法—花括号会被解释为函数体
        let getItem = id => {
            id: id,
            name: 'gaby'
        };
    //正确写法
        let getItem = id => ({
            id: id,
            name: 'gaby'
        });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    ③如果箭头函数的函数体只有一条语句且不需要返回值(最常用于回调函数),加上void关键字

    let fn = () => void doesNotReturn();
    
    • 1

    箭头函数用于回调函数,常见简洁

    //栗子1
    //普通函数
        [1, 2, 3].map(function (x) {
            return x + x;
        });
    //ES6箭头函数
    [1, 2, 3].map(x => x + x);
    
    
    //栗子2
    //普通函数
        var result = [2, 4, 5, 1, 6].sort(function (a, b) {
            return a - b;
        });
    //ES6箭头函数
    	var result = [2, 4, 5, 1, 6].sort((a, b) => a - b);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    二、箭头函数的this指向规则

    2.1 箭头函数没有原型prototype,因此箭头函数没有this指向

        let fn = () => {
            console.log('Hello World !')
        };
        console.log(fn.prototype); // undefined
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    2.2 箭头函数不会创建自己的this,如果存在外层第一个普通函数,在定义的时候会继承它的this

    箭头函数没有自己的this指向,它会捕获自己定义所处的外层执行环境,并且继承这个this值。箭头函数的this指向在被定义的时候就确定了,之后永远都不会改变。(!永远)

    (1)栗子1
        var id = 'Global';
        //普通函数
        function fn1() {
            setTimeout(function () {
                console.log(this.id)
    
            }, 1000);
        }
        //箭头函数
        function fn2() {
            setTimeout(() => {
                console.log(this.id)
            }, 1000);
        }
    
        fn1.call({
            id: 'obj'
        });//Global
    
        fn2.call({
            id: 'obj'
        });//obj
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这里插入图片描述

    解析:普通函数的setTimeout 一秒后执行是在全局作用域,所有this指向window对象,this.id指向了全局变量id,输出Golbal。箭头函数的this在定义的时候就确定了,继承fn2的执行环境中的this,fn2的this指向被call方法改变绑定到obj这个对象

    (2)栗子2
        var id = 'Global';
        var obj = {
            id: 'OBJ',
            a: function () {
                console.log(this.id)
            },//方法a普通函数定义
            b: () => {
                console.log(this.id)
            }//方法b用箭头函数定义
        };
        obj.a();//OBJ
        obj.b();//Global
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述

    解析:普通函数作为对象的方法调用,this指向所属的对象(谁调用它就指向谁),this.id 就是obj.id;箭头函数继承定义它的执行环境的this,指向window对象,指向全局变量,输出Global。花括号{}无法形成一个单独的执行环境,所有它依然在全局中。

    2.3 箭头函数的this是继承而来的永远不会变,call/apply/bind也无法改变

    .call()/.apply()/.bind()方法可以用来动态修改函数执行时this的指向,但由于箭头函数的this定义时就已经确定且永远不会改变

        var name = 'gaby'
        var person = {
            name: 'gabrielle',
            say: function () {
                console.log('say hello', this.name)
            }, //普通函数
            say2: () => {
                console.log('say2 hello', this.name)
            } //箭头函数
        }
        person.say.call({
            name: 'Mike'
        })
        person.say2.call({
            name: 'Amy'
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述

    解析:say的普通函数通过call调用已经改变this指向。say2箭头函数调用call绑定尝试改变this指向,但是仍然打印出外一层普通函数的this指向,window对象的全局变量name。

    2.4 箭头函数this指向只能间接修改

    间接修改:修改被继承的普通函数的this指向,箭头函数的this指向也会跟着改变。

    箭头函数的this指向定义时所在的外层第一个普通函数,跟使用的位置没有关系。

        let al
        let aObj = {
            msg: 'a的this指向'
        };
        bObj = {
            msg: 'b的this指向'
        };
        a.call(aObj); //将a的this指向aObj
        b.call(bObj); //将b普通函数的this指向bObj 箭头函数内部的this指向也会指向bObj
    
        function b() {
            al();
        }
    
        function a() {
            al = () => {
                console.log(this, 'this指向定义时外层第一个普通函数 ')
            };
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述

    2.5 箭头函数外层没有函数,严格模式和非严格模式下它的this都会指向window全局对象

    箭头函数的this指向继承自外层第一个普通函数的this,那么如果没有外层函数,它的this指向哪里?

    this的绑定规则:非严格模式下,默认绑定的this指向全局对象,严格模式下this指向undefined。

    如果箭头函数外层没有普通函数继承,箭头函数在全局作用域下,严格模式和非严格模式下它的this都会指向window(全局对象)

    2.6 多层嵌套函数this指向

    箭头函数中的this引用的是最近作用域中的this,是向外层作用域中,一层层查找this,直到有this的定义。

    2.7 箭头函数不能作为构造函数使用new

    构造函数做了什么?

    ①JS内部首先会先生成一个对象

    ②再把函数中的this指向该对象

    ③然后执行构造函数中的语句

    ④最终返回该对象实例

    箭头函数没有自己的this,this继承外层执行环境中的this,且this永远不会改变。new会报错

        let fn = (name, age) => {
            this.name = name;
            this.age = age;
        };
    
        let person = new fn('gaby', 20)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    2.8 箭头函数不支持new.target

    ES6新引入的属性,普通函数可以通过new调用,new.target返回该函数的引用。用于确定构造函数是否为new调用。箭头函数并不能作为构造函数使用new,自然也不支持new.targer。

    (1)箭头函数的this指向全局对象,在箭头函数中使用箭头函数会报错
        let fn = () => {
            console.log(new.target)
        };
        fn()
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    (2)箭头函数的this指向普通函数,它的new.target就是指向该普通函数的引用
        new fn2();
    
        function fn2() {
            let fn = () => {
                console.log(new.target)
            };
            fn();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    三、箭头函数的arguments规则

    3.1 箭头函数没有自己的arguments

    (1)箭头函数处于全局作用域中

    箭头函数的this指向全局对象,会报arguments未声明的错。

        let fn = name => {
            console.log(arguments)
        }
        let fn2 = function (name) {
            console.log(arguments)
        }
        //fn()
        fn2()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

        let fn = name => {
            console.log(arguments)
        }
        let fn2 = function (name) {
            console.log(arguments)
        }
        fn()
        fn2()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    解析:普通函数可以打印arguments,箭头函数报错。因为箭头函数处于全局作用域中,在全局作用域没有arguments的定义,箭头函数本身没有arguments,所以报错。

    (2)箭头函数的this如果指向普通函数,它的argumens继承于该普通函数
        let fn2 = function (name) {
            console.log('fn2:', arguments)
            let fn = name => {
                console.log('fn:', arguments)
            }
            fn()
        }
        fn2('gaby')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    解析:两个函数打印的argument相同,都是fn2函数的arguments。

    总结

    箭头函数没有自己的arguments对象。在箭头函数中访问arguments实际上获得的是外层局部(函数)执行环境中的值。

    3.2 可以用rest替代,rest参数获取函数的多余参数

    rest是ES6的API,用于获取函数不定数量的参数数组。这个API可以用来替代arguments。

    (1)基本用法
        //形式是...变量名 
    	let fn = (first, ...arr) => {
            console.log(first, arr);
        }
        fn(1, 2, 3, 4);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    解析:rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。获取函数的第一个确定的参数,以及用一个变量接收其他剩余函数的实例。

    (2)使用注意事项

    ①rest必须是函数的最后一位参数

        let a = (first, ...rest, three) => {
            console.log(first, rest, three);
        };
        a(1, 2, 3, 4);
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    ②函数的length属性不包括rest

    (3)rest和arguments函数比较

    ①箭头函数和普通函数都可以使用rest参数,而arguments只能普通函数用。

    ②接收参数rest比arguments更加灵活,完全可以自定义。

    ③rest是一个真正的数组可以使用数组API,arguments只是一个类数组。

    3.3 箭头函数不支持重复函数参数的名称

        function fn(name, name) {
            console.log('fn2:', name)
        }
        let fn2 = (name, name) => {
            console.log('fn:', name)
        }
        fn('wang', 'gaby')
        fn2('wang', 'gaby')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    3.4 箭头函数不能用作Generator,不能使用yeild关键字

    四、箭头函数的注意事项

    ①函数箭头一条语句返回对象字面量,需要加括号。

    ②箭头函数在参数和箭头之间不能换行

    ③箭头函数的解析顺序相对||靠前

    五、箭头函数不适用场景

    (1)对象方法,且方法使用了this

    对象无法构造单独的作用域

        var name = 'gaby'
        var person = {
            name: 'gabrielle',
            say: function () {
                console.log('say hello', this.name)
            }, //普通函数
            say2: () => {
                console.log('say2 hello', this.name)
            } //箭头函数
        }
        person.say()
        person.say2()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述

    解析:person.say2()方法是一个箭头函数,调用person.say2()的时候this指向全局对象,达不到预期。对象无法构成单独的作用域,定义say2()箭头函数的时候作用域在全局作用域。

    (2)回调函数的动态this
        var button = document.querySelector('.btn');
        button.addEventListener('click', () => {
            this.classList.toggle('on');
        });
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    解析:报错。按钮点击是一个回调函数,而箭头函数内部的this指向外一层普通函数的this,在这里就是window,所以报错。改成普通函数就不会报错

    六、箭头函数与普通函数简单区别总结

    (1)箭头函数语法更简洁清晰,快捷。

    (2)箭头函数没有原型prototype,并不会自己创建this,并且this不能被修改,call等都不能修改到。只能间接修改被继承的this

    (3)箭头函数的this在定义时就定了,继承外一层的普通函数

    (4)如果箭头函数外一层再外一层都不能找到普通函数,在严格和非严格情况下都会指向window对象

    (5)箭头函数的this指向全局,使用arguments会报未声明的错误

    (6)箭头函数的this指向外一层的普通函数,使用argument继承该普通函数

    (7)箭头函数不能构造函数,不能new.target,不能new,没有constructor

    (8)箭头函数不支持重复命名参数,普通函数可以重复命名参数

    先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦

  • 相关阅读:
    ChinaSkills技能大赛网络系统管理Debian模块(样题一)||RSERVER TASK配置
    从零开始Blazor Server(12)--编辑菜单
    中断实验(按键/光电开关/火焰传感器/人体红外)
    【FAQ】HarmonyOS SDK 闭源开放能力 —Map Kit
    Pytorch加载数据初认识
    MySQL库的操作『增删改查 ‖ 编码问题 ‖ 备份与恢复』
    亲测好用-obsidian无法打开插件库安装或更新的解决办法-结合FastGithub
    数字孪生智慧选煤厂:数据监控赋能矿山高效生产
    【Promise】Promise 使用 / 回调地狱问题 async-await /宏队列与微队列
    JavaWeb核心(3)
  • 原文地址:https://blog.csdn.net/m0_67392126/article/details/126100080