ES6 参数


我们知道,参数分为形参(parameter)和实参(argument),形参是指函数定义时的参数,实参是指真正传入函数的参数。下面,我们将从多个角度来分析,ES6中,参数的一些行为。


参数的默认值####

函数中参数的默认值这一设定尤为重要,不仅可以避免一些不必要的错误,还能简化过程,好处很多。下面我们来看看,在ES5中,参数的默认值是如何设定的:

function foo(num1,num2){
    num1 = num1||10;
    num2 = num2||5;
    console.log(num1,num2);
}
foo(1,2)               //1,2
foo(1)                 //1,5
foo(undefined,2)       //10,2

通常是用||运算符来做默认值处理,判断传入的参数的真假,如果为真,用传入的参数,为假值,用默认的参数。当然,这种方式有一定的漏洞的,比如当我们传入的参数是0的时候。

foo(0,2)       //10,2

就有问题了。其实得到这个结果也是意料之中的,0的隐式转换为布尔值的结果就是false,那么应该如何改进呢?在ES5中,人们是这么处理的:

function foo(num1,num2){
    num1 = num1 !== undefined?num1:10;
    num2 = num2 !== undefined?num2:5;
    console.log(num1,num2);
}
foo(1,2)               //1,2
foo(1)                 //1,5
foo(undefined,2)       //10,2
foo(0,2)               //0,2

确实,这样写看起来就万无一失了,但是显得太臃肿了不是吗,在ES6中,我们可以直接使用如下方式设置默认值:

function foo(num1=10,num2=5){
    console.log(num1,num2);
}
foo(1,2)               //1,2
foo(1)                 //1,5
foo(undefined,2)       //10,2
foo(0,2)               //0,2

下面,让我们来思考一个问题,默认值到底是如何影响参数的呢?传入的参数我们知道,可以通过arguments对象获得,那么,如果传入的参数在函数体内被改变,那么对应的arguments也会改变吗?请看下面的例子:

function foo(num1,num2){
    console.log(num1 === arguments[0]);
    console.log(num2 === arguments[1]);
    num1 = 'a';
    num2 = 'b';
    console.log(num1 === arguments[0]);
    console.log(num2 === arguments[1]);
}
foo(1,2);              //true
                       //true
                       //true
                       //true

由此可以看出,在参数被修改的时候,arguments也会跟着修改,并且保持与修改的参数一致。这是在非严格模式下,那么在严格模式下呢?请看如下例子:

'use strict'
function foo(num1,num2){
    console.log(num1 === arguments[0]);
    console.log(num2 === arguments[1]);
    num1 = 'a';
    num2 = 'b';
    console.log(num1 === arguments[0]);
    console.log(num2 === arguments[1]);
}
foo(1,2);              //true
                       //true
                       //false
                       //false

正如你所看到的,在严格模式下,arguments并没有修改。那么,在ES6中的默认值呢?看如下例子:

function foo(num1,num2=2){
    console.log(arguments.length);
    console.log(num1 === arguments[0]);
    console.log(num2 === arguments[1]);
    num1 = 'a';
    num2 = 'b';
    console.log(num1 === arguments[0]);
    console.log(num2 === arguments[1]);
}
foo(1);                //1
                       //true
                       //false
                       //false
                       //false

在严格模式下:

'use strict'
function foo(num1,num2=2){
    console.log(arguments.length);
    console.log(num1 === arguments[0]);
    console.log(num2 === arguments[1]);
    num1 = 'a';
    num2 = 'b';
    console.log(num1 === arguments[0]);
    console.log(num2 === arguments[1]);
}
foo(1);                //1
                       //true
                       //false
                       //false
                       //false

通过arguments.length,传入的参数个数是1,我们可以明白,其实arguments真正收集的不是默认值,而是输入的参数,并且只要加入了默认值,无论是在严格模式,还是非严格模式,参数arguments都不会改变,只会保留初始值,也就是函数调用的时候传入的最初的值。

不仅如此

ES6默认值的用法不仅如此,它不仅可以传入原始值,还可以是函数调用,甚至是参数本身,具体例子如下:

function add(num1,num2){
    return num1+num2
}
function foo(num1=10,num2=add(num1,5)){
    console.log(num1,num2);
}
foo(1,2)               //1,2
foo(1)                 //1,6
foo(undefined,1)       //10,1
foo()                  //10,15

当然,如果调用的默认值是不存在的,那么会报错。比如:

function add1(num1,num2){
    return num1+num2
}
function foo(num1=10,num2=add(num1,5)){ //报错,ReferenceError,add不存在
    console.log(num1,num2);
}

当然,还有一种不太明显的,就是第一个参数把第二个参数当默认值:

function foo(num1=num2,num2=10){ 
    console.log(num1,num2);
}
foo(1,2)           //1,2
foo(undefined,2)   //报错,ReferenceError,num2不存在

因为暂时性死区,在使用num2的时候,并没有申明,其实上述的代码可以大概理解为在函数内部是这样的:

function foo(num1,num2){ 
    let num1;
    num1 = arguments[0] !== undefined?arguments[0]:num2;
    let num2;
    num2 = arguments[1] !== undefined?arguments[1]:10;
    console.log(num1,num2);
}

由此,可以看出,使用num2的时候并没有申明,所以会报错。

还有一点值得注意,函数参数的有自己单独的作用域和自己的暂时性死区(TDZ),和函数本身的作用域是分开的。也就是说,参数的默认值不能使用函数内部申明的变量。


参数的默认值就告一段落了,下面说一个ES6引入的新的东西,作用和arguments类似,但是又不完全相同

剩余参数(Rest Parameters)####

剩余参数的申明是使用...3个点加在参数名前。我们知道,在JavaScript中,参数的个数,传入的多少并不重要,需求2个参数,但是传入了3个参数,那么最后一个参数就会被舍去;需求2个参数,但是传入了1个参数,第二个参数就是undefined,这个本身不会报错。那么剩余参数的作用就是类似于arguments,把剩下的参数以数组的形式收集起来,具体操作如下:

function foo(num1,...num2){ 
    console.log(num2);
}
foo(0,1,2,3,4,5);          //[1,2,3,4,5]

正如你说看到的,num10,剩下的参数1,2,3,4,5全部被num2以数组的形式收集了起来。
剩余参数的概念并不复杂,但是还是需要注意2点:

  • 剩余参数后面不能再跟参数,否则会报错:
function foo(num1,...num2,num3){       //报错,SyntaxError,后面不能再跟参数
    console.log(num2);
}

也就是说,剩余参数只能是函数的最后一个参数。

  • 剩余参数不能运用在对象的setter方法中。例如:
let a = {
    set name(...value) {      //报错,SyntaxError
            // do something
        }
}

至于理由,很简单,因为setter方法本身只能接受单个数,而剩余参数是一个数组,不符合要求,当然会报错。

最后再讲一点,如果一个函数的参数只有剩余参数,那么此时,剩余参数arguments表达的差不多是一个意思,只不过剩余参数是一个更纯粹的数组。arguments还背负着自己的历史使命,比如callee,之类的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335

推荐阅读更多精彩内容

  • 三,字符串扩展 3.1 Unicode表示法 ES6 做出了改进,只要将码点放入大括号,就能正确解读该字符。有了这...
    eastbaby阅读 1,484评论 0 8
  • 1.函数参数的默认值 (1).基本用法 在ES6之前,不能直接为函数的参数指定默认值,只能采用变通的方法。
    赵然228阅读 676评论 0 0
  • 函数参数的默认值 基本用法 在ES6之前,不能直接为函数的参数指定默认值,只能采用变通的方法。 上面代码检查函数l...
    呼呼哥阅读 3,339评论 0 1
  • 参数扩展 1.收集剩余参数到一个数组中 2.数组展开(...arr 表示把数组arr展开) 例1 例2 例3 默认参数
    余生筑阅读 184评论 0 0
  • 斜雨微湿飞燕子,烟波沆砀,春水随风皱,望极天涯云梦处,也无计潇湘暂住。 拟泛轻舟逐晚晴,水天之际,残照忽而逝,无情...
    莫自在阅读 224评论 0 0