一,ES6
的参数默认值
1.在es5
中并没有实现函数的参数默认值,而ES6
实现了这部分功能,使函数的参数默认值书写更为简洁,直观。
{
function defalutArg(name='max',age=21)
{
let info = name + ' is ' + age +' years old';
return info
}
console.log(defalutArg('miko')) // miko is 21 years old
console.log(defalutArg('jim',30)) // jim is 30 years old
}
2.函数参数默认值可以是任何合理的表达式,且每次调用都会重新计算默认值表达式的值。
{
let n=100
function addY(x=0,y=n+1)
{
return x+y+n
}
console.log(addY(10)) // 211
n=90
console.log(addY(10)) //201
}
3.可以使用解构赋值为参数设置默认值。
{
function introduce({name,age,id}={name:'max',age:21,id:1})
{
let introTemplate =`${id}: my name is ${name},i am ${age} years old.`
let info = introTemplate;
return info
}
console.log(introduce()) // 1: my name is max,i am 21 years old.
}
二,rest
参数
1.rest
参数接受函数的多余参数,组成一个数组,放在形参的最后,形式为...arg
。注意rest
参数后不能在有形参,即rest
参数要放在最后面,否则会报错。
{
function intro(name,age,...details)
{
return details
}
console.log(intro('lin',23,'male','china')) // ["male", "china"]
function err(name,...details,age)
{
return details
}
console.log(err('lin',23,'male','china')) //Rest parameter must be last formal parameter
}
2.rest
参数和arguments
的区别:
arguments
包含传入的所有参数,rest
参数只包含没有直接声明的参数
arguments
是一个类数组对象,而rest
参数是一个真正的数组,可以使用数组的所有方法。
函数的length
属性,不包含rest
参数
3.rest
参数可以被结构化,类似于数组的解构赋值
{
function f(...[a, b, c]) {
return a + b + c;
}
f(1) //NaN 因为只传递一个值,b 和 c = undefined
f(1, 2, 3) // 6
f(1, 2, 3, 4) // 6 (第四值没有与之对应的变量名)
}
三,箭头函数
1.ES6
标准新增了一种新的函数:箭头函数,也称“胖箭头函数”, 允许使用“箭头”(=>
)定义函数,是一种简写的函数表达式。
2.箭头函数的形式
// 一个参数对应一个表达式
param => expression;// 例如 x => x+2;
// 多个参数对应一个表达式
(param [, param]) => expression; //例如 (x,y) => (x + y);
// 一个参数对应多个表示式
param => {statements;} //例如 x = > { x++; return x;};
// 多个参数对应多个表达式
([param] [, param]) => {statements} // 例如 (x,y) => { x++;y++;return x*y;};
//表达式里没有参数
() => expression; //例如var flag = (() => 2)(); flag等于2
() => {statements;} //例如 var flag = (() => {return 1;})(); flag就等于1
//传入一个表达式,返回一个对象
([param]) => ({ key: value });
//例如 var fuc = (x) => ({key:x})
var object = fuc(1);
alert(object);//{key:1}
3.箭头函数的性质特点
(1)箭头函数本身没有this
,当在箭头函数使用了this
对象,该this
对象是父作用域的this
对象,和调用方式无关。且要注意,箭头函数的this
是被定义时处于的上下文的this
,而不是箭头函数被调用时处于的上下文。
{
let cat={
name:'nancy',
sex:'female',
voice:'maoomaoo',
catVoice:()=>this.voice
}
console.log(cat.catVoice()) //undefined catVoice的父作用域为块作用域。块作用域的this指向window
}
{
let cat={
name:'nancy',
sex:'female',
voice:'maoomaoo',
catVoice:function()
{
let f = ()=>this.voice
return f()
}
}
console.log(cat.catVoice()) // 'maoomaoo'
let fn=cat.catVoice
console.log(fn()) // 'undefined'
}
执行cat.catVoice()
时,箭头函数f
的父作用域是函数catVoice
的函数作用域,catVoice
函数通过对象的方法被调用,所以catVoice
函数的this
指向当前对象cat
, 因此箭头函数的this
也指向cat
,最后返回'maoomaoo'
当执行fn()
时,catVoice
函数被裸调用,因此catVoice
的this
指向全局对象window
,f
的this
对象随即指向window
,所以返回undefined
。
总结,箭头函数的this指向
由父作用域的this指向
决定
(2)箭头函数没有arguments
关键字,要想接受不定参数,需使用rest
参数。
{
let fn =(...[a,b,c])=>a+b+c
console.log(fn(1,2,3,4)) // 6
}
(3)箭头函数没有原型属性
{
let add = (x,y)=>x+y
console.log(add.prototype) // undefined
}
(4) 箭头函数不能作为构造函数,也没有new
操作,因为箭头函数都没有this
,
四,尾调用(Tail Call)
1.尾调用用一句话说就是某个函数的最后一步操作是调用一个函数,则称为尾调用
// 情况一
function f(x){
let y = g(x);
return y;
}
// 情况二
function f(x){
return g(x) + 1;
}
//情况三
function f(x){
return g(x);
}
情况一和情况二都不是尾调用,情况三属于尾调用。
2.尾调用由于是函数的最后一步操作,所以不需要保留外层函数的调用记录,因为调用位置、内部变量等信息都不会再用到了,只要直接用内层函数的调用记录,取代外层函数的调用记录就可以了。如果所有函数都是尾调用,那么完全可以做到每次执行时,调用记录只有一项,这将大大节省内存。我们称之为尾调用优化。
3.在ES6的严格模式下,才有尾调用优化。
参考:
https://segmentfault.com/a/1190000019102902
https://www.cnblogs.com/mengff/p/9656486.html
http://www.ruanyifeng.com/blog/2015/04/tail-call.html