ES2015函式擴充套件
阿新 • • 發佈:2019-02-14
基本用法
在ES6之前,不能直接為函式的引數指定預設值,只能採用變通的方法
function log(x, y){
y = y || 'world';
console.log(x, y);
}
log('Hello'); // Hello world
log('hello', 'china'); // hello china
log('hello', ''); // hello world
這種寫法的缺點在於,如果引數y
賦值了,但是對應的布林值為false
,則該賦值不起作用。就像上面最後一行,引數y
等於空字元,結果該改為預設值。
為了避免這個問題,通常需要先判斷一下引數y
是否被賦值,如果沒有,再等於預設值
if (typeof y === 'undefined') {
y = 'world';
}
ES6允許為函式的引數設定預設值,即直接寫在引數定義的後面
function log(x, y = 'World'){
console.log(x, y);
}
log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello
可以看到,ES6的寫法比ES5簡潔許多。
引數變數是預設宣告的,所以不能用let
或const
再次宣告
function foo(x = 5) {
let x = 1; // error
const x = 2; // error
}
與解構賦值預設值結合使用
function foo({x, y = 5}){
console.log(x, y);
}
foo({}); // undefined,5
foo({x:1}); // 1,5
foo(); // TypeError: Cannot read property 'x' of undefined
上面的程式碼使用了物件的解構賦值預設值,而沒有使用函式引數的預設值。只有當函式foo
的引數是一個物件時,變數x
和y
才會通過解構賦值而生成。否則會報錯。
引數預設值的位置
通常情況下,定義了預設值的引數,應該是函式的尾引數。因為這樣比較容易看出來,到底省略了那些引數。如果非尾部的引數設定預設值,實際上這個引數是沒法省略的。
// 例子1
function f(x=1, y){
return [x, y];
}
f(); // [1, undefined]
f(2); // [2, undefined]
f(, 1); // 報錯
f(1, 1); // [1, 1]
// 例子2
function f(x, y=5, z){
return [x, y, z];
}
f() // [undefined, 5, undefined]
f(1) // [1, 5, undefined]
f(1, 2) // 報錯
f(1, undefined, 2) // [1, 5, 2]
函式的length屬性
指定了預設值以後,函式的length
屬性,將返回沒有指定預設值的引數個人。也就是說,指定了預設值,length
屬性將失真。
(function(a){}).length // 1
(function(a=5){}).length // 0
(function(a, b, c=5){}).length // 2
作用域
一個需要注意的地方是,如果引數預設值是一個變數,則該變數所處的作用域,與其他變數的作用域規則是一樣的,即先是當前函式的作用域,然後才是全域性作用域
var x = 1;
function f(x, y=x){
console.log(y);
}
f(2); // 2
上面的程式碼中,引數y
的預設值等於x
。呼叫時,由於函式的作用域內部的變數x
已經生成,所以y
等於引數x
,而不是全域性變數x
。
如果呼叫時,函式的作用域內部的變數x
沒有生成,結果就會不一樣
let x = 1;
function f(y=x){
let x = 2;
console.log(y);
}
f() // 1
上面的程式碼中,函式呼叫時,y
的預設值變數x
尚未在函式內部生成,所以x
指向全域性變數。
如果此時,全域性變數x
不存在,就會報錯
function f(y = x) {
let x = 2;
console.log(y);
}
f() // ReferenceError: x is not defined