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

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 这两个编译器都已经支持了参数默认值,所以你可以大胆使用。

结论

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

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

(0)

相关推荐

  • 举例说明如何为JavaScript的方法参数设置默认值

    你是否遇到过这样的情况,写了个function,无参数. function showUserInfo(){ alert("你好!我是小明."); } function showUserInfo(){ alert("你好!我是小明."); } 调用: showUserInfo(); showUserInfo(); 后来,发现其他地方也需要这个function,但是有变量值已经在function里面写死了,怎么办?加个参数吧. function showUserInfo

  • 深入学习JavaScript中的Rest参数和参数默认值

    本文将讨论使 JavaScript 函数更有表现力的两个特性:Rest 参数和参数默认值. Rest 参数 通常,我们需要创建一个可变参数的函数,可变参数是指函数可以接受任意数量的参数.例如,String.prototype.concat 可以接受任何数量的字符串作为参数.使用 Rest 参数,ES6 为我们提供一种新的方式来创建可变参数的函数. 我们来实现一个示例函数 containsAll,用于检查一个字符串中是否包含某些子字符串.例如,containsAll("banana",

  • JavaScript中无法通过div.style.left获取值的解决方法

    一.问题总结: 样式必须直接写在元素内部才能通过div.style.left直接获取属性值(也就是必须是内联样式才行),定义在css中的样式不能通过这种方式获取. 让元素移动到200停止 setTimeout ( function () { var div = document.getElementById("div4"); //var left = parseInt(div.style.left) + 5; var left = div.offsetLeft + 5; div.sty

  • Java中八种基本数据类型的默认值

    通过一段代码来测试一下 8种基本数据类型的默认值 package dierge; public class Ceshi { int a; double b; boolean c; char d; float f; byte e; long h; short j; public static void main(String args[]){ Ceshi a=new Ceshi(); System.out.println("整型的默认值是:"+a.a); System.out.print

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

    Rest 参数 通常,我们需要创建一个可变参数的函数,可变参数是指函数可以接受任意数量的参数.例如,String.prototype.concat 可以接受任何数量的字符串作为参数.使用 Rest 参数,ES6 为我们提供一种新的方式来创建可变参数的函数. 我们来实现一个示例函数 containsAll,用于检查一个字符串中是否包含某些子字符串.例如,containsAll("banana", "b", "nan") 将返回true,contai

  • 深入探讨javascript中的数据类型

    学一门编程语言,无非两方面:一是语法,二是数据类型.类C语言的语法不外乎if.while.for.函数.算术运算等,面向对象的语言再加上object. 语法只是语言设计者预先做的一套规则,不同语言语法不尽相同,但都有一些共通点,对于熟悉一两门编程语言的人,学其他的编程语言时,语法往往不是问题(当然,如果你一直学的是类C语言,那么首次接触lisp时肯定也要花些时间),学习的重点往往是数据类型及其相关操作上,不是有句老话:"数据结构+算法=程序"!其次,有些语言的语法本身就存在设计问题(j

  • 探讨JavaScript中声明全局变量三种方式的异同

    变量及变量声明是一门语言最基本的概念,初学者都会很快掌握.JavaScript中声明变量也是如此,很简单var(关键字)+变量名(标识符). 方式1 var test;var test = 5;需注意的是该句不能包含在function内,否则是局部变量.这是第一种方式声明全局变量. 方式2 test = 5;没有使用var,直接给标识符test赋值,这样会隐式的声明了全局变量test.即使该语句是在一个function内,当该function被执行后test变成了全局变量. 方式3 window

  • 在JavaScript中获取请求的URL参数

    当然我们可以在后台中获取参数的值,然后在前台js代码中获取变量的值,具体做法请参考我的这篇文章:JavaScript获取后台C#变量以及调用后台方法. 其实我们也可以直接在js中获取请求的参数的值,通过使用window.location.search可以获取到当前URL的?号开始的字符串,如前面的链接获取到的search为?id=001.再对获取的字符串进行处理,就可以获取到参数的值了. 复制代码 代码如下: function getUrlParam(name) { var reg = new

  • 在JavaScript中获取请求的URL参数[正则]

    第一种方法:,代码比较专业 推荐 复制代码 代码如下: <script> function GetLocationParam(param){ var request = { QueryString : function(val) { var uri = window.location.search; var re = new RegExp("" +val+ "=([^&?]*)", "ig"); return ((uri.ma

  • ES6中参数的默认值语法介绍

    前言 在ES6如果函数参数没有值或未定义的,默认函数参数允许将初始值初始化为默认值.下面来看看详细的介绍吧. 语法 function [name]([param1[ = defaultValue1 ][, ..., paramN[ = defaultValueN ]]]) { statements } 描述 在JavaScript中,函数默认参数定义.然而,在某些情况下,设置不同的默认值可能是有用的.这是默认参数可以帮助的地方. 在过去,设置默认值的一般策略是在函数体中测试参数值,如果它们是未定

  • Django的URLconf中使用缺省视图参数的方法

    一个方便的特性是你可以给一个视图指定默认的参数. 这样,当没有给这个参数赋值的时候将会使用默认的值. 例子: # urls.py from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns('', (r'^blog/$', views.page), (r'^blog/page(?P<num>\d+)/$', views.page), ) # views.py def page(r

  • Python中的函数参数(位置参数、默认参数、可变参数)

    目录 一.位置参数 二.默认参数 三.可变参数 四.关键字参数 五.命名关键字参数 六.各种参数之间的组合 函数的参数:Python中函数定义非常简单,由于函数参数的存在,使函数变得非常灵活应用广泛:不但使得函数能够处理复杂多变的参数,还能简化函数的调用. Python中的函数参数有如下几种:位置参数.默认参数.可变参数.关键字参数和命名关键字参数 一.位置参数 位置参数(positional arguments)就是其他语言的参数,其他语言没有分参数的种类是因为只有这一种参数, 所有参数都遵循

随机推荐