ES6 针对新的语法特性(解构、参数默认值、箭头语句、块级作用域let),对于函数的属性、参数、作用域进行了扩展,并对递归调导致内存栈溢出用进行了优化。
同时ES6规定,只要函数参数使用了默认值、解构赋值、扩展运算符,函数内部都不可以使用严格模式(ES5可以),否则会报错;

1. 函数参数默认值

ES6之前,函数定义/声名时不能指定默认值;ES6可以在函数定义时进行初始化;同时有以下几点需要注意:

  • 参数设置默认值时,参数直接写在默认值后面,如:function(x,y=1){return x+y};
  • 函数传递参数时,不允许有同名参数,如:function(x,x,y=true){return x};//报错:参数重复命名
  • 函数传递参数时,不能在函数体内部用letconst再次声明,如:function(x){let x=false;}//报错;
  • rest参数,用于获取多余的参数,可替代arguments,rest参数之后不可再有其他参数,否则会报错:
function sum(...values){let sum=0;for(let val of values){sum+=val;}return sum;
}
sum(1,2,3,4);//10
  • 传递默认参数时,默认参数需放在无默认值参数后面,如果不在最后,需要显示传入undefiend
function fn(x,y=5,z){return [x,y,z];
}
fn();   // [undefined,5,undeifined]
fn(1);  //[1,5,undefiend]
fn(1,2);// [1,2,undefined]
fn(1,,3);//报错
fn(1,undefined,3);//[1,5,3]
  • 传参与结构赋值结合:
// 写法一
function fn1({x=0,y=0}={}){return [x,y];
}
//写法二
function fn2({x,y}={x=0,y=0}){return [x,y];
}
// ① 函数无参数
fn1();  // [0,0]
fn2(); // [0,0]
// ② x、y都无值情况;
fn1({});   // [0,0]
fn2({});  // [undefined,undefined]
// ③x有值,y无值;
fn1({x:3}});  // [3,0]
fn2({x:3});  // [3,undefiend]

2.函数作用域

函数参数设置默认值后,函数初始化时,参数会形成一个单独的作用域;等到初始化完成后,这个作用域消失;不设置默认值时,该机制不生效;

// ① 函数参数独立作用域机制赋值:
let x=1;
function fn1(x,y=x){console.log(y)};
fn1(2);//2
//② 函数参数独立作用域+作用域链
let a=1;
function fn2(b=a){
let a=2;
console.log(b);
};
fn2();//1// ③ 函数参数单独作用域+作用域链
function fn3(e=d){
console.log(e)
}
fn3();// ReferenceError:e is not defiined// ④ 参数赋初值+let 暂时性死区 =>报错
let j=2;
function fn4(j=j){
console.log(j)
}
fn4();//ReferenceError:j is not defined  

3. 函数新增属性

  • name:返回函数名称:function fn(){};fn.name;//fn

    ①将匿名函数赋值给变量,ES5中该属性返回空字符串"",而ES6返回实际函数名;②Function构造函数返回函数实例,name属性返回anoymous,bind返回的函数,name属性加上bound前缀:

(new Function).name;         //"anoymous"
function fn(){};
fn.bind({}).name;                // "bound fn"
(function(){}).bind({}).name; // "bound"
  • length:返回函数没有指定默认值的参数的个数,本质是返回该函数预期传入的参数个数,即指定默认值的参数,length属性将失效(忽略该参数)、同理rest参数页不会计入length属性;
(function(a){}).length;//1
(function(a=1){}).length;//0
(fucntion(a,b,c=5){}).length;//2(function(..args){}).length;//0
(function(a,b=1,c,d){}).length;//1

4. 箭头函数——()=>{}

箭头函数不存在单独的作用域,即不存在单独的this、arguments、super、new.target;这四个对象分别指向外层函数对应的变量;
箭头函数中this指向固化并不是箭头函数内部有绑定this的机制,相反,本质原因是箭头函数根本没有自己的this,导致箭头函数内部的this就是外层代码块的this,也正是因为没有this,即没有独自的作用域,所以不能用作构造函数;

1.注意事项
  • 不存在this:箭头函数体内的this对象指向定义时所在对象,而非调用时所在对象;
  • 不可做构造函数:箭头函数不可用实例化,即不可用new创建,否则报错;
  • 不可使用arguments对象:arguments对象在箭头函数体内部存在,可用rest参数替代;
  • 不可使用yeild命令:即箭头函数不能用作Generator函数;
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);  // s1:3
setTimeout(()=>console.log('s2:',timer.s2),3100); // s2:0
2. 箭头函数使用场景
  • 简化回调函数;
  • 绑定this:自动绑定this到外层函数对象,减少显示绑定this对象写法(call、apply);
  • 部署管道机制(pipeline):即前一个函数的输出时后一个函数的输入;
