本文为电子书《ECMAScript 6 入门》:ES6入门教程学习笔记
1. 函数参数的默认值
ES6开始允许函数设置默认值,直接写在参数后面,并和解构赋值配合起来使用:
function fetch(url, { body = '', method = 'GET', headers = {} }) {
console.log(method);
}
fetch('http://example.com', {})
// "GET"
fetch('http://example.com')
// 报错
需要注意,使用默认值之后,由于函数的length属性的含义是“函数预期传入的参数数量”,因此该属性的值会“失真”。
利用参数默认值,可以指定某一个参数不得省略,如果省略就抛出一个错误。
function throwIfMissing() {
throw new Error('Missing parameter');
}
function foo(mustBeProvided = throwIfMissing()) {
return mustBeProvided;
}
foo()
// Error: Missing parameter
2. rest 参数
是的,经常用到的“…变量名”形式的参数学名叫做rest参数,是一个数组
function add(...values) {
let sum = 0;
for (var val of values) {
sum += val;
}
return sum;
}
add(2, 5, 3) // 10
rest参数必须是最后一个参数,且length属性不会计算。
3. 严格模式
ES2016 做了一点修改,规定只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。
这样规定的原因是,函数内部的严格模式,同时适用于函数体和函数参数。但是,函数执行的时候,先执行函数参数,然后再执行函数体。这样就有一个不合理的地方,只有从函数体之中,才能知道参数是否应该以严格模式执行,但是参数却应该先于函数体执行。
可以通过全局设置严格模式和把函数包在一个无参数的立即执行函数里面绕过这一点。
4. name 属性
ES6 对这个属性的行为做出了一些修改。如果将一个匿名函数赋值给一个变量,ES5 的name属性,会返回空字符串,而 ES6 的name属性会返回实际的函数名。
var f = function () {};
// ES5
f.name // ""
// ES6
f.name // "f"
如果将一个具名函数赋值给一个变量,则 ES5 和 ES6 的name属性都返回这个具名函数原本的名字。
const bar = function baz() {};
// ES5
bar.name // "baz"
// ES6
bar.name // "baz"
Function构造函数返回的函数实例,name属性的值为anonymous。
(new Function).name // "anonymous"
bind返回的函数,name属性值会加上bound前缀。
function foo() {};
foo.bind({}).name // "bound foo"
(function(){}).bind({}).name // "bound "
5. 箭头函数
var f = () => 5;
// 等同于
var f = function () { return 5 };
var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
return num1 + num2;
};
如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return语句返回。由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错。
6. 尾调用优化
尾调用(Tail Call)是指某个函数的最后一步是调用另一个函数。
函数调用会在内存形成一个“调用记录”,又称“调用帧”(call frame),保存调用位置和内部变量等信息。如果在函数A的内部调用函数B,那么在A的调用帧上方,还会形成一个B的调用帧。等到B运行结束,将结果返回到A,B的调用帧才会消失。如果函数B内部还调用函数C,那就还有一个C的调用帧,以此类推。所有的调用帧,就形成一个“调用栈”(call stack)。
尾调用由于是函数的最后一步操作,所以不需要保留外层函数的调用帧,因为调用位置、内部变量等信息都不会再用到了,只要直接用内层函数的调用帧,取代外层函数的调用帧就可以了。
ES6的尾调用在严格模式下开启,正常模式无效。
7. 函数参数的尾逗号
ES2017 允许函数的最后一个参数有尾逗号(trailing comma),这样的规定也使函数参数与数组和对象的尾逗号规则保持一致了。
function clownsEverywhere(
param1,
param2,
) { /* ... */ }
clownsEverywhere(
'foo',
'bar',
);
8. Function.prototype.toString()
ES2019 对函数实例的toString()方法做出了修改。
toString()方法返回函数代码本身,以前会省略注释和空格。
function /* foo comment */ foo () {}
foo.toString()
// function foo() {}
上面代码中,函数foo的原始代码包含注释,函数名foo和圆括号之间有空格,但是toString()方法都把它们省略了。
修改后的toString()方法,明确要求返回一模一样的原始代码。
function /* foo comment */ foo () {}
foo.toString()
// “function /* foo comment */ foo () {}”
9. catch 命令的参数省略
JavaScript 语言的try…catch结构,以前明确要求catch命令后面必须跟参数,接受try代码块抛出的错误对象。
try {
// ...
} catch (err) {
// 处理错误
}
上面代码中,catch命令后面带有参数err。
很多时候,catch代码块可能用不到这个参数。但是,为了保证语法正确,还是必须写。ES2019 做出了改变,允许catch语句省略参数。
try {
// ...
} catch {
// ...
}