函数参数的默认值
function log(x, y = 'World') {
console.log(x, y);
}
log('Hello') // Hello World
function Point(x = 0, y = 0) {
this.x = x;
this.y = y;
}
var p = new Point();
p // { x: 0, y: 0 }
解构赋值默认值的使用:
function fetch(url, { body = '', method = 'GET', headers = {} }) {
console.log(method);
}
fetch('http://example.com', {})// "GET"
fetch('http://example.com')// 报错
函数的length属性:
指定了默认值以后,函数的length
属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后,length
属性将失真。
(function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2
利用参数默认值,可以指定某一个参数不得省略,如果省略就抛出一个错误
function throwIfMissing() {
throw new Error('Missing parameter');
}
function foo(mustBeProvided = throwIfMissing()) {
return mustBeProvided;
}
foo()
rest参数
ES6引入rest参数(形式为“...变量名”),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest参数搭配的变量是一个数组,该变量将多余的参数放入数组中。与java中的可变形参功能一样。
// arguments变量的写法
function sortNumbers() {
return Array.prototype.slice.call(arguments).sort();
}
// rest参数的写法
const sortNumbers = (...numbers) => numbers.sort();
扩展运算符
扩展运算符(spread)是三个点(...)。它好比rest参数的逆运算,将一个数组转为用逗号分隔的参数序列。
console.log(...[1, 2, 3])
// 1 2 3
console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5
[...document.querySelectorAll('div')]
// [<div>, <div>, <div>]
// ES5的写法
Math.max.apply(null, [14, 3, 77])
// ES6的写法
Math.max(...[14, 3, 77])
// 等同于
Math.max(14, 3, 77);
扩展运算符的应用
- 合并数组
// ES5
[1, 2].concat(more)
// ES6
[1, 2, ...more]
var arr1 = ['a', 'b'];
var arr2 = ['c'];
var arr3 = ['d', 'e'];
// ES5的合并数组
arr1.concat(arr2, arr3);
// [ 'a', 'b', 'c', 'd', 'e' ]
// ES6的合并数组
[...arr1, ...arr2, ...arr3
]// [ 'a', 'b', 'c', 'd', 'e' ]
-
与解构赋值结合
扩展运算符可以与解构赋值结合起来,用于生成数组。
const [first, ...rest] = [1, 2, 3, 4, 5];
first
// 1
rest
// [2, 3, 4, 5]
const [first, ...rest] = [];
first
// undefined
rest
// []
const [first, ...rest] = ["foo"];
first
// "foo"
rest
// []
- 字符串
[...'hello'];
[...'hello'].reverse().join("")
-
实现了Iterator接口的对象
任何Iterator接口的对象,都可以用扩展运算符转为真正的数组。
var nodeList = document.querySelectorAll('div');var array = [...nodeList];
-
Map和Set结构,Generator函数
扩展运算符内部调用的是数据结构的Iterator接口,因此只要具有Iterator接口的对象,都可以使用扩展运算符,比如Map结构。
let map = new Map([
[1, 'one'],
[2, 'two'],
[3, 'three'],
]);
let arr = [...map.keys()]; // [1, 2, 3]
var go = function*(){
yield 1;
yield 2;
yield 3;
};
[...go()]
// [1, 2, 3]
- 严格模式
从ES5开始,函数内部可以设定为严格模式。
function doSomething(a, b) {
'use strict';
// code
}
只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。但可以如下解决(包含在一个立即执行的函数里):
const doSomething = (function () {
'use strict';
return function(value = 42) {
return value;
};
}());
name属性
函数的name属性,返回该函数的函数名。箭头函数
var f = v => v;
上面的箭头函数等同于:
var f = function(v) { return v;};```
如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return语句返回。
由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号。
var getTempItem = id => ({ id: id, name: "Temp" });
箭头函数可以与变量解构结合使用。
const full = ({ first, last }) => first + ' ' + last;
// 等同于
function full(person) {
return person.first + ' ' + person.last;
}
箭头函数的一个用处是简化回调函数。
// 正常函数写法
[1,2,3].map(function (x) { return x * x;});
// 箭头函数写法
[1,2,3].map(x => x * x);
rest用法
const numbers = (...nums) => nums;
numbers(1, 2, 3, 4, 5)// [1,2,3,4,5]
const headAndTail = (head, ...tail) => [head, tail];
headAndTail(1, 2, 3, 4, 5)// [1,[2,3,4,5]]
+ 使用注意点
箭头函数有几个使用注意点。
- 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
- 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
- 不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用Rest参数代替。
- 不可以使用yield命令,因此箭头函数不能用作Generator函数。
上面四点中,第一点尤其值得注意。this对象的指向是可变的,但是在箭头函数中,它是固定的。
function Timer() {
this.s1 = 0;
this.s2 = 0;
// 箭头函数
setInterval(() => this.s1++, 1000);
// 普通函数
setInterval(function () {
this.s2++;
}, 1000);}
var timer = new Timer();
setTimeout(() => console.log('s1: ', timer.s1), 3100);
setTimeout(() => console.log('s2: ', timer.s2), 3100);
// s1: 3// s2: 0
箭头函数可以让this指向固定化,这种特性很有利于封装回调函数
所以,箭头函数转成ES5的代码如下。
// ES6function foo() {
setTimeout(() => {
console.log('id:', this.id); }, 100);
}
// ES5
function foo() {
var _this = this;
setTimeout(function () {
console.log('id:', _this.id);
}, 100);
}
下面是一个部署管道机制(pipeline)的例子,即前一个函数的输出是后一个函数的输入。
const pipeline = (...funcs) => val => funcs.reduce((a, b) => b(a), val);
const plus1 = a => a + 1;
const mult2 = a => a * 2;
const addThenMult = pipeline(plus1, mult2);
addThenMult(5)// 12