ES6&函数扩展

ES6函数的扩展

1.函数默认值

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

示例
function print(x,y='world'){
console.log(x,y);
}
print('hello'); //hello world
在ES5中则需要判断传参是否存在,再进行默认值赋值

参数变量是默认声明的,使用let和const再次进行声明会报错,var声明则不会,因为let定义不允许在相同作用域内重复声明一个变量。

2.函数的length属性

定义:函数的length属性将返回没有指定默认值的参数个数

示例
//在ES5中获取函数的参数个数需要函数return
function count(x,y){
return arguments.length;
}
//ES6中新增函数length属性
(function (x,y){}).length; //2
function count(x,y = "world"){
}
console.log(count.length); //1,指定默认值不算进去

3.函数的name属性

定义:获取函数的名称

var hello = function(){};
hello.name; //hello
//Function构造函数返回的示例name为anonymous
(new Function()).name; //anonymous

4.rest参数

定义:rest参数的写法为(...变量名),用于获取函数多余的变量,可替代arguments,rest参数中的变量是一个数组,arguments是类数组对象需要使用Array.from()方法转换成真正数组。

示例
function add(...numbers){
let count = 0;
for (let i of numbers){
count += i;
}
return count;
}
//或者使用numbers.forEach(x => count += x);
rest参数变量是一个数组,数组特有的方法都可以使用。
rest参数后不能再有其他的参数,rest参数必须为最后一个参数,使用函数属性length获取参数个数,rest参数不计入。
示例
function add(a,...numbers,c){
} //error
(function(a,b,...numbers){}).length; //2,rest参数不算

5.扩展运算符...

定义: 扩展运算符的写法为(...),将一个数组转为用逗号分隔的参数序列

示例
console.log(1,...[2,3,4,5],6); //1,2,3,4,5,6

使用扩展运算符替代apply()方法

//ES5
Math.max.apply(null,[4,6,0]); //Math.max不能接受数组为参数
Math.max(4,6,0);
//ES6
Math.max(...[4,6,0]);

使用扩展运算符合并数组

//ES5
var arr1 = [1,2,3];
var arr2 = [4,5,6,];
var arr = arr1.concat(arr2);
//ES6
var array1 = Array.of(1,2,3);
var array2 = Array.of(4,5,6);
var array = [...array1,...array2];

使用扩展运算符可将具有Iterator接口的数据结构转换成真正的数组(ES6数组扩展篇章也有提及)

[...'hello']; //将字符串转化成数组
var NodeList = [...document.querySelectorAll('p')];//类似数组对象
var someSet = new Set([4,5,6]);
var array = [...someSet.keys()]; //Set数据结构
var someMap = new Map([['name','lijaha'],['age',20]]);
var array = [...someMap.keys()]; //Map数据结构

6.箭头函数

定义: ES6允许使用箭头( => )定义函数

示例
var hello = x => x;
//如果箭头函数不需要参数或者需要多个参数就用()圆括号代表参数部分
var hello = () => 1; //return 1
var hello = (x,y) => x+y;
//如果箭头函数的代码块语句多于一句,需要使用大括号{}括起来
var hello = (x,y) => {return x+y};
//如果箭头函数返回的是对象,则需要在大括号外加上小括号({})
var hello = id => ({id: id,name: 'world'});

箭头函数体内的this对象是定义时所在的对象,而不是使用时所在的对象,称为箭头函数的this指向固定化。因为箭头函数内部是没有自己的this(不能作为构造函数,也不能使用apply、call、bind等方法改变this指向),所以它的this是外层代码块的this。

箭头函数内部没有arguments对象,需使用rest参数代替

var hello = (...numbers) => {console.log(...numbers)};

尾调用优化

定义:指某个函数在最后一步调用另一个函数

function hello(){

return hi();

} //尾调用的结尾一定是return xx();

函数调用会在内存中形成一个“调用帧”,保存调用位置和内部变量等信息。如果函数A中调用用了函数B,则会在函数A调用帧的上方形成一个B的调用帧,函数B执行完毕后,函数A中的调用帧B才会结束。如果函数B内调用了函数C,就会形成一个C地调用帧,所有的调用帧就会形成一个‘调用栈’。

//尾调用是函数的最后一步操作,所以不需要保留外层函数的调用帧,外层函数的调用位置和内部变量都不会用到。
function hello(){
let m = 1;
let n = 2;
return g(m+n);
}
//等同于
function hello(){
return g(3);
}
//等同于
g(3);
//上面代码中,如果函数g不是尾调用则函数hello需要保留内部变量m、n以及调用位置等信息,由于函数hello调用函数g后,hello函数就结束了,则可以删除hello()的调用帧,只保留g()的调用帧。

这就叫做‘尾调用优化’,即只保留内层函数的调用帧,如果所有的函数都是尾调用,则可以做到每次执行时调用帧只有一项。

//只有不再用到外层函数的内部变量,内层函数的调用帧才能取代外层函数的调用帧,实现尾调用优化。
function hello(a){
let b = 1;
function hi(a){
return a + b; //使用了hello函数的内部变量b
}
return hi(a);
}

尾递归

函数自己调用自己则叫递归,函数在尾部调用自己则称为尾递归

//使用递归实现阶乘,递归过程会比较耗费内存,因为保存大量的调用帧,容易发生栈溢出。
function factorial(n){
if(n == 1) return 1;
return nfactorial(n-1);
}
//使用尾递归
function factorial(n,total=1){ //使用默认值
if(n == 1) return total;
return factorial(n-1,n
total);
} //每次只保存一个调用记录
一般的递归的复杂度为O(n),使用尾递归的复杂度为O(1)

需要开启严格模式,尾调用优化才会生效,一旦使用尾调用优化,函数的内部对象arguments和caller都会失效,因为整个外层函数调用帧会被删除掉,这两个对象也就不存在了。严格模式下,这两个对象也是不可用的。

function hello(){
"use strict";
hello.arguments; //error
hello.caller; //error
}

本文章参考阮一峰《ES6 标准入门》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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

推荐阅读更多精彩内容

  • 1.函数参数的默认值 (1).基本用法 在ES6之前,不能直接为函数的参数指定默认值,只能采用变通的方法。
    赵然228阅读 676评论 0 0
  • 函数参数的默认值 基本用法 在ES6之前,不能直接为函数的参数指定默认值,只能采用变通的方法。 上面代码检查函数l...
    呼呼哥阅读 3,339评论 0 1
  • 函数新增特性 函数默认值,rest参数,扩展运算符,箭头函数,this绑定,尾调用 函数参数的默认值 rest参数...
    bjhu电net阅读 205评论 0 0
  • // 参数默认值 在有默认值的参数后面不能有没有默认值的参数,比如(x,y='world',c) 不允许 { ...
    super静_jingjing阅读 196评论 0 1
  • 想送你回家的人,东南西北都顺路。愿陪你吃饭的人,酸甜苦辣都爱吃。想见你的人,24小时都有空。
    南望先生的日记本阅读 152评论 0 0