探讨JavaScript中的Rest参数和参数默认值


Posted in Javascript onJuly 29, 2015

Rest 参数

通常,我们需要创建一个可变参数的函数,可变参数是指函数可以接受任意数量的参数。例如,String.prototype.concat 可以接受任何数量的字符串作为参数。使用 Rest 参数,ES6 为我们提供一种新的方式来创建可变参数的函数。

我们来实现一个示例函数 containsAll,用于检查一个字符串中是否包含某些子字符串。例如,containsAll("banana", "b", "nan") 将返回true,containsAll("banana", "c", "nan") 将返回 false。

下面是传统的实现方式

function containsAll(haystack) { 
 for (var i = 1; i < arguments.length; i++) { 
 var needle = arguments[i]; 
 if (haystack.indexOf(needle) === -1) { 
  return false; 
 } 
 } 
 return true; 
} 
  
function containsAll(haystack) { 
 for (var i = 1; i < arguments.length; i++) { 
 var needle = arguments[i]; 
 if (haystack.indexOf(needle) === -1) { 
  return false; 
 } 
 } 
 return true; 
}

该实现用到了 arguments 对象,该对象是一个类数组对象,包含函数被调用时的实参列表。这段代码正是我们想要的,但其可读性却不是最优的。函数只有一个形参 haystack,所以不可能一看就知道该函数需要多个参数,并且在遍历 arguments 时,需要特别注意遍历的开始索引为1 ,而不是常见的 0,因为 arguments[0] 就是函数定义时的形参 haystack。如果我们想在 haystack 参数之前或之后添加一些参数,我们不得不更新内部的循环。Rest 参数解决了这些问题,下面是使用 Rest 参数的实现方式:

function containsAll(haystack, ...needles) { 
 for (var needle of needles) { 
 if (haystack.indexOf(needle) === -1) { 
  return false; 
 } 
 } 
 return true; 
} 
  
function containsAll(haystack, ...needles) { 
 for (var needle of needles) { 
 if (haystack.indexOf(needle) === -1) { 
  return false; 
 } 
 } 
 return true; 
}

以上两个实现都满足了我们的需求,但后者包含一个特殊的 ...needles 语法。我们来看看调用containsAll("banana", "b", "nan") 时的细节,参数 haystack 和以往一样,将用函数的第一个实参填充,值为 "banana",needles 前面的省略号表示它是一个 Rest 参数,剩余的所有实参将被放入一个数组中,并将该数组赋给 needles 遍量。在这个调用中,needles 的值为 ["b", "nan"]。然后,就是正常的函数执行了。

只能将函数的最后一个函数作为 Rest 参数,在函数被调用时,Rest 参数之前的参数都将被正常填充,之外的参数将被放入一个数组中,并将该数组作为 Rest 参数的值,如果没有更多的参数,那么 Rest 参数的值为一个空数组 [],Rest 参数的值永远都不会是 undefined。

参数的默认值

通常,调用一个函数时,不需要调用者传递所有可能的参数,那些没有传递的参数都需要一个合理的默认值。JavaScript 对那些没有传递的参数都有一个固定的默认值 undefined。在 ES6 中,引入了一种新方法来指定任意参数的默认值。

看下面例子:

function animalSentence(animals2="tigers", animals3="bears") { 
 return `Lions and ${animals2} and ${animals3}! Oh my!`; 
} 
  
function animalSentence(animals2="tigers", animals3="bears") { 
 return `Lions and ${animals2} and ${animals3}! Oh my!`; 
}

在每个参数的 = 后面是一个表达式,指定了参数未传递时的默认值。所以,animalSentence() 返回 "Lions and tigers and bears! Oh my!", animalSentence("elephants") 返回"Lions and elephants and bears! Oh my!", animalSentence("elephants", "whales") 返回 "Lions and elephants and whales! Oh my!"。

参数默认值需要注意的几个细节:

与 Python 不一样的是,参数默认值的表达式是在函数调用时从左到右计算的,这意味着表达式可以使用前面已经被填充的参数。例如,我们可以将上面的函数变得更有趣一点:

function animalSentenceFancy(animals2="tigers", 
 animals3=(animals2 == "bears") ? "sealions" : "bears") 
{ 
 return `Lions and ${animals2} and ${animals3}! Oh my!`; 
} 
 
  
function animalSentenceFancy(animals2="tigers", 
 animals3=(animals2 == "bears") ? "sealions" : "bears") 
{ 
 return `Lions and ${animals2} and ${animals3}! Oh my!`; 
}

那么,animalSentenceFancy("bears") 将返回 "Lions and bears and sealions. Oh my!"。

传递 undefined 等同于没有传递该参数。因此,animalSentence(undefined, "unicorns") 将返回 "Lions and tigers and unicorns! Oh my!"。

如果没有为一个参数指定默认值,那么该参数的默认值为 undefined,所以

function myFunc(a=42, b) {...}  

   

function myFunc(a=42, b) {...} 

等同于

function myFunc(a=42, b=undefined) {...}  

   

function myFunc(a=42, b=undefined) {...} 

抛弃 arguments

通过 Rest 参数和参数的默认值,我们可以完全抛弃 arguments 对象,使我们的代码可读性更高。此外,arguments 对象也加深了优化 JavaScript 的难题。