const plus=a=>a+1;
const mult=b=>b*2;
mult(plus(5));//12const pipeline=((...fns)=>val=>fns.reduce((a,b)=>b(a),val));
const addThenMult=pipeline(plus,mult);
addThenMult(5);//12

5.函数优化

四个概念:调用帧、尾调用函数、尾递归函数、蹦床函数、函数柯里化(currying)

  • 调用帧:

    函数调用时会在内存中形成一个调用记录(调用帧-call frame),保存调用位置和内部变量等息息;如果A函数的内部调用B函数,那么在A的调用帧上方会形成一个B函数的调用帧,待B函数运行结束,将结果返回A时,B函数的调用帧占用的内存才会被回收消失;如果B函数内部还调用了C函数,就会生成一个C函数的调用帧,以此类推,所有的调用帧形成一个调用栈(call stack);
    递归函数非常消耗内存,因为需要同时保存数量巨大的调用帧,容易造成“栈溢出”错误(stack overflow);

  • 尾调用函数: 尾调用函数(Tail call):即某个函数的最后一步是返回调用另一个函数,如:function f(x){return g(x)};尾调用不一定出现在函数的尾部,但一定是最后一步操作,以下三种均不属于尾调用:
function fn1(){return g()+1;}              // 调用后还有其他操作
function fn2(){let res=g();return res;} // 不是最后一步操作
function fn3(){g()}                          // 返回 undeifend
  • 尾递归函数: 尾调用函数的调用函数为函数自身时,成为尾递归函数;
// ① ES6尾递归优化案例:阶乘
function fn1(n){if(n===1) retrun 1;return n*fn(n-1);
}fn1(5; // 120
funcion fn1Optimize(n,tatal){if(n===1)return 1;return fn1Optimize(n-1,n*total);
}
fn1Optimize(5,1); //120
// ② ES6尾递归优化案例: 斐波那数列
function fibonacci(n){if(n<=1) return 1;return fibonacci(n-1)+fibonacci(n-2);
}
fibonacci(10); //89
fibonacci(100); //堆栈溢出
fibonacci(1000); // 堆栈溢出function fibonacciOpt(n,a1=1,a2=1){if(n<=1) return a2;return fibonacciOpt(n-1,a2,a1+a2)
}
fibonacciOpt(10); //89
fibonacciOpt(100); // 573147844013817200000
fibonacciOpt(1000); // 49 7.0330367711422765e+208
fibonacciOpt(10000);//  Infinity 或 Uncaught RangeError: Maximum call stack size exceeded
  • 蹦床函数(trampoline):可以将尾递归转换为循环执行;进而避免递归执行,消除调用栈溢出,蹦床函数的实现方法实例;
function trampoline(fn){while(f&&f instanceof Function){fn=fn()};return fn;
}
  • 函数柯里化:函数式编程中,函数柯里化指 将多参数的函数转换成单个参数形式的函数;
function currying(fn,n){return function(m){return fn.call(this,m,n)}
}
  • 优化方案: ① 外层函数封装多参数的尾递归函数,如:function fn(n){function g(n,1){return g(n,1) }};②函数柯里化

    只有当调用函数不再需要外层函数的内部变量,内层函数的调用帧才会取代外层函数的调用帧,否则无法进行尾调用优化;
    优化方案:尾调用、尾递归由于是函数的最后一步,调用位置、内部变量信息等都不会再用到了,所以不需要保留外层函数的调用帧,直接用内层函数的调用帧取代外层函数即可,这就是尾调用优化(Tail call Optimize)、尾递归函数优化;

    由于尾调用优化的重要性,ES6第一次明确规定: 所有ECMAScript的实现都必须部署“尾调用优化”;即ES6中只要使用尾递归,就不会发生内存溢出;

ps:

  • ES7 提案函数对象绑定运算符(babel已支持)::: 双冒号左边是一个对象,右边是一个函数,该运算符自动将左边对象作为右边函数的上下文环境(context);

转载于:https://www.cnblogs.com/hbzyin/p/8012299.html

