函数的扩展
函数参数的默认值基本用法:
(1)ES6 之前,不能直接为函数的参数指定默认值,只能采用变通的方法。
```
(2)与解构赋值默认值结合使用
```
(3)参数默认值的位置
通常情况下,定义了默认值的参数,应该是函数的尾参数。因为这样比较容易看出来,到底省略了哪些参数。如果非尾部的参数设置默认值,实际上这个参数是没法省略的。
```
(4)函数的 length 属性
指定了默认值以后,函数的`length`属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后,`length`属性将失真。
(function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2
```
- fn.length 返回形参个数
- arguments.length 返回实参个数
(5)作用域
一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域。等到初始化结束,这个作用域就会消失。这种语法行为,在不设置参数默认值时,是不会出现的。
5.1代码中,参数`y`的默认值等于变量`x`。调用函数`f`时,参数形成一个单独的作用域。在这个作用域里面,默认值变量`x`指向第一个参数`x`,而不是全局变量`x`,所以输出是`2`。
```
5.2代码中,函数`f`调用时,参数`y = x`形成一个单独的作用域。这个作用域里面,变量`x`本身没有定义,所以指向外层的全局变量`x`。函数调用时,函数体内部的局部变量`x`影响不到默认值变量`x`。
```
5.3代码中,参数`x = x`形成一个单独作用域。实际执行的是`let x = x`,由于暂时性死区的原因,这行代码会报错”x 未定义“。
```
5.4如果将`var x = 3`的`var`去除,函数`foo`的内部变量`x`就指向第一个参数`x`,与匿名函数内部的`x`是一致的,所以最后输出的就是`2`,而外层的全局变量`x`依然不受影响。
```
(6)rest 参数
ES6 引入 rest 参数(形式为`...变量名`),用于获取函数的多余参数,这样就不需要使用`arguments`对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
`arguments`对象不是数组,而是一个类似数组的对象。所以为了使用数组的方法,必须使用`Array.prototype.slice.call`先将其转为数组。rest 参数就不存在这个问题,它就是一个真正的数组,数组特有的方法都可以使用。下面是一个利用 rest 参数改写数组`push`方法的例子。
注:rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。
// 报错
function f(a, ...b, c) {
// ...
}
注:函数的`length`属性,不包括 rest 参数。
(function(a) {}).length // 1
(function(...a) {}).length // 0
(function(a, ...b) {}).length // 1
```
(7)严格模式
从 ES5 开始,函数内部可以设定为严格模式。ES2016 做了一点修改,规定只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错
(8)name 属性
返回函数名:
function foo() {}
console.log(foo.name) // foo
var f = function () {};
console.log(f.name) // f
```
(9)箭头函数基本用法
ES6 允许使用“箭头”(`=>`)定义函数。
例如:var fn = v => v; 箭头函数等同于:var fn = function(v) {return v;};
注:如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。
```
如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用`return`语句返回。
var sum = (num1, num2) => { return num1 + num2; }
```
由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错。
// 报错
let getTempItem = id => { id: id, name: "Temp" };
// 不报错
let getTempItem = id => ({ id: id, name: "Temp" });
```
箭头函数使用注意点:
1. 函数体内的`this`对象,就是定义时所在的环境,而不是使用时所在的环境。
2. 不可以当作构造函数,也就是说,不可以使用`new`命令,否则会抛出一个错误。
3. 不可以使用`arguments`对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
4. 不可以使用`yield`命令,因此箭头函数不能用作 Generator 函数。
`this`指向的固定化,并不是因为箭头函数内部有绑定`this`的机制,实际原因是箭头函数根本没有自己的`this`,导致内部的`this`就是外层代码块的`this`。正是因为它没有`this`,所以也就不能用作构造函数。
箭头函数转成 ES5 的代码如下:
转换后的 ES5 版本清楚地说明了,箭头函数里面根本没有自己的this,而是引用外层的this。
```
由于箭头函数没有自己的`this`,所以当然也就不能用`call()`、`apply()`、`bind()`这些方法去改变`this`的指向。
```
(10)函数参数的尾逗号
ES2017 [允许](https://github.com/jeffmo/es-trailing-function-commas)函数的最后一个参数有尾逗号(trailing comma)。
这样的规定也使得,函数参数与数组和对象的尾逗号规则,保持一致了。