函数参数的默认值
-
es6允许为函数的参数设置默认值,用法如下
function log(x, y = 'World') { console.log(x, y); }
参数变量不能再次声明。另外,使用参数默认值的时候,不能有同名参数,但是不用默认值可以有同名参数
参数默认值不是传值的,而是每次都重新计算默认值表达式的值。参数默认值是惰性求值的。
let x = 99; function foo(p = x + 1) { console.log(p); } foo() // 100 x = 100; foo() // 101
-
可以在参数中使用解构赋值
function foo({x, y = 5}) { console.log(x, y); } foo({}) // undefined 5 foo({x: 1}) // 1 5 foo({x: 1, y: 2}) // 1 2 foo() // TypeError: Cannot read property 'x' of undefined
这个例子没有给参数提供默认值,也可以为参数提供默认值
-
一般情况下,定义的默认参数应该是尾参数,因为如果不是尾参数,这个参数无法省略,否则需要输入
undefined
如下:function f(x = 1, y) { return [x, y]; } f() // [1, undefined] f(2) // [2, undefined]) f(, 1) // 报错 f(undefined, 1) // [1, 1]
-
指定了默认值参数之后,函数的
length
属性应该返回的是没有指定默认值的参数个数但是如果指定的默认值不是尾参数,那么
length
属性不再计算后面的参数 -
设置了参数的默认值,参数会形成一个单独的作用域
如果在使用参数赋值之前,用
var
声明了一个变量,会出现暂时性死区,如下:var x = 1; function foo(x = x) { //相当于let x = x // ... } foo() // ReferenceError: x is not defined
如果参数是一个函数,那么这个函数的作用域也应该遵守规则
var x = 1; function foo(x, y = function() { x = 2; }) { var x = 3; y(); console.log(x); } foo() // 3 x // 1
rest参数
rest参数的形式为...变量名
,用于获取函数的多余参数,可以这样使用
function add(...values) {
let sum = 0;
for (var val of values) {
sum += val;
}
return sum;
}
**注意:**rest参数只能作为最后一个参数,且函数的length属性不包括rest参数
严格模式
函数内部不能使用严格模式的情况:参数使用了默认值、解构赋值、扩展运算符
避免以上问题的方法:
-
设定全局性的严格模式
'use strict'; function doSomething(a, b = a) { // code }
-
把函数包含在一个无参数的立即执行的函数里面
const doSomething = (function () { 'use strict'; return function(value = 42) { return value; }; }());
name属性
函数的name属性返回函数名。
将函数赋值给变量的两种情况:
-
将匿名函数赋值给一个变量,返回实际的函数名,即变量名
-
将具名函数赋值给一个变量:返回具名函数名
Function
构造函数返回的函数实例,name
属性的值为anonymous
。
(new Function).name // "anonymous"
bind
返回的函数,name
属性值会加上bound
前缀。
function foo() {};
foo.bind({}).name // "bound foo"
(function(){}).bind({}).name // "bound "
箭头函数
- 形式:
var f = v => v;
// 等同于
var f = function (v) {
return v;
};
-
参数:如果箭头函数不需要或者需要多个参数,可以用圆括号吧参数括起来
-
**注意:**如果要直接返回一个对象,那么必须在对象外面加上一个括号
-
与变量结构结合:
const full = ({ first, last }) => first + ' ' + last; // 等同于 function full(person) { return person.first + ' ' + person.last; }
-
使用注意:
-
函数体内的
this
对象,就是定义时所在的对象,而不是使用时所在的对象。 -
不可以当作构造函数,也就是说,不可以使用
new
命令,否则会抛出一个错误。 -
不可以使用
arguments
对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。 -
不可以使用
yield
命令,因此箭头函数不能用作 Generator 函数。
-
-
箭头函数还有一个功能,就是可以很方便地改写 λ 演算。
// λ演算的写法 fix = λf.(λx.f(λv.x(x)(v)))(λx.f(λv.x(x)(v))) // ES6的写法 var fix = f => (x => f(v => x(x)(v))) (x => f(v => x(x)(v)));
尾调用优化
-
尾调用就是某个函数的最后一步是调用另外一个函数,即在函数的最后一步操作
-
优化:到了尾调用的时候,只保留内层函数的调用帧,而不保留外层函数的调用帧,因为内部变量等信息都不会用到了
只有当不再用到外层函数的内部变量时,内层函数的调用帧才会取代外层函数的调用帧,否则无法优化
-
尾递归:尾调用自身就是尾递归
好处:只存在一个调用栈,所以永远不会发生“栈溢出”错误
-
严格模式:尾调用优化只在严格模式下开启
-
在正常模式下实现尾调用优化:蹦床函数可以将递归执行转为循环执行
function trampoline(f) { while (f && f instanceof Function) { f = f(); } return f; }
函数参数的尾逗号
函数的最后一个参数允许有尾逗号
Function.prototype.toString()
函数实例的toString()
方法返回函数代码本身,包括注释和空格
catch 命令的参数省略
try...catch
结构中,catch
代码块可能用不到这个参数,可以把这个参数是省略