我是小又又,住在武汉,做了两年新媒体,准备用 6 个月时间转行前端。
今日学习目标
昨天基于搜索来基础学习 Function 数据结构。今天主要是基于搜索来学习 function 箭头函数 ,又是适合学习的一天,加油,小又又!!!!
基本说明
ES6
允许使用箭头
(=>
)定义函数。箭头函数表达式
的语法
比函数表达式更简洁
,并且没有自己的this
,arguments
,super
或 new.target
。这些函数表达式
更适用于那些本来需要匿名函数
的地方,并且它们不能用作构造函数
。
语法
基础语法
(param1, param2, …, paramN) => { statements }
// 等同于
// function(param1, param2, …, paramN){ return {statements}; }
(param1, param2, …, paramN) => expression
// 等同于
// function(param1, param2, …, paramN){ return expression; }
// Parentheses are optional when there's only one parameter name:
// 当只有一个参数时,圆括号是可选的
(singleParam) => { statements }
singleParam => { statements }
// 等同于
// function(singleParam){ return expression; }
// The parameter list for a function with no parameters should be written with a pair of parentheses.
// 没有参数的函数应该写成一对圆括号。
() => { statements }
高阶语法
// Parenthesize the body of function to return an object literal expression:
// 加括号的函数体返回对象字面表达式:
params => ({foo: bar})
// Rest parameters and default parameters are supported
// 支持剩余参数和默认参数
(param1, param2, ...rest) => { statements }
(param1 = defaultValue1, param2, …, paramN = defaultValueN) => {
statements }
// Destructuring within the parameter list is also supported
// 同样支持参数列表解构
const f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
f(); // 6
```
如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return语句返回。
const sum = (num1, num2) => { return num1 + num2; }
这一段出现了好些新名词,剩余参数和默认参数,解构,感觉有些看不太懂~~~~
箭头函数变量作用域
箭头函数
内定义的变量
及其作用域
常规内部变量
// 常规写法
const greeting_1 = () => {let now = new Date(); return ("Good" + ((now.getHours() > 17) ? " evening." : " day."));}
console.log(greeting_1()); //"Good evening."
console.log(now); // ReferenceError: now is not defined 标准的let作用域
形参
参数括号内定义的变量是局部变量(默认参数)
const greeting_2 = (now=new Date()) => "Good" + (now.getHours() > 17 ? " evening." : " day.");
console.log(greeting_2()); //"Good evening."
console.log(now); // ReferenceError: now is not defined
函数体内定义变量
函数体内{}
不使用var
定义的变量是全局变量
const greeting_3 = () => {now = new Date(); return ("Good" + ((now.getHours() > 17) ? " evening." : " day."));}
console.log(greeting_3()); //"Good evening."
console.log(now); // Wed Apr 24 2019 23:02:07 GMT+0800 (中国标准时间)
函数体内{}
用const
定义的变量是局部变量
const greeting_4 = () => {const now = new Date(); return ("Good" + ((now.getHours() > 17) ? " evening." : " day."));}
console.log(greeting_4()); //"Good evening."
console.log(now); // ReferenceError: now is not defined
主要解决问题
视觉优化
无参数箭头函数
在视觉上容易分析
setTimeout( () => {
console.log('I happen sooner');
setTimeout( () => {
// deeper code
console.log('I happen later');
}, 1);
}, 1);
更短的函数
const elements = [
'Hydrogen',
'Helium',
'Lithium',
'Beryllium'
];
console.log(elements.map(function(element) {
return element.length;
})); // [8, 6, 7, 9]
// 上面的普通函数可以改写成如下的箭头函数
console.log(elements.map((element) => {
return element.length;
})); // [8, 6, 7, 9]
// 当箭头函数只有一个参数时,可以省略参数的圆括号
console.log(elements.map(element => {
return element.length;
})); // [8, 6, 7, 9]
// 当箭头函数的函数体只有一个 `return` 语句时,可以省略 `return` 关键字和方法体的花括号
console.log(elements.map(element => element.length)); // [8, 6, 7, 9]
// 在这个例子中,因为我们只需要 `length` 属性,所以可以使用参数解构
// 需要注意的是字符串 `"length"` 是我们想要获得的属性的名称,而 `lengthFooBArX` 则只是个变量名,
// 可以替换成任意合法的变量名
console.log(elements.map(({ "length": lengthFooBArX }) => lengthFooBArX)); // [8, 6, 7, 9]
不绑定this
在箭头函数
出现之前,每个新定义的函数
都有它自己的 this
值(在构造函数的情况下是一个新对象
,在严格模式
的函数调用中为 undefined
,如果该函数被作为对象方法
调用则为基础对象
等)。This
被证明是令人厌烦的面向对象风格的编程。
function Person() {
// Person() 构造函数定义 `this`作为它自己的实例.
this.age = 0;
setInterval(function growUp() {
// 在非严格模式, growUp()函数定义 `this`作为全局对象,
// 与在 Person()构造函数中定义的 `this`并不相同.
this.age++;
}, 1000);
}
const p = new Person();
console.log(p);// Person {age: 0}
在ECMAScript 3/5
中,通过将this
值分配给封闭
的变量
,可以解决this
问题。
function Person() {
const that = this;
that.age = 0;
setInterval(function growUp() {
// 回调引用的是`that`变量, 其值是预期的对象.
that.age++;
}, 1000);
}
或者,可以创建绑定函数
,以便将预先分配的this
值传递到绑定的目标函数
(上述示例中的growUp()
函数)。
箭头函数
不会创建自己的this
,它只会从自己的作用域链的上一层继承this
。因此,在下面的代码中,传递给setInterval
的函数内的this
与封闭函数中的this
值相同:
function Person(){
this.age = 0;
setInterval(() => {
this.age++; // |this| 正确地指向 p 实例
}, 1000);
}
const p = new Person();
不绑定arguments
箭头函数不绑定Arguments
对象。因此,在本示例中,arguments
只是引用了封闭作用域内的arguments
:
const arguments = [1, 2, 3];
const arr = () => arguments[0];
console.log(arr()); // 1
function foo(n) {
const f = () => arguments[0] + n; // 隐式绑定 foo 函数的 arguments 对象. arguments[0] 是 n
return f();
}
console.log(foo(1)); // 2
在大多数情况下,使用剩余参数
是相较使用arguments
对象的更好选择。
function foo(arg) {
const f = (...args) => args[0];
return f(arg);
}
console.log(foo(1)); // 1
function foo(arg1,arg2) {
const f = (...args) => args[1];
return f(arg1,arg2);
}
console.log(foo(1,2)); //2
注意事项
方法函数
箭头函数表达式
对非方法函数
是最合适的。如果试着把它们作为方法
时发生了什么。
'use strict';
const obj = {
i: 10,
b: () => console.log(this.i, this),
c: function() {
console.log(this.i,this)
}
}
console.log(obj.b());
// undefined Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
// undefined
console.log(obj.c());
// 10 {i: 10, b: ƒ, c: ƒ}
// undefined
箭头函数
没有定义this
绑定。
Object.defineProperty()
涉及Object.defineProperty()
的示例
'use strict';
const obj = {
a: 10
};
Object.defineProperty(obj, "b", {
get: () => {
console.log(this.a, typeof this.a, this);
return this.a+10; // NaN
// 代表全局对象 'Window', 因此 'this.a' 返回 'undefined'
}
});
console.log(obj.b); // undefined "undefined" Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
new 操作符
箭头函数不能用作构造器,和 new一起用会抛出错误。
const Foo = () => {};
const foo = new Foo(); // TypeError: Foo is not a constructor
prototype 属性
箭头函数
没有prototype
属性。
const Foo = () => {};
console.log(Foo.prototype); // undefined
yield
yield
关键字通常不能在箭头函数
中使用(除非是嵌套在允许使用的函数内)。因此,箭头函数
不能用作生成器
。
返回值为对象字面量
记住用params => {object:literal}
这种简单的语法返回对象字面量
是行不通的。
由于大括号
被解释为代码块
,所以如果箭头函数
直接返回一个对象,必须在对象字面量
外面加上括号,否则会报错。
// 报错
// let getTempItem = id => { id: id, name: "Temp" };
// 不报错 但是没有取得指定返回值
let getTempItem_1 = id => { id: id };
// 不报错 可以取得指定返回值
let getTempItem_2 = id => ({ id: id, name: "Temp" });
console.log(getTempItem_1(123));// undefined
console.log(getTempItem_2(12));// {id: 12, name: "Temp"}
上面代码getTempItem_1
中,原始意图是返回一个对象{ id: id }
,但是由于引擎
认为大括号
是代码块
,所以执行了一行语句id: id
。
这时,id
可以被解释为语句
的标签
,因此实际执行的语句
是id
;,然后函数
就结束了,没有返回值。
省略大括号
如果箭头函数
只有一行语句,且不需要返回值,可以采用下面的写法,就不用写大括号
了。
let fn = () => void doesNotReturn();
换行
箭头函数
在参数
和箭头
之间不能换行。
const func = ()
=> 1;
// SyntaxError: expected expression, got '=>'
解析顺序
虽然箭头函数
中的箭头
不是运算符
,但箭头函数
具有与常规函数
不同的特殊[运算符优先级][Operator-Precedence]解析规则。
let callback;
callback = callback || function() {}; // ok
callback = callback || () => {};
// SyntaxError: invalid arrow-function arguments
callback = callback || (() => {}); // ok
函数体
箭头函数
可以有一个简写体
或常见的块体
。
在一个简写体
中,只需要一个表达式
,并附加一个隐式
的返回值
。在块体中,必须使用明确的return
语句。
var func = x => x * x;
// 简写函数 省略return
var func = (x, y) => { return x + y; };
//常规编写 明确的返回值
与严格模式的关系
鉴于 this
是词法层面上的,严格模式
中与 this
相关的规则都将被忽略。
function Person() {
this.age = 0;
const closure = "123"
setInterval(function growUp() {
this.age++;
console.log(closure);
}, 1000);
}
const p = new Person();
function PersonX() {
'use strict'
this.age = 0;
const closure = "123"
setInterval(()=>{
this.age++;
console.log(closure);
}, 1000);
}
const px = new PersonX();
console.log(px);// PersonX {age: 0}
严格模式
的其他规则依然不变。
call & apply
由于 箭头函数
没有自己的this
指针,通过 call()
或 apply()
方法调用一个函数
时,只能传递参数(不能绑定this
),他们的第一个参数会被忽略
。(这种现象对于bind
方法同样成立)
const adder = {
base : 1,
add : function(a) {
const f = v => v + this.base;
return f(a);
},
addThruCall: function(a) {
const f = v => v + this.base;
const b = {
base : 2
};
return f.call(b, a);
}
};
console.log(adder.add(1)); // 输出 2
console.log(adder.addThruCall(1)); // 仍然输出 2(而不是3)
使用案例
简洁基础函数
箭头函数
使得表达更加简洁。
const isEven = n => n % 2 === 0;
const square = n => n * n;
上面代码只用了两行,就定义了两个简单的工具函数
。如果不用箭头函数
,可能就要占用多行,而且还不如现在这样写醒目。
简洁回调函数
箭头函数
的一个用处是简化回调函数。
// 正常函数写法
[1,2,3].map(function (x) {
return x * x;
});
// 箭头函数写法
[1,2,3].map(x => x * x);
另一个例子是
// 正常函数写法
const result = values.sort(function (a, b) {
return a - b;
});
// 箭头函数写法
const result = values.sort((a, b) => a - b);
array相关
方便数组reduce
,filter
,和map
;
// Easy array filtering, mapping, ...
const arr = [5, 6, 13, 0, 1, 18, 23];
const sum = arr.reduce((a, b) => a + b);
console.log(sum); // 66
const even = arr.filter(v => v % 2 == 0);
console.log(even); // [6, 0, 18]
const double = arr.map(v => v * 2);
console.log(double); // [10, 12, 26, 0, 2, 36, 46]
IIFE
// 空的箭头函数返回 undefined
const empty = () => {};
console.log((() => 'foobar')());// foobar
// (这是一个立即执行函数表达式,可参阅 'IIFE'术语表)
三元运算符
箭头函数
也可以使用条件(三元
)运算符
const simple = a => a > 15 ? 15 : a;
console.log(simple(16)); // 15
console.log(simple(10)); // 10
let max = (a, b) => a > b ? a : b;
console.log(max(4, 5));// 5
参考网站
- arrow function: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
- Church_encoding: https://en.wikipedia.org/wiki/Church_encoding
- combinators: https://en.wikipedia.org/wiki/Fixed-point_combinator#Strict_fixed_point_combinator
- how-to-use-arrow: https://github.com/getify/You-Dont-Know-JS/blob/master/es6%20%26%20beyond/fig1.png
- Operator-Precedence: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Operator_Precedence
今日学习总结

今日心情
今日主要是基于搜索来基础学习function 箭头函数,感觉用了箭头函数内容主要就是简洁了很多,然后了解到了剩余参数,默认参数和解构,之后要再详细了解一下,希望明天学到更多的内容~~~~

本文使用 mdnice 排版