ES6学习(二):函数的扩展
chapter07 函数的扩展
7.1 函数默认值
7.1.1 参数默认值简介
传统做法的弊端(||):如果传入的参数相等于(==)false的话,仍会被设为默认值,需要多加入一个if判断,比较麻烦。
参数变量是默认声明的,不可在函数体内部重复声明。
参数的默认值会在每次调用的时候重新计算
7.1.2 和解构赋值默认值结合使用
用两个例子来说明
Example1
function foo({x, y=5}) {
console.log(x, y);
} foo({}) // undefined, 5
foo({x:1}) // 1, 5
foo({x:1, y:2}) // 1, 2
foo() // TypeError: Cannot read property 'x' of undefined
Example2
function m1({x = 0, y = 0} = {}) {
return [x, y];
} function m2({x, y} = {x: 0, y: 0}) {
return [x, y];
} m1() // [0, 0]
m2() // [0, 0] m1({x: 3, y: 8}) // [3, 8]
m2({x: 3, y: 8}) // [3, 8] m1({x: 3}) // [3, 0]
m2({x: 3}) // [3, undefined] m1({}) // [0, 0]
m2({}) // [undefined, undefined] m1({z: 3}) // [0, 0]
m2({z: 3}) // [undefined, undefined]
7.1.3 参数默认值的位置
设置了默认值的参数应当在参数列表的末尾(同其他编程语言相同)
7.1.4 函数的length属性
返回没有指定默认值的参数的个数
说明:
rest参数不会被计入到length属性
如果设置了默认值得参数并不是尾参数(这样是不对滴),那么从这个设置了默认值得参数开始后面的参数都不会被计入到length属性之中。
7.2 rest参数
参考java的rest参数 ...rest rest成为了一个数组,可以用来代替arguments
rest参数之后不能有其他参数,否则报错
7.3 严格模式
ES5函数内部可以设定为严格模式
ES6规定如果函数使用了默认值、结构赋值或者扩展运算符的话,就不可以在函数体内部使用严格模式('use strict')
这是因为函数在执行的时候会先执行函数参数,再执行函数体。但是从函数体才可以知道参数是否应该以严格模式执行,但是参数却已经先于函数体执行。
规避方法:
- 设定全局的严格模式
- 讲函数包裹在一个无参的立即执行函数内部
7.4 函数的name属性
函数的name属性返回函数名称
如果一个匿名函数被赋值给一个变量
ES5的name属性会返回空字符串
ES6的name属性会返回真正的函数名称
如果一个具名函数被赋值给一个变量
- ES5和ES6均会返回具名函数声明时的名称
Function构造函数返回的函数实例,name属性值返回anonymous
bind返回的函数,name属性值之前会加上bound前缀
7.5 箭头函数
7.5.1 基本用法
var f = v => v
等价于
var f = function(v) {
return f;
}
var f = () => 5;
等价于
var f = function() {
return 5;
}
var (num1, num2) => num1 + num2
等价于
var (num1, num2) => {return num1 + num2;}
等价于
var sum = function (num1, num2) {
return num1 + num2;
}
var getTempItem = id => ({id: id, name: 'Temp'});
const full = ({first, last}) => last + " " + last;
7.5.2 箭头函数的注意事项
- 箭头函数没有this,在箭头函数的内部使用this的话,这个this指向的是箭头函数声明时所在的对象
- 不可以用箭头函数当构造器(因为箭头函数是没有this的)
- 不可以使用arguments对象,该对象在箭头函数函数体内部不存在。如果想使用的话,就用rest参数
- 不可以使用yield命令,因此不可以用作Generator函数
- arguments、super和new.target变量在箭头函数的内部都是不存在的
- 由于箭头函数的内部不存在this,故call()、apply()和bind()函数都是不可用的。
7.6 绑定this
函数绑定运算符 ::
::的左边是一个对象
::的右边是一个函数
该运算符会自动讲左边的对象作为上下文环境
由于该运算符返回的还是原对象,所以可以链式调用
7.7 尾调用优化
7.7.1 尾调用优化概念
某个函数的最后一步是调用另一个函数
以下情况不属于尾调用
function f(x) {
let y = g(x);
return y;
}
//还有赋值操作
function f(x) {
return g(x) + 1;
}
//调用之后还有操作
function f(x) {
g(x)
}
// 实质为return undefined
7.7.2 尾调用优化
尾调用由于是函数的最后一步操作,所以不需要保存外层函数的调用栈,可以节省内存,这就是尾调用优化的意义。
只有不再用到外层函数的内部变量,内部函数的调用帧才会取代外层函数的调用帧,否则无法进行尾调用优化
7.7.3 尾递归
我调我自己
阶乘的尾递归实例
function factorial(n, total) {
if (n === 1) return total;
return factorial(n - 1, n * total)
}
factorial(5, 1) // 120
斐波那契数列的尾递归实例
// 非尾递归
function Fibonacci(n) {
if (n <= 1) return 1;
return Fibonacci(n - 1) + Fibonacci(n - 2);
}
// 尾递归优化
function Fibonacci(n, ac1 = 1, ac2 = 2) {
if (n <= 1) return ac2;
return Fibonacci(n - 1, ac2, ac2 + 1)
}
7.7.4 实现尾递归
尾递归的实现在于改线原有函数使得保证最后一步仅仅调用自己。
实质是讲调用的内部函数所需要用到的外部函数的局部变量作为参
数传递给内部函数,从而切断内部函数对外部函数的调用。
实现方法有以下几种:
- 在尾递归函数之外提供一个正常形式的函数
- 使用函数式编程中的柯里化,讲多参数的函数转换为单参数的函数
- 使用ES6的函数参数默认值
function factorial(n, total = 1) {
if (n === 1) return total;
return factorial(n-1, n*total);
}
factorial(5) // 120
递归本质上是一种循环操作,纯粹的函数式编程语言没有循环操作命令,所有的循环都是使用递归实现的。在支持尾调用优化的语言,循环可以使用递归代替,而且递归最好使用尾递归。
7.7.5 严格模式
ES6的尾调用优化只会在严格模式之下开启,正常模式之下是无效的。
原因是,正常模式之下,函数内部有两个变量func.arguments和func.caller,分别返回函数调用时的参数和调用者。严格模式下会禁用这两个变量。
7.7.6 尾递归优化的实现
在不支持尾递归优化的环境中,应该自己尝试实现尾调用优化。方法例如蹦床函数等。
原则是:使用循环调用递归。具体来说,就是把递归函数的每一步改写成返回一个函数,下面是一个例子。
function sum(x, y) {
if (y > 0) return sum(x + 1, y - 1);
else return x;
}
// 优化之后
function sum(x, y) {
if (y > 0) {
return sum.bind(null, x + 1, y - 1);
} else {
return x;
}
}
7.7.8 函数参数的尾逗号
和C语言里的参数的,一致
ES6学习(二):函数的扩展的更多相关文章
- ES6 入门系列 - 函数的扩展
1函数参数的默认值 基本用法 在ES6之前,不能直接为函数的参数指定默认值,只能采用变通的方法. function log(x, y) { y = y || 'World'; console.log( ...
- ES6入门之函数的扩展
函数js原有的: 属性:arguments[].caller(调用该函数的引用,注意与callee分别开,callee指的是调用函数本身经常在递归中出现).length(形参个数).prototype ...
- ES6中对函数的扩展
ES6一路扩展,字符串.数组.数值.对象无一“幸免”,ES6说要雨露均沾,函数也不能落下,今天,就来讲解ES6对函数的扩展. 参数的默认值 在开发中,给函数的参数指定默认值,是很普遍很常见的一个需求, ...
- ES6 学习3 函数
1.函数默认参数 在ES5我们给函数定义参数默认值是怎么样? function action(num) { num = num || 200 //当传入num时,num为传入的值 //当没传入参数时, ...
- ES6介绍二 函数的增强
ES6对于函数的使用新增了很多实用的API,JS的函数跟很多后台语言PHP,ASP.NET开始看齐: 1. 参数默认值: 以前我们为了给函数创建默认值,必须用一种冗杂的语句,而且有歧义的语句. //E ...
- ES6学习之函数扩展
函数默认参数 function test(x = 1, y = 2) { return x + y } test(5, 6) test() 若默认参数在必须参数之前,要想取得默认参数,只有当传入的值为 ...
- js-ES6学习笔记-函数的扩展
1.ES6函数参数的默认值,直接写在参数定义的后面.参数变量是默认声明的,所以不能用let或const再次声明. function Point(x = 0, y = 0) { this.x = x; ...
- ES6学习历程(字符串的扩展)
字符串的扩展 在看这一节的时候前半部分写的都是关于unicode的内容,我个人感觉这部分在实际的开发中用的很少,所以不打算在做记录,等届时用到再有针对性的看,所以就将在ES6里面关于字符串操作的一些新 ...
- ES6 学习6 数组的扩展
本章学习要点: 扩展运算符 Array.from() Array.of() 数组实例的 copyWithin() 数组实例的 find() 和 findIndex() 数组实例的 fill() 数组实 ...
- JavaScript学习笔记--ES6学习(四) 字符串的扩展
ES6对字符串进行了一些扩展,主要表现在对Unicode 大于\uFFFF的字符的处理上. 1. ES6中字符的Unicode表示方法 在ES5中,字符串的Unicode表示方法: \uxxxx . ...
随机推荐
- IIS上部署网站问题总结
主要是对使用IIS过程遇到的问题的一些简单总结: 1. 当部署完web系统后,通过浏览器访问,如果遇到问题,一定要仔细阅读抛出来的error信息,很重要!很重要!很重要!说三遍. 2. 当每次尝试修改 ...
- Proxy模式(代理[延迟]模式)
Proxy?? Proxy是"代理人"的意思,它指的是代替别人进行工作的人.代理实际上就是使用委托的机制,在代理的过程中你可以做点其他的事情,然后再来执行被代理对象的代码. 知识储 ...
- Windows安装IIS后,启动网站报错:不能在此路径中使用此配置节……
在IIS里启动设置好的网站(ASP.net网站),浏览器报如下错误: 不能在此路径中使用此配置节.如果在父级别上锁定了该节,便会出现这种情况.锁定是默认设置的(overrideModeDefault= ...
- Java ping 主机 端口
22:04:08.002 [main] INFO Ping - 目标地址 192.168.1.107 是否可到达:true 22:04:08.006 [main] INFO Ping - 执行命令 p ...
- php函数超实用
DateTime DateTime::addDateTime::diffDateTime::formatDateTime::modifyDateTime::sub... * DateInterval ...
- C# 几种数据类型转换方式
1.(int)变量名[强制类型转换] 该转换方式主要用于数字类型之间的转换,从int类型向long,float,double,decimal 类型转换可以使用隐式转换,但从long型到int 就需要使 ...
- 发布MVC网站的时候出现缺少WebHost等程序集问题的解决办法
将一下几个dll 拷贝到bin文件夹下就行 链接:https://pan.baidu.com/s/17xhTdakzM_SQmOjJdZvviw 密码:c976
- GitHub上易于高效开发的Android开源项目TOP20--适合新手
1. android-async-http android-async-http是Android上的一个异步.基于回调的HTTP客户端开发包,建立在Apache的HttpClient库上. 2. an ...
- HhashMap HashTable ConcurrentHashMap
hashMap hashTable concurrentHashMap hashMap的效率高于hashTable,hashMap是线程不安全的,并发时hashMap put方法容易引起死循环,导致c ...
- 微软AI发布会,集齐六大亮点召唤黑科技!
7月12日,微软合作伙伴大会Inspire在华盛顿特区如火如荼地举行.同一天,在相隔5个时区的伦敦,微软还举办了一场关于人工智能的发布会.这是一场智能技术和情感体验两相交融的科技盛宴,既有黑科技,也有 ...