前面的话

  ES6标准关于函数扩展部分,主要涉及以下四个方面:参数默认值、rest参数、扩展运算符和箭头函数

参数默认值

  一般地,为参数设置默认值需进行如下设置

function log(x, y) {
y = y || 'World';
console.log(x, y);
}

  但这样设置实际上是有问题的,如果y的值本身是假值(包括false、undefined、null、''、0、-0、NaN),则无法取得本身值

function log(x, y) {
y = y || 'World';
console.log(x, y);
}
log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', NaN) // Hello World

  ES6允许为函数的参数设置默认值,即直接写在参数定义的后面

function log(x, y = 'World') {
console.log(x, y);
}
log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', NaN) // Hello NaN

  [注意]参数变量是默认声明的,所以不能用let或const再次声明

function foo(x = 5) {
let x = 1; //SyntaxError: Identifier 'x' has already been declared
const x = 2; //SyntaxError: Identifier 'x' has already been declared
}

尾参数

  通常情况下,定义了默认值的参数,应该是函数的尾参数。因为这样比较容易看出来,到底省略了哪些参数。如果非尾部的参数设置默认值,实际上这个参数是没法省略的

function f(x = 1, y) {
return [x, y];
}
f() // [1, undefined]
f(2) // [2, undefined])
f(, 1) // 报错
f(undefined, 1) // [1, 1]

  如果传入undefined,将触发该参数等于默认值,null则没有这个效果

function foo(x = 5, y = 6) {
console.log(x, y);
}
foo(undefined, null)// 5 null

length

  指定了默认值以后,函数的length属性,将返回没有指定默认值的参数个数

(function (a) {}).length //
(function (a = 5) {}).length //
(function (a, b, c = 5) {}).length //

  [注意]如果设置了默认值的参数不是尾参数,那么length属性也不再计入后面的参数了

(function (a = 0, b, c) {}).length //
(function (a, b = 1, c) {}).length //

作用域

  【1】如果参数默认值是一个变量,则该变量所处的作用域,与其他变量的作用域规则是一样的,即先是当前函数的作用域,然后才是全局作用域

var x = 1;
function f(x, y = x) {
console.log(y);
}
f(2) //

  【2】如果函数调用时,函数作用域内部的变量x没有生成,则x指向全局变量

var x = 1;
function f(y = x) {
var x = 2;
console.log(y);
}
f() //

应用

  利用参数默认值,可以指定某一个参数不得省略,如果省略就抛出一个错误

function throwIfMissing() {
throw new Error('Missing parameter');
}
function foo(mustBeProvided = throwIfMissing()) {
return mustBeProvided;
}
foo()// Error: Missing parameter

  [注意]将参数默认值设为undefined,表明这个参数可以省略

function foo(optional = undefined) {
//todo
}

rest参数

  ES6引入rest参数(形式为“...变量名”),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest参数搭配的变量是一个数组,该变量将多余的参数放入数组中

function add(...values) {
var sum = 0;
for (var val of values) {
sum += val;
}
return sum;
}
add(2, 5, 3) //

  rest参数中的变量代表一个数组,所以数组特有的方法都可以用于这个变量

  下面是一个利用rest参数改写数组push方法的例子

function push(array, ...items) {
items.forEach(function(i) {
array.push(i);
console.log(i);
});
}
var a = [];
push(a, 1, 2, 3);

  函数的length属性不包括rest参数

(function(a) {}).length  //
(function(...a) {}).length //
(function(a, ...b) {}).length //

  [注意]rest参数之后不能再有其他参数

//Uncaught SyntaxError: Rest parameter must be last formal parameter
function f(a, ...b, c) {
//todo
}

扩展运算符

  扩展运算符(spread)是三个点(...)。它好比rest参数的逆运算,将一个数组转为用逗号分隔的参数序列

console.log(...[1, 2, 3])// 1 2 3
console.log(1, ...[2, 3, 4], 5)// 1 2 3 4 5
[...document.querySelectorAll('div')]// [<div>, <div>, <div>]

  该运算符主要用于函数调用

function add(x, y) {
return x + y;
}
var numbers = [4, 38];
add(...numbers) //

  Math.max方法简化

// ES5
Math.max.apply(null, [14, 3, 77]) // ES6
Math.max(...[14, 3, 77]) //等同于
Math.max(14, 3, 77)

  push方法简化

// ES5
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
Array.prototype.push.apply(arr1, arr2); // ES6
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
arr1.push(...arr2);

  扩展运算符可以将字符串转为真正的数组

[...'hello']// [ "h", "e", "l", "l", "o" ]

箭头函数

  关于箭头函数的详细介绍移步至此

参考资料

  《ECMAScript 6入门》 阮一峰

