- ES6允许为函数的参数设置默认值,即直接写在参数定义的后面。
function log(x, y = 'world') {
console.log(x, y)
}
log('Hello') // Hello world
log('Hello', 'China') // Hello China
log('Hello', '') // Hello
参数变量是默认声明的,所以不能用let或const再次声明。
function foo(x=5) {
let x = 1 // error
const x = 1 // error
}
参数默认值不是传值的,而是每次会重新计算默认值表达式的值,即惰性求值。
let x = 99
function foo(p = x + 1) {
console.log(p)
}
foo() // 100
x = 100
foo() // 101
- 参数默认值可以与解构赋值的默认值结合使用,避免函数调用时未提供参数导致变量
x和y无法生成,从而报错。
function foo({x, y = 5}) {
console.log(x, y)
}
foo({}) // undefined 5
foo() // TypeError: Cannot read property 'x' of undefine
function foo({x, y = 5} = {}){
console.log(x, y)
}
foo() // undefined 5
- 函数的
length属性将返回没有指定默认值的参数个数。即如果指定了默认值,length属性将失真。
(function (a) {}).length // 1
(function (a - 5) {}).length // 0
length属性的含义是:该函数预期传入的参数个数。某个参数指定默认值后,预期传入的参数个数就不包括这个参数了。
(function (...arg) {}).length // 0
如果设置默认值的参数不是尾参,那么length属性也不再计入其后面的参数。
(function (a = 0, b) {}).length // 0
- 函数的参数会形成一个单独的作用域。
let x = 1
function (y = x) {
let x = 2
console.log(y)
}
f() // 1
在y = x的作用域里,变量x没有定义,所以会指向外层的变量x(如果全局变量x不存在会报错),函数调用时,函数体内的局部变量x不会影响默认值变量x。
- ES6引入rest参数(形式为
...变量名),rest参数是一个数组,且只能是最后一个参数(否则会报错)。
function push(arr, ...items) {
items.forEach(function(item) {
arr.push(item)
console.log(item)
})
}
var a = []
push(a, 1, 2, 3)
- 箭头函数中大括号会被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错。
let getItem = id => ({id: id})
使用注意点:
(1)箭头函数没有自己的this对象,内部的this就是定义时上层作用域中的this。
(2)不能当作构造对象。
(3)不能使用argumens对象,因为它在函数体中不存在,可以用rest参数替代。
- 尾调用是指某个函数的最后一步是调用另一个函数。
function f(x) {
return g(x)
}
尾调用不一定出现在函数尾部,只要是最后一步操作即可。
funtion f(x) {
if (x > 0) {
return m(x)
}
return n(x)
}
上面代码中,函数m和n都属于尾调用。
函数调用会在内存中形成一个调用记录,即调用帧,保存了调用位置和内部变量等信息。尾调用优化是指只保存内层函数的调用帧,这可以大大节省内存。
function f() {
let m = 1
let n = 2
return g(m + n)
}
f()
// 等同于
function f() {
return g(3)
}
f()
// 等同于
g(3)
但只有不再用到外层函数的内部变量,内层函数的调用帧才会取代外层函数的调用帧。
function addOne(a) {
var one = 1
function inner(b) {
return b + one
}
return inner(a)
}
上述函数不会进行尾调用优化,因为内层函数inner用到了外层函数addOne的内部变量one。
- 尾调用自身称为
尾递归,由于只存在一个调用帧,所以永远不会发生“栈溢出”错误。
function factorial(n, total) {
if (n === 1) return total
return factorial(n - 1 ,n * total)
}
- 函数实例的
toString()返回函数代码本身。
function /* foo comment */ foo () {}
foo.toString()
// "function /* foo comment */ foo () {}"
- ES2019允许
catch语句省略参数。
try {
// ...
} catch {
// ...
}