默认参数
-
示例
// 当没有传入足够的参数时,会使用默认参数,如无默认参数,则为undefined function test(arg1, arg2 = '', arg3 = 0, arg4) {}
-
对于默认参数值,null是一个合法值
-
ES5下函数arguments的特性
// 非严格模式 function mixArgs(first, second) { console.log(first === arguments[0]); // true console.log(second === arguments[1]); // true first = 'c'; second = 'd'; console.log(first === arguments[0]); // true console.log(second === arguments[1]); // true } mixArgs('a', 'b'); // 严格模式 function mixArgs(first, second) { 'use strict'; console.log(first === arguments[0]); // true console.log(second === arguments[1]); // true first = 'a'; second = 'b'; console.log(first === arguments[0]); // true console.log(second === arguments[1]); // true first = 'c'; second = 'd'; console.log(first === arguments[0]); // false console.log(second === arguments[1]); // false } mixArgs('a', 'b');
-
ES6环境下,如果函数采用了默认参数值,则无论是否显示采用严格模式,其arguments行为都与ES5的严格模式保持一致
function mixArgs(first, second = 'b') { console.log(first === arguments[0]); // true console.log(second === arguments[1]); // false first = 'c'; second = 'd'; console.log(first === arguments[0]); // false console.log(second === arguments[1]); // false } mixArgs('a'); // true // false // false // false mixArgs('a', 'b'); // true // true // false // false
-
注意:如果使用了默认参数,且在函数内部显式使用严格模式,会报错
-
默认参数表达式:默认参数可以是函数的调用
function getValue() { return 5; } function add(first, second = getValue()) { return first + second; } console.log(add(1, 1)); // 2 console.log(add(1)); // 6
-
注意:上面的例子中,add首次解析不会调用getValue函数,若传入second参数也不会调用getValue函数,只有未传second参数时才会调用getValue函数
-
正因为默认参数是在函数调用时求职,所以可以使用先定义的参数作为后定义的参数的默认值
function add(first, second = first) { return first + second; } console.log(add(1, 1)); // 2 console.log(add(1)); // 2
-
上面的示例中,如果first参数以second参数为默认值会报错,原因是second尚在临时死区,未被初始化。
不定参数
-
在函数的命名参数前添加三个点(…)就标明这是一个不定参数,该参数为一个数组,包含着自它之后传入的所有参数,通过这个数组名即可逐一访问里面的参数
function pick(object, ...keys) { let result = Object.create(null); for (let i = 0, len = keys.length; i < len; i++) { result[keys[i]] = object[keys[i]]; } return result; }
-
函数的length属性值统计的是函数命名参数的数量,不定参数的加入不会影响length的属性值,即以上的例子的length值为1,即只有object这一个命名参数
-
arguments对象总是包含所有传入函数的参数
-
每个函数最多只能声明一个不定参数,而且一定要放在所有参数的末尾
展开运算符
let values = [25, 50, 75, 100];
console.log(Math.max(...values)); // 100
函数的多重用途
-
JavaScript函数有两个不同的内部方法:[[Call]]和[[Construct]]。当通过new关键字调用函数时,执行的是[[Construct]]函数,它负责创建一个通常被称作实例的新对象,将this绑定到实例上,然后执行函数体;如果不通过new关键字调用函数,则执行[[call]]函数,从而直接执行代码中的函数。具有[[Construct]]方法的函数称为构造函数。
-
注意:不是所有的函数都有[[Construct]]方法,例如箭头函数
-
判断函数是否通过new关键字调用
function Person(name) { if (this instanceof Person) { this.name = name; // 通过new关键字调用 } else { throw new Error("必须通过new关键字来调用Person") } } var person = new Person("Crane"); var notAPerson = Person("notAPerson"); // 抛出异常 // 此方法有不安全的漏洞,函数本身无法区分是通过Person.call()(或者是Person.apply())还是new关键字调用得到的Person实例 var person = new Person("Crane"); var notAPerson = Person.call(person, "notAPerson"); // 有效
-
原属性(Metaproperty)new.target
function Person(name) { // 以下两种判断方式皆可 // if (typeof new.target !== 'undefined') { if (new.target === Person) { this.name = name; } else { throw new Error('必须通过new关键字来调用Person'); } } function AnotherPerson(name) { Person.call(this, name); } var person = new Person('Crane'); var anotherPerson = new AnotherPerson('Crane');
在函数外使用new.target是一个语法错误