深入理解javascript函数系列第四篇——ES6函数扩展的更多相关文章

  1. 深入理解javascript作用域系列第四篇——块作用域

    × 目录 [1]let [2]const [3]try 前面的话 尽管函数作用域是最常见的作用域单元,也是现行大多数javascript最普遍的设计方法,但其他类型的作用域单元也是存在的,并且通过使用 ...

  2. 深入理解javascript作用域系列第四篇

    前面的话 尽管函数作用域是最常见的作用域单元,也是现行大多数javascript最普遍的设计方法,但其他类型的作用域单元也是存在的,并且通过使用其他类型的作用域单元甚至可以实现维护起来更加优秀.简洁的 ...

  3. 深入理解javascript作用域系列第三篇——声明提升(hoisting)

    × 目录 [1]变量 [2]函数 [3]优先 前面的话 一般认为,javascript代码在执行时是由上到下一行一行执行的.但实际上这并不完全正确,主要是因为声明提升的存在.本文是深入理解javasc ...

  4. 深入理解javascript作用域系列第三篇

    前面的话 一般认为,javascript代码在执行时是由上到下一行一行执行的.但实际上这并不完全正确,主要是因为声明提升的存在.本文是深入理解javascript作用域系列第三篇——声明提升(hois ...

  5. 深入理解javascript函数进阶系列第四篇——惰性函数

    前面的话 惰性函数表示函数执行的分支只会在函数第一次调用的时候执行,在第一次调用过程中,该函数会被覆盖为另一个按照合适方式执行的函数,这样任何对原函数的调用就不用再经过执行的分支了.本文将详细介绍惰性 ...

  6. javascript面向对象系列第四篇——选项卡的实现

    前面的话 面向对象的应用并非只是读几本书那么容易,需要有大量的工程实践做基础才能真正理解并学会使用它.本文将用面向对象的技术来制作一个简单的选项卡 图示说明 由图示结果看到,这是一个非常简单的选项卡. ...

  7. 深入理解javascript作用域系列第五篇——一张图理解执行环境和作用域

    × 目录 [1]图示 [2]概念 [3]说明[4]总结 前面的话 对于执行环境(execution context)和作用域(scope)并不容易区分,甚至很多人认为它们就是一回事,只是高程和犀牛书关 ...

  8. 深入理解javascript作用域系列第五篇

    前面的话 对于执行环境(execution context)和作用域(scope)并不容易区分,甚至很多人认为它们就是一回事,只是高程和犀牛书关于作用域的两种不同翻译而已.但实际上,它们并不相同,却相 ...

  9. 深入理解javascript对象系列第三篇——神秘的属性描述符

    × 目录 [1]类型 [2]方法 [3]详述[4]状态 前面的话 对于操作系统中的文件,我们可以驾轻就熟将其设置为只读.隐藏.系统文件或普通文件.于对象来说,属性描述符提供类似的功能,用来描述对象的值 ...

随机推荐

  1. js与多行字符串

    JS里并没有标准的多行字符串的表示方法,但是在用模板的时候,为了保证模板的可阅读性,我们又不可避免的使用多行字符串,所以出现了各种搞法,这里以一段jade的模板作为示例,简单总结和对比一下. 字符串相 ...

  2. css 浅析display属性

    继续开始我的css之旅吧.今天我们来说什么啊.构思了两天还是没有什么思路,但是学习的步伐我们不能停止下来.还是按照之前的计划来讲讲display,在讲这个之前我们还是按照老规矩来扯扯蛋,步子不能够迈大 ...

  3. ZeroMQ(ZMQ)函数接口英汉直译

    找了好多地方都找不到ZMQ接口函数的中文文档,就厚着脸皮自己翻译了下.但因为作者本人涉世未深,翻译有错误的地方还请大家不吝赐教,在下感激不尽. 因为时间有限,只能一点一点翻译了. ZMQ接口文档的官方 ...

  4. 输出日志实例改成用Spring的AOP来实现

    1.采用Interception Around通知的形式实现 Interception Around通知会在Join Point的前后执行,实现Interception Around通知的类需要实现接 ...

  5. python方法中的self

    前几天在写一个c作业时,突发奇想,在结构体中加入函数指针, 像这样: struct People { int _age; int (*age)(); }people; 这样调用时就可以 people. ...

  6. elasticsearch 之mapping

    搭好elk 后,有时候会发现kibana 统计数据时,数据类型不对,这个时候就和elasticsearch的mapping有关,虽然我们可以用logstash修改传入es里的数据类型,比如 float ...

  7. listview嵌套gridview,并实现grid元素部分显示以及点击展开与折叠

    原文链接:http://blog.csdn.net/duguju/article/details/49538341 有时我们需要用GridView显示目录列表,有时甚至是二级的,即listview每一 ...

  8. What's the difference between a stub and mock?

    I believe the biggest distinction is that a stub you have already written with predetermined behavio ...

  9. 正在运行的android程序,按home键之后退回到桌面,在次点击程序图标避免再次重新启动程序解决办法

    正在运行的android程序,按home键之后退回到桌面,在次点击程序图标避免再次重新启动程序解决办法 例如:一个android程序包含两个Activity,分别为MainActivity和Other ...

  10. Mysql修改root密码

    一.启动命令行,输入: taskkill /f /im mysqld.exe //关闭mysql 二.转入mysql的bin目录下 三.输入:mysqld --skip-grant-tables // ...