ES6-04:函数的扩展相关推荐

  1. ES6之函数的扩展(二)

    主要讲解: 1. rest参数 2. 严格模式 3. name属性 -- 返回函数的函数名 4. 箭头函数 -- 用 "=>" 定义函数 1.rest参数 ...argume ...

  2. [ES6] 细化ES6之 -- 函数的扩展

    函数参数的默认值 函数参数指定状认值 ES6 之前,不能直接为函数的参数指定默认值,如果定义了形参,不传递实参时导致形参为undefined,只能采用变通的方法. //ES5 function fn( ...

  3. 004. ES6之函数的扩展

    2019独角兽企业重金招聘Python工程师标准>>> 1. 函数参数的默认值 ES6 允许为函数的参数设置默认值, function log(x, y = 'World') {co ...

  4. 第十节:ES6为函数做了哪些扩展?

    ES6一路扩展,字符串.数组.数值.对象无一"幸免",ES6说要雨露均沾,函数也不能落下,今天,就来讲解ES6对函数的扩展. 姿势准备好了吗?前方高能,第10节开讲...... 参 ...

  5. es6 箭头函数 rest参数 扩展运算符

    Es6 箭头函数 语法: 普通函数: fn=function(){} 箭头函数: fn=()=>{} 特性: this是静态的,this始终指向函数声明时所在作用域下的this的值(使用call ...

  6. ES6学习(六)—函数的扩展

    ES6学习(六)-函数的扩展 挑重点 文章只列举了一部分 完整版请看阮一峰ES6入门教程 点我查看阮一峰ES6入门教程 一.函数参数的默认值 二.rest 参数 ES6 引入 rest 参数(形式为- ...

  7. 重学ES6 函数的扩展(下)

    尾调用优化 什么是尾调用 尾调用(Tail Call)是函数式变成的重要概念,本身很简单,就是指函数的最后一步,调用另一个函数. function f(x){return g(x) } // 函数最后 ...

  8. 【ES6】函数的拓展

    [ES6]函数的拓展 一.函数参数的默认值 二.扩展运算符 三.箭头函数[重点!!!] 查看更多ES6教学文章: 参考文献 引言:ES6添加了函数的默认值的写法.rest参数.拓展运算符.箭头函数等特 ...

  9. ES6基础3(扩展)-学习笔记

    文章目录 ES6基础3(扩展)-学习笔记 字符串扩展 数值扩展 函数扩展 扩展运算符 ES6基础3(扩展)-学习笔记 字符串扩展 //扩展//字符串扩展charAt(); //返回指定索引位置的字符 ...

  10. “睡服”面试官系列第十三篇之函数的扩展(建议收藏学习)

    目录 1. 函数参数的默认值 1.1基本用法 1.2与解构赋值默认值结合使用 1.3参数默认值的位置 1.4函数的 length 属性 1.5作用域 1.6应用 2. rest 参数 3. 严格模式 ...

最新文章

  1. js的apply方法使用详解,绝对NB
  2. 30个非常有吸引力的黑色网站设计作品
  3. 汉文博士 0.5.6 正式版发布
  4. 31.CSS3变形效果【下】
  5. Java中当前的时间的各种写法
  6. mysql表空间_浅谈mysql中各种表空间(tablespaces)的概念
  7. WebMatrix经典案例
  8. 公司组织框架以及人员信息同步到钉钉相关解决方案
  9. python读写word、excel、csv、json文件
  10. 动态链接库(共享库).so文件的使用
  11. for_else,break——python小练
  12. linux查服务器硬件PN号,查看linux系统常用的命令,Linux查看系统配置常用命令
  13. Access2016学习8
  14. Shiro学习(22)集成验证码
  15. android直接连接本地数据库文件,Android 直接连MySQL数据库
  16. 网易web安全:课后问题-CSRF
  17. 大盘点!进口+国产28款分子POCT设备分析
  18. 可以免费做题,免费查答案的模拟计算机等级考试软件
  19. 数值越界mysql_Mysql数据读取越界问题
  20. R语言学习之科学计算——求导与积分

热门文章

  1. PO、VO、BO、DTO、POJO、DAO之间的关系
  2. 识别图书ISBN号并输出查询结果的示例 | Marshal's Blog
  3. DIV+CSS样式表命名的规则方法
  4. JS基础知识(数据类型)
  5. 狡兔死,良弓藏-每个王朝都一样
  6. php 判断设备是手机还是平板还是pc
  7. layer 刷新某个页面
  8. BZOJ4817 [SDOI2017]树点涂色
  9. 除法求模中求逆元的两种方法
  10. Linux下vsftpd的安装,Java上传文件实现。