函数参数的默认值
基本用法
- 函数变量是默认声明的,所以不能用 let 或 const 再次声明
- 参数默认值不是传值的(计算表达式),每次都会重新计算默认值表达式的值
- 默认值的参数不是尾参数时,不能省略该参数而不省略后边的参数,除非显示输入 undefined
- 参数传入 undefined 时才能触发该参数的默认值, null 不可以
function foo(x = 3) {
// 以下两个语句都会报错
let x = 1;
const x = 2;
}
let x = 99;
function bar(p = x + 1) {
console.log(p);
}
bar(); // 100
x = 100;
bar(); // 101
function too(x, y = 5, z) {
return [x, y, z];
}
too(); // [undefined, 5, undefined]
too(1); // [1, 5, undefined]
too(1, , 2); // 报错
too(1, undefined, 2); // [1, 5, 2]
function far(x = 5, y = 6) {
return [x, y];
}
far(undefined, null); // [5, undefined]
函数的 length 属性
指定默认值以后,函数的 length 属性将返回没有指定默认值的参数个数。若设置默认值的参数不是尾参数,那么后面的参数也不计入 length 属性。同理, rest 参数不会计入 length 属性。
(function(a, b, c = 2) {}).length // 2
(function (a, b = 2, c) {}).length // 1
(function(...args) {}).length // 0
严格模式
ES5开始,函数内部可以设定为严格模式。ES6规定只要函数参数使用了默认值、解构赋值或扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错
name 属性
函数的 name 属性返回该函数的函数名。
如果将一个具名函数赋值给一个变量, name 属性返回具名函数原来的名字。
Function 构造函数返回的函数实例, name 属性的值为 anonymous。
bind 返回的函数, name 属性值会加上 bound 前缀。
var f = function () {};
f.name // ES5——"",ES6——"f"
const bar = function baz() {};
bar.name // "baz"
(New Function).name // anonymous
function foo() {}
foo.bind({}).name // "bound foo"
(function() {}).bind({}).name // "bound"
箭头函数
箭头函数使用时注意事项:
- 函数体内的 this 对象就是定义时所在的对象,而不是使用时所在的对象。箭头函数没有自己的 this 对象,导致内部的 this 就是外层代码的 this
- 不可以当做构造函数
- 不可以使用 arguments 对象,该对象在函数体内不存在
- 不可以使用 yield 命令
函数绑定运算符
"::"——函数绑定运算符,双冒号左边是一个对象,右边是一个函数。表示将左边的对象作为上下文环境(即 this 对象)绑定到右边的函数上。如果双冒号左边为空,右边是一个对象的方法,表示将该方法绑定在该对象上。
foo::bar;
// 等同于
bar.bind(foo);
obj::obj.foo;
// 等同于
::obj.foo;
尾调用优化
尾调用是指某个函数的最后一步是调用另一个函数。尾调用优化就是只保留内层函数的调用帧。尾调用优化只在严格模式下开启。
// 尾调用
function f(x) {
return g(x);
}
function g(x) {
if (x > 0) {
return m(x);
}
return n(x);
}
// 以下三种情况不是尾调用
// 情况一,调用函数 g 之后还用赋值操作
function f(x) {
let y = g(x);
return y;
}
// 情况二,调用后还有操作
function f(x) {
return g(x) + 1;
}
// 情况三,等同于
// function f(x) {
// g(x);
// return undefined;
// }
function f(x) {
g(x);
}