• JavaScript系列之箭头函数



    一、概述

    箭头函数表达式的语法比函数表达式更简洁,并且没有自己的this,arguments,super或new.target。箭头函数表达式更适用于那些本来需要匿名函数的地方,并且它不能用作构造函数。

    二、语法

    1、基础语法

    (param1, param2,, paramN) => {
    	statements;
    };
    (param1, param2,, paramN) => expression;
    //相当于:(param1, param2, …, paramN) =>{ return expression; }
    
    // 当只有一个参数时,圆括号是可选的:
    (singleParam) => {
    	statements;
    };
    singleParam => {
    	statements;
    };
    
    // 没有参数的函数应该写成一对圆括号。
    () => {
    	statements;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2、高级语法

    //加括号的函数体返回对象字面量表达式:
    params => ({ foo: bar });
    
    //支持剩余参数和默认参数
    (param1, param2, ...rest) => {
    	statements;
    };
    (param1 = defaultValue1, param2,, paramN = defaultValueN) => {
    	statements;
    };
    
    //同样支持参数列表解构
    let f = ([a, b] = [1, 2], { x: c } = { x: a + b }) => a + b + c;
    f(); // 6
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    三、引入箭头函数的作用

    1、更短的函数

    var elements = ["Hydrogen", "Helium", "Lithium", "Beryllium"];
    
    elements.map(function (element) {
    	return element.length;
    }); // 返回数组:[8, 6, 7, 9]
    
    // 上面的普通函数可以改写成如下的箭头函数
    elements.map((element) => {
    	return element.length;
    }); // [8, 6, 7, 9]
    
    // 当箭头函数只有一个参数时,可以省略参数的圆括号
    elements.map(element => {
    	return element.length;
    }); // [8, 6, 7, 9]
    
    // 当箭头函数的函数体只有一个 `return` 语句时,可以省略 `return` 关键字和方法体的花括号
    elements.map(element => element.length); // [8, 6, 7, 9]
    
    // 在这个例子中,因为我们只需要 `length` 属性,所以可以使用参数解构
    // 需要注意的是字符串 `"length"` 是我们想要获得的属性的名称,而 `lengthFooBArX` 则只是个变量名,
    // 可以替换成任意合法的变量名
    elements.map(({ length: lengthFooBArX }) => lengthFooBArX); // [8, 6, 7, 9]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    2、没有单独的this

    在 ECMAScript 3/5 中,通过将this值分配给封闭的变量,可以解决this问题。

    function Person() {
    	var that = this;
    	that.age = 0;
    
    	setInterval(function growUp() {
    		// 回调引用的是`that`变量,其值是预期的对象。
    		that.age++;
    	}, 1000);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    四、示例

    1、不绑定arguments

    箭头函数不绑定 Arguments 对象。因此,在本示例中,arguments只是引用了封闭作用域内的 arguments:

    var arguments = [1, 2, 3];
    var arr = () => arguments[0];
    
    arr(); // 1
    
    function foo(n) {
    	var f = () => arguments[0] + n; // 隐式绑定 foo 函数的 arguments 对象. arguments[0] 是 n,即传给 foo 函数的第一个参数
    	return f();
    }
    
    foo(1); // 2
    foo(2); // 4
    foo(3); // 6
    foo(3, 2); //6
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在大多数情况下,使用剩余参数是相较使用arguments对象的更好选择。

    function foo(arg) {
    	var f = (...args) => args[0];
    	return f(arg);
    }
    foo(1); // 1
    
    function foo(arg1, arg2) {
    	var f = (...args) => args[1];
    	return f(arg1, arg2);
    }
    foo(1, 2); //2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2、使用箭头函数作为方法

    如上所述,箭头函数表达式对非方法函数是最合适的。让我们看看当我们试着把它们作为方法时发生了什么。

    "use strict";
    var obj = {
    	i: 10,
    	b: () => console.log(this.i, this),
    	c: function () {
    		console.log(this.i, this);
    	}
    };
    obj.b();
    // undefined, Window{...}
    obj.c();
    // 10, Object {...}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    箭头函数没有定义 this 绑定。另一个涉及Object.defineProperty()的示例:

    "use strict";
    var obj = {
    	a: 10
    };
    
    Object.defineProperty(obj, "b", {
    	get: () => {
    		console.log(this.a, typeof this.a, this);
    		return this.a + 10;
    		// 代表全局对象 'Window', 因此 'this.a' 返回 'undefined'
    	}
    });
    
    obj.b; // undefined   "undefined"   Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    3、使用 new 操作符

    箭头函数不能用作构造器,和 new一起用会抛出错误。

    var Foo = () => {};
    var foo = new Foo(); // TypeError: Foo is not a constructor
    
    • 1
    • 2

    4、使用prototype属性

    箭头函数没有prototype属性。

    var Foo = () => {};
    console.log(Foo.prototype); // undefined
    
    • 1
    • 2

    5、使用 yield 关键字

    yield 关键字通常不能在箭头函数中使用(除非是嵌套在允许使用的函数内)。因此,箭头函数不能用作函数生成器。

    6、函数体

    箭头函数可以有一个“简写体”或常见的“块体”。

    在一个简写体中,只需要一个表达式,并附加一个隐式的返回值。在块体中,必须使用明确的return语句。

    var func = x => x * x;
    // 简写函数 省略 return
    
    var func = (x, y) => {
    	return x + y;
    };
    //常规编写 明确的返回值
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    7、返回对象字面量

    记住用params => {object:literal}这种简单的语法返回对象字面量是行不通的。

    var func = () => { foo: 1 };
    // Calling func() returns undefined!
    
    var func = () => { foo: function() {} };
    // SyntaxError: function statement requires a name
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这是因为花括号({} )里面的代码被解析为一系列语句(即 foo 被认为是一个标签,而非对象字面量的组成部分)。
    所以,记得用圆括号把对象字面量包起来:

    var func = () => ({ foo: 1 });
    
    • 1

    8、换行

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

    var func = ()
               => 1;
    // SyntaxError: expected expression, got '=>'
    
    • 1
    • 2
    • 3

    但是,可以通过在 ‘=>’ 之后换行,或者用 ‘( )’、'{ }'来实现换行,如下:

    var func = (a, b, c) =>
      1;
    
    var func = (a, b, c) => (
      1
    );
    
    var func = (a, b, c) => {
      return 1
    };
    
    var func = (
      a,
      b,
      c
    ) => 1;
    
    // 不会有语法错误
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    9、解析顺序

    虽然箭头函数中的箭头不是运算符,但箭头函数具有与常规函数不同的特殊运算符优先级解析规则。

    let callback;
    
    callback = callback || function() {}; // ok
    
    callback = callback || () => {};
    // SyntaxError: invalid arrow-function arguments
    
    callback = callback || (() => {});    // ok
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    10、箭头函数也可以使用条件(三元)运算符:

    var simple = a => (a > 15 ? 15 : a);
    simple(16); // 15
    simple(10); // 10
    
    let max = (a, b) => (a > b ? a : b);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    11、箭头函数也可以使用闭包:

    // 标准的闭包函数
    function A() {
    	var i = 0;
    	return function b() {
    		return ++i;
    	};
    }
    
    var v = A();
    v(); //1
    v(); //2
    
    //箭头函数体的闭包( i=0 是默认参数)
    var Add = (i = 0) => {
    	return () => ++i;
    };
    var v = Add();
    v(); //1
    v(); //2
    
    //因为仅有一个返回,return 及括号()也可以省略
    var Add =
    	(i = 0) =>
    	() =>
    		++i;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    12、箭头函数递归

    var fact = x => (x == 0 ? 1 : x * fact(x - 1));
    fact(5); // 120
    
    • 1
    • 2

    13、箭头函数内定义的变量及其作用域

    // 常规写法
    var greeting = () => {
    	let now = new Date();
    	return "Good" + (now.getHours() > 17 ? " evening." : " day.");
    };
    greeting(); //"Good day."
    console.log(now); // ReferenceError: now is not defined 标准的 let 作用域
    
    // 参数括号内定义的变量是局部变量(默认参数)
    var greeting = (now = new Date()) => "Good" + (now.getHours() > 17 ? " evening." : " day.");
    greeting(); //"Good day."
    console.log(now); // ReferenceError: now is not defined
    
    // 对比:函数体内{}不使用 var 定义的变量是全局变量
    var greeting = () => {
    	now = new Date();
    	return "Good" + (now.getHours() > 17 ? " evening." : " day.");
    };
    greeting(); //"Good day."
    console.log(now); // Fri Dec 22 2017 10:01:00 GMT+0800 (中国标准时间)
    
    // 对比:函数体内{} 用 var 定义的变量是局部变量
    var greeting = () => {
    	var now = new Date();
    	return "Good" + (now.getHours() > 17 ? " evening." : " day.");
    };
    greeting(); //"Good day."
    console.log(now); // ReferenceError: now is not defined
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    写在最后

    如果你感觉文章不咋地//(ㄒoㄒ)//,就在评论处留言,作者继续改进;o_O???
    如果你觉得该文章有一点点用处,可以给作者点个赞;\\*^o^*//
    如果你想要和作者一起进步,可以微信扫描二维码,关注前端老L~~~///(^v^)\\\~~~
    谢谢各位读者们啦(^_^)∠※!!!

  • 相关阅读:
    CDGA|工业互联网行业怎么做好数据治理?
    HTML、CSS学习笔记小结
    AI_Neural Network_Note(一)
    了解JVM的相关概述,发现很多全忘了(文末福利)
    JavaScript作用域链与预解析
    基于matomo实现业务数据埋点采集上报
    《C++程序设计原理与实践》笔记 第7章 完成一个程序
    Hexagon_V65_Programmers_Reference_Manual(38)
    用 ChatGPT 做一个 Chrome 扩展 | 京东云技术团队
    WeetCode3 暴力递归->记忆化搜索->动态规划
  • 原文地址:https://blog.csdn.net/weixin_62277266/article/details/126916070