希望以上两个新特性可以完全取代 arguments。作为第一步,在使用 Rest 参数或参数的默认值时,请避免使用 arguments 对象,假如 arguments 对象还不会立即被移除,或者永远不会,那么也最好是避免在使用 Rest 参数或参数默认值时使用 arguments 对象。

兼容性

Firefox 15 以上的版本已经支持这两个新特性。然而,除此之外,还没有其他任何浏览器支持。最近,V8 的实验环境添加了对 Rest 参数的支持,而参数默认值还有一个 issue,JSC 也对 Rest 参数和参数默认值提了一些 issue。

Babel 和 Traceur 这两个编译器都已经支持了参数默认值,所以你可以大胆使用。

结论

尽管从技术层面上看,这两个新特性在并没有给函数引入新的行为,但它们可以使一些函数的声明更具表现力和可读性。

以上就是本文的全部内容,希望对大家的学习有所帮助。

Javascript 相关文章推荐
利用JS自动打开页面上链接的实现代码
Sep 25 Javascript
jQuery循环滚动展示代码 可应用到文字和图片上
May 11 Javascript
Jquery图片延迟加载插件jquery.lazyload.js的使用方法
May 21 Javascript
JS实现兼容性好,带缓冲的动感网页右键菜单效果
Sep 18 Javascript
JS动态给对象添加事件的简单方法
Jul 19 Javascript
详细谈谈javascript的对象
Jul 31 Javascript
jquery 判断div show的状态实例
Dec 03 Javascript
jQuery插件HighCharts绘制2D柱状图、折线图和饼图的组合图效果示例【附demo源码下载】
Mar 09 Javascript
js传递数组参数到后台controller的方法
Mar 29 Javascript
vue webpack重写cookie路径的方法
Jul 10 Javascript
基于JS实现数字动态变化显示效果附源码
Jul 18 Javascript
简单聊聊TypeScript只读修饰符
Apr 06 Javascript
JS的框架Polymer中的dom-if和is属性使用说明
Jul 29 #Javascript
js数组去重的方法汇总
Jul 29 #Javascript
浅谈JavaScript的Polymer框架中的behaviors对象
Jul 29 #Javascript
JavaScript中的cacheStorage使用详解
Jul 29 #Javascript
JavaScript中数组继承的简单示例
Jul 29 #Javascript
小议JavaScript中Generator和Iterator的使用
Jul 29 #Javascript
浅析Node.js的Stream模块中的Readable对象
Jul 29 #Javascript
You might like
微信支付开发教程(一)微信支付URL配置
2014/05/28 PHP
Laravel 框架基于自带的用户系统实现登录注册及错误处理功能分析
2020/04/14 PHP
jQuery函数的等价原生函数代码示例
2013/05/27 Javascript
JS获取当前网址、主机地址项目根路径
2013/11/19 Javascript
用javascript删除当前行,添加行(示例代码)
2013/11/25 Javascript
node.js解决获取图片真实文件类型的问题
2014/12/20 Javascript
Bootstrap嵌入jqGrid,使你的table牛逼起来
2016/05/05 Javascript
JavaScript中对JSON对象的基本操作示例
2016/05/21 Javascript
JS监听微信、支付宝等移动app及浏览器的返回、后退、上一页按钮的事件方法
2016/08/05 Javascript
详解Vue中添加过渡效果
2017/03/20 Javascript
js,jq,css多方面实现简易下拉菜单功能
2017/05/13 Javascript
小程序实现左滑删除功能
2018/10/30 Javascript
Vue 框架之动态绑定 css 样式实例分析
2018/11/14 Javascript
Vuex中的State使用介绍
2019/01/19 Javascript
[48:05]2018DOTA2亚洲邀请赛 3.31 小组赛 B组 VGJ.T vs VP
2018/03/31 DOTA
Python中属性和描述符的正确使用
2016/08/23 Python
简单学习Python多进程Multiprocessing
2017/08/29 Python
Python使用matplotlib简单绘图示例
2018/02/01 Python
Django Web开发中django-debug-toolbar的配置以及使用
2018/05/06 Python
python selenium 获取标签的属性值、内容、状态方法
2018/06/22 Python
Python 实现一个手机号码获取妹子名字的功能
2019/09/25 Python
基于python调用psutil模块过程解析
2019/12/20 Python
Spring Boot中使用IntelliJ IDEA插件EasyCode一键生成代码详细方法
2020/03/20 Python
python使用hdfs3模块对hdfs进行操作详解
2020/06/06 Python
python 如何利用argparse解析命令行参数
2020/09/11 Python
css3实现图片遮罩效果鼠标hover以后出现文字
2013/11/05 HTML / CSS
HTML5+CSS3实现机器猫
2016/10/17 HTML / CSS
英国皇家邮政海外旗舰店:Royal Mail
2018/02/21 全球购物
AJAX都有哪些有点和缺点
2012/11/03 面试题
建筑文秘专业个人求职信范文
2013/12/28 职场文书
社团活动总结书
2014/06/27 职场文书
文秘自荐信
2014/06/28 职场文书
运动会主持人开幕词
2016/03/04 职场文书
扩展多台相同的Web服务器
2021/04/01 Servers
python 三边测量定位的实现代码
2021/04/22 Python
python常见的占位符总结及用法
2021/07/02 Python