函数名

  • 函数名是指向函数的指针,它们跟其他包含对象指针的变量具有相同的行为。
  • 一个函数可以有多个名称。
  • ES6所有函数对象都会暴露一个只读的name属性。
    • 包含关于函数的信息;
    • 多数情况下,这个属性中保存的就是一个函数标识符,或者说是一个字符串化的变量名;
    • 函数没有名称会如实显示成空字符串;
    • 使用Function构造函数创建的,则会标识成“anonymous”。
1
2
3
4
5
6
7
8
function foo() {} 
let bar = function() {};
let baz = () => {};
console.log(foo.name); // foo
console.log(bar.name); // bar
console.log(baz.name); // baz
console.log((() => {}).name); //(空字符串)
console.log((new Function()).name); // anonymous
  • 如果函数是一个 获取函数、设置函数,或者使用bind()实例化,那么标识符前面会加上一个前缀。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function foo() {} 
console.log(foo.bind(null).name); // bound foo
let dog = {
years: 1,
get age() {
return this.years;
},
set age(newAge) {
this.years = newAge;
}
}
let propertyDescriptor = Object.getOwnPropertyDescriptor(dog, 'age');
console.log(propertyDescriptor.get.name); // get age
console.log(propertyDescriptor.set.name); // set age

函数参数

  • ECMAScript函数的参数在内部表现为一个数组。

  • 函数被调用时总会接收一个数组,但函数并不关心这个数组中包含什么。

  • 不存在验证命名参数的机制。

  • arguments对象是一个类数组对象

    • 可以使用中括号语法访问其中的元素。
  • 通过arguments.length可以确定参数个数。

1
2
3
4
5
6
function howManyArgs() { 
console.log(arguments.length);
}
howManyArgs("string", 45); // 2
howManyArgs(); // 0
howManyArgs(12); // 1
  • arguments对象可以跟命名参数一起使用。
1
2
3
4
5
6
7
function doAdd(num1, num2) { 
if (arguments.length === 1) {
console.log(num1 + 10);
} else if (arguments.length === 2) {
console.log(arguments[0] + num2);
}
}

箭头函数中的参数

  • 箭头函数的参数不能使用arguments关键字访问,只能通过定义的命名参数访问。
1
2
3
4
5
6
7
8
function foo() { 
console.log(arguments[0]);
}
foo(5); // 5
let bar = () => {
console.log(arguments[0]);
};
bar(5); // ReferenceError: arguments is not defined
  • 虽然箭头函数中没有arguments对象,但可以在包装函数中把它提供给箭头函数。
1
2
3
4
5
6
7
function foo() { 
let bar = () => {
console.log(arguments[0]); // 5
};
bar();
}
foo(5);

默认参数值

  • ES6中只要在函数定义中的参数后面用就可以为参数赋一个默认值。
1
2
3
4
5
function makeKing(name = 'Henry') { 
return `King ${name} VIII`;
}
console.log(makeKing('Louis')); // 'King Louis VIII'
console.log(makeKing()); // 'King Henry VIII'
  • 给参数传undefined相当于没有传值。
1
2
3
4
5
6
function makeKing(name = 'Henry', numerals = 'VIII') { 
return `King ${name} ${numerals}`;
}
console.log(makeKing()); // 'King Henry VIII'
console.log(makeKing('Louis')); // 'King Louis VIII'
console.log(makeKing(undefined, 'VI')); // 'King Henry VI'
  • 在使用默认参数时,arguments 对象的值不反映参数的默认值,只反映传给函数的参数。
1
2
3
4
5
6
function makeKing(name = 'Henry') { 
name = 'Louis';
return `King ${arguments[0]}`;
}
console.log(makeKing()); // 'King undefined'
console.log(makeKing('Louis')); // 'King Louis'

默认参数作用域与暂时性死区

  • 因为在求值默认参数时可以定义对象,也可以动态调用函数,所以函数参数肯定是在某个作用域中求值的。
  • 给多个参数定义默认值实际上跟使用let关键字顺序声明变量一样。
  • 参数初始化顺序遵循“暂时性死区”规则,即前面定义的参数不能引用后面定义的
1
2
3
4
5
6
7
8
9
// 调用时不传第一个参数会报错
function makeKing(name = numerals, numerals = 'VIII') {
return `King ${name} ${numerals}`;
}
// 调用时不传第二个参数会报错
function makeKing(name = 'Henry', numerals = defaultNumeral) {
let defaultNumeral = 'VIII';
return `King ${name} ${numerals}`;
}

参数扩展与收集

扩展参数

  • **…**等价于apply()方法
1
2
3
4
5
6
7
8
9
10
11
12
function getProduct(a, b, c = 1) { 
return a * b * c;
}
let getSum = (a, b, c = 0) => {
return a + b + c;
}
console.log(getProduct(...[1,2])); // 2
console.log(getProduct(...[1,2,3])); // 6
console.log(getProduct(...[1,2,3,4])); // 6
console.log(getSum(...[0,1])); // 1
console.log(getSum(...[0,1,2])); // 3
console.log(getSum(...[0,1,2,3])); // 3

收集参数

  • 使用扩展操作符把不同长度的独立参数组合为一个数组。
1
2
3
4
5
6
function getSum(...values) { 
// 顺序累加 values 中的所有值
// 初始值的总和为 0
return values.reduce((x, y) => x + y, 0);
}
console.log(getSum(1,2,3)); // 6
  • 收集参数的前面如果还有命名参数,则只会收集其余的参数;如果没有则会得到空数组。
  • 收集参数的结果可变,只能把它作为最后一个参数。
1
2
3
4
5
6
7
8
9
10
// 不可以
function getProduct(...values, lastValue) {}
// 可以
function ignoreFirst(firstValue, ...values) {
console.log(values);
}
ignoreFirst(); // []
ignoreFirst(1); // []
ignoreFirst(1,2); // [2]
ignoreFirst(1,2,3); // [2, 3]
  • 使用收集参数并不影响arguments对象。
1
2
3
4
5
6
function getSum(...values) { 
console.log(arguments.length); // 3
console.log(arguments); // [1, 2, 3]
console.log(values); // [1, 2, 3]
}
console.log(getSum(1,2,3));