ES6入门函数篇(一)之函数形参的默认值

本文介绍了在ES6中引入的函数默认参数值特性,对比了ES5中模拟默认参数的常见方法及其局限性,详细阐述了ES6中如何设置默认参数、默认参数对arguments对象的影响,以及默认参数表达式的使用规则,包括临时死区的概念。

一、在ECMAScript5中模拟默认参数

JavaScript函数有一个特别的地方,无论在函数定义中声明了多少参数,都可以传入任意数量的参数,也可以在函数定义时添加针对参数数量的处理逻辑,当已定义的形参无对应的传入参数时,为其指定一个默认值。

在ES6之前,不能直接为函数的参数指定默认值,只能采用变通的方法。

function makeRequest(url,timeout,callback){
    timeout = timeout||2000;
    callback = callback||function(){};

    //函数的其余部分
}

在这个例子中,timeoutcallback为可选参数,如果不传入相应的参数,系统就会自己给他们赋一个默认值。在含有逻辑或者操作符的表达式中,前一个操作符的值为false时,总会返回后一个值。对于函数的命名参数,如果不显式传值,则其值默认为undefined。因此我们经常用逻辑或者操作符来为缺失的参数提供默认值。然而这个方法是有缺陷的,如果我们想给makeRequest函数的第二个形参timeout传入值0,即使这个值是合法的,也会被视为一个false值,并最终将timeout赋值为2000.

我们可以采取更安全的选择,即通过typeof检查参数类型,如下例所示:

function makeRequest(url,timeout,callback){
    timeout = (typeof timeout !== "undefined")? timeout :2000;
    callback = (typeof callback !== "undefined")?callback :function(){};
    //函数的其余部分   
}

尽管这种方法更安全,但是需要额外的代码来执行这种非常基础的操作,这是一种常见的用法,在流行的JavaScript库中很多都采用了这种写法来进行模式补全。

二、在ECMAScript 6中的默认参数值

ECMAScript6简化了为形参提供默认值的过程,如果没为参数传入值则为其提供一个初始值。
如:

function makeRequest(url,timeout = 2000,callback = function(){}){
    //the rest
}

在这个例子中,只有第一个参数被认为总是要为其传入值的,其他两个参数都有默认值,而且不需要添加任何校验值是否缺失的代码,所以函数会更简洁。

//使用参数timeout和参数callback的默认值
makeRequest("/foo");

//使用参数callback的默认值
makeRequest("/foo",500);

//不使用默认值
makeRequest("/foo",500,function(params){
    doSomething(body);
});

在声明函数时,可以为任意参数指定默认值,在已指定的参数后面就可以继续声明无默认值参数。

function makeRequest(url,timeout = 2000,callback){
    //函数的其余部分
}

在上面的例子中,只有当不为第二个参数传入值或者主动为第二个参数传入undefined时才会使用timeout的默认值

//使用timeout的默认值
makeRequest("/foo",undefined,function(){

})

//使用timeout的默认值
makeRequest("/foo");

//不使用timeout的默认值
makeRequest("/foo",null,function(body){

});

对于默认参数值,null是一个合法的值,也就是说第三次调用makeRequest方法的时候,不使用timeout的默认值,其值最终为null

三、 默认参数值对arguments对象的影响

ES5非严格模式

在此模式下,命名参数的变化会同步更新到arguments对象里面。

function mixArgs(first,second){
    console.log(first===arguments[0]);
    console.log(second===arguments[1]);
    first = "c";
    second = "d";
    console.log(first === arguments[0]);
    console.log(second === arguments[1]);
}

mixArgs("a","b");

输出为

true
true
true
true

firstsecond被赋新值时,arguments[0]arguments[1]也随之改变。

ES5严格模式

在此种模式下,无论参数如何变化,arguments对象不再随之改变。

function mixArgs(first,second){
    "use strict";
    console.log( first === arguments[0]);
    console.log( second === arguments[1]);
    first = "c";
    second = "d";
    console.log(first === arguments[0]);
    console.log(second === arguments[1]);
}

mixArgs("a","b");

输出

true
true
false
false

ES6

在ES6中,如果一个函数使用了默认参数值,则无论是否显式定义了严格模式,arguments对象的行为都将与ES5严格模式下保持一致。

四、默认参数表达式

非原始值传参

可以通过函数执行来得到默认参数的值

function getValue(){
    return 5;
}

function add (first ,second = getValue()){
    return first + second;
}

console.log(add(1,1));
console.lg(add(1));

在此例中,如果不传入second参数,就会调用getValue()函数来得到正确的默认值。当然,第一次解析函数的时候,不会调用getValue()函数。
注意:如果将getValue()写成getValue,那么最终传入的是对函数的引用,而不是对函数调用的结果。

因为默认参数在函数调用中求值,可以使用先定义的参数作为后定义参数的默认值

function add(first ,second = first){
    return first + second ;
}

console.log(add(1,1));  //2
console.log(add(1));  //2

在引用参数默认值时,只允许引用前面参数的值,即先定义的参数才能访问后定义的参数。

function add(first = second ,second ){
    return first + second;
}

console.log(add(1,1));//2
console.log((undefined,1));   //抛出错误

第二个调用会抛出错误,因为secondfirst晚定义,因此其不能作为first的默认值。

默认参数的临时死区

letconst一样,默认参数也有同样的临时死区,在这里参数不可访问。

function getValue(value){
    return value + 5;
}

function add(first,second = getValue(first)){
    return first + second ;
}

console.log(add(1,1));
console.log(add(1));

其实调用的过程相当于下面代码

//表示调用add(1,1)时的JavaScript代码
let first = 1;
let second = 1;

//表示调用add(1)时的JavaScript代码
let first = 1;
let second = getValue(first);

当初次执行函数add()时,绑定firstsecond被添加到一个专属于函数参数的临时死区。由于初始化second时,first已经被初始化,所以它可以访问first的值,但是反过来就错了。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值