4.函数的扩展

函数参数的默认值

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

function Point(x = 0, y = 0) { 
this.x = x; 
this.y = y;
}
var p = new Point();
p // { x: 0, y: 0 }

解构赋值默认值的使用:

function fetch(url, { body = '', method = 'GET', headers = {} }) { 
console.log(method);
}
fetch('http://example.com', {})// "GET"
fetch('http://example.com')// 报错

函数的length属性:
指定了默认值以后,函数的length
属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后,length
属性将失真。

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

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

function throwIfMissing() { 
  throw new Error('Missing parameter');
}

function foo(mustBeProvided = throwIfMissing()) {
   return mustBeProvided;
}
foo()

rest参数

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

// arguments变量的写法
function sortNumbers() { 
return Array.prototype.slice.call(arguments).sort();
}
// rest参数的写法
const sortNumbers = (...numbers) => numbers.sort();

扩展运算符

扩展运算符(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>]

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

扩展运算符的应用

  • 合并数组
// ES5
[1, 2].concat(more)
// ES6
[1, 2, ...more]
var arr1 = ['a', 'b'];
var arr2 = ['c'];
var arr3 = ['d', 'e'];
// ES5的合并数组
arr1.concat(arr2, arr3);
// [ 'a', 'b', 'c', 'd', 'e' ]
// ES6的合并数组
[...arr1, ...arr2, ...arr3
]// [ 'a', 'b', 'c', 'd', 'e' ]
  • 与解构赋值结合
    扩展运算符可以与解构赋值结合起来,用于生成数组。
const [first, ...rest] = [1, 2, 3, 4, 5];
first 
// 1
rest  
// [2, 3, 4, 5]
const [first, ...rest] = [];
first
 // undefined
rest 
 // []
const [first, ...rest] = ["foo"];
first 
 // "foo"
rest  
// []
  • 字符串
[...'hello'];
[...'hello'].reverse().join("")
  • 实现了Iterator接口的对象
    任何Iterator接口的对象,都可以用扩展运算符转为真正的数组。
var nodeList = document.querySelectorAll('div');var array = [...nodeList];
  • Map和Set结构,Generator函数
    扩展运算符内部调用的是数据结构的Iterator接口,因此只要具有Iterator接口的对象,都可以使用扩展运算符,比如Map结构。
 let map = new Map([
    [1, 'one'], 
    [2, 'two'], 
    [3, 'three'],
]);
let arr = [...map.keys()]; // [1, 2, 3]

var go = function*(){
 yield 1;
 yield 2; 
yield 3;
};
[...go()]
 // [1, 2, 3]
  • 严格模式
    从ES5开始,函数内部可以设定为严格模式。
function doSomething(a, b) { 
'use strict'; 
 // code
}

只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。但可以如下解决(包含在一个立即执行的函数里):

const doSomething = (function () {
   'use strict';
    return function(value = 42) {
       return value;
 };
}());
  • name属性
    函数的name属性,返回该函数的函数名。

  • 箭头函数

var f = v => v; 

上面的箭头函数等同于:

var f = function(v) { return v;};```

如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return语句返回。
由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号。

var getTempItem = id => ({ id: id, name: "Temp" });

箭头函数可以与变量解构结合使用。

const full = ({ first, last }) => first + ' ' + last;
// 等同于
function full(person) {
return person.first + ' ' + person.last;
}

箭头函数的一个用处是简化回调函数。

// 正常函数写法
[1,2,3].map(function (x) { return x * x;});
// 箭头函数写法
[1,2,3].map(x => x * x);

rest用法

const numbers = (...nums) => nums;
numbers(1, 2, 3, 4, 5)// [1,2,3,4,5]
const headAndTail = (head, ...tail) => [head, tail];
headAndTail(1, 2, 3, 4, 5)// [1,[2,3,4,5]]

+ 使用注意点
     箭头函数有几个使用注意点。
  - 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
 - 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
 - 不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用Rest参数代替。
 - 不可以使用yield命令,因此箭头函数不能用作Generator函数。

上面四点中,第一点尤其值得注意。this对象的指向是可变的,但是在箭头函数中,它是固定的。

function Timer() {
this.s1 = 0;
this.s2 = 0;
// 箭头函数
setInterval(() => this.s1++, 1000);
// 普通函数
setInterval(function () {
this.s2++;
}, 1000);}
var timer = new Timer();
setTimeout(() => console.log('s1: ', timer.s1), 3100);
setTimeout(() => console.log('s2: ', timer.s2), 3100);
// s1: 3// s2: 0

箭头函数可以让this指向固定化,这种特性很有利于封装回调函数

所以,箭头函数转成ES5的代码如下。

// ES6function foo() {
setTimeout(() => {
console.log('id:', this.id); }, 100);
}
// ES5
function foo() {
var _this = this;
setTimeout(function () {
console.log('id:', _this.id);
}, 100);
}

下面是一个部署管道机制(pipeline)的例子,即前一个函数的输出是后一个函数的输入。

const pipeline = (...funcs) => val => funcs.reduce((a, b) => b(a), val);
const plus1 = a => a + 1;
const mult2 = a => a * 2;
const addThenMult = pipeline(plus1, mult2);
addThenMult(5)// 12

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

推荐阅读更多精彩内容

  • 函数参数的默认值 基本用法 在ES6之前,不能直接为函数的参数指定默认值,只能采用变通的方法。 上面代码检查函数l...
    呼呼哥阅读 3,353评论 0 1
  • 1.函数参数的默认值 (1).基本用法 在ES6之前,不能直接为函数的参数指定默认值,只能采用变通的方法。
    赵然228阅读 683评论 0 0
  • 三,字符串扩展 3.1 Unicode表示法 ES6 做出了改进,只要将码点放入大括号,就能正确解读该字符。有了这...
    eastbaby阅读 1,510评论 0 8
  • 1、函数参数的默认值1)基本用法在ES6之前,不能直接为函数的参数指定默认值,为了避免这个问题,通常需要先判断一下...
    秋天de童话阅读 370评论 0 0
  • 标题是对这个暑假找工作的总结吧。 2017年6月29日10点30分结束了这学期最后一场考试,租的车在十一点左右载着...
    橘子Leslie阅读 287评论 8 1