第七章 函数的扩展

7.1函数参数的默认值

7.1.1基本用法:

在es6之前,不能直接为函数的参数指定默认值,只能采用变通的方法。
es6
允许函数的参数设置默值,会直接写在参数定义的后面。

function log(x,y='word'){
console.log(x,y)

}
log('hello')//hello  word
log('hello','a')//hello a

参数变量是默认声明的,就不能用let或者const再次声明。会报错。
使用参数默认值时,函数名不能有同名参数。
默认参数值不是传值的,而是每次都重新计算默认值表达式的值,就是参数默认值是惰性求值的。

7.1.2与解构赋值默认值结合使用

只有当函数的参数是一个对象时,变量x,y才会通过解构赋值而生成,付过函数调用时参数不是对象时,变量就不会生成,而是会报错。另外只有某个参数设置默认值后,后面又没有重新赋值,默认值才会生效。如下》

function  foo({x,y=8}){
console.log(x,y)
}
foo({})//undefined,8
foo({x:1})//1,8
foo({x:1,y:0})//1,0
foo()//报错 

7.1.3

通常,定义了了默认值的参数应该是函数的尾数,因为这样比较容易看出到底省略了哪些参数,如果非尾部的参数设置默认值,实际上这个参数是·无法省略的。

例子:
function(x=1,y){
return[x,y];
}

f()//[1,undefined];
f(2)//[2,undefined];
f( ,1)//报错
f(undefined,1)//[1,1]
例子二:
function f(x,y=6,z){
return [x,y,z];
}
f()//[undefined,6,undefined]
f(1)//[1,6,undefined];
f(1, ,2)//报错
f(1,undefined,2)//[1,6,2]
在上面中,有默认参数值都不是尾参数,这时,无法省略该参数而不省略其后的参数,除非显示输入undefined,就触发默认值。null没有这个效果。
如果传得是null,打印的也会是null。

7.1.4函数的length属性

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

如果设置了默认值的参是不是尾数,那么length属性也不再计入后面的参数,只算默认值前面的参数。

7.1.5作用域

一旦设置了参数的默认值,函数进行声明初始化的时候,参数会形成一个单独的作用域。等到初始化结束时,这个作用域就会消失,这种语法行为在不设置默认值的时候是不会出现的。

var x=1;
function f(x,y=x){
console.log(y)

}

f(2)//2;

上面代码中,参数y的默认值是x,调用函数y 的时候,参数形成一个单独的作用域。在这个作用域里面,默认值变量x指向第一个参数x,而不是全局变量x,所以输出的是2.

7.2rest参数

es6引入了rest参数(形如"...变量名"),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest参数搭配的变量是一个数组,该变量将多余的参数放入其中。
rest参数中的变量代表一个数组。所以数组特有的方法都可以用于这个变量。
函数的length不包括rest参数。rest参数只能是最后一个参数,否则会报错;

7.3严格模式。

ES6规定只要函数参数使用了默认值、解构赋值或者扩展运算符。那么函数内部就不能显示设定为严格模式,否则会报错。
是因为函数内部的严格模式同时适用于函数体和函数参数。但是,还是执行时候,先执行函数参数,然后在执行函数体,这样就有一个不合理的地方,只有函数体之中才能知道参数是否应该以严格模式执行,但是参数却先与函数体执行。
但是有两种方法可以规避这种限制。
第一种是设定全局的严格模式,这是合法的
第二种就是把函数包在一个无参数的立即执行函数里面。

7.4name属性

函数的name属性返回的是函数的函数名。
如果讲一个匿名函数赋值给一个变量,es5返回的是一个空字符串,es6返回的name属性则会是是实际的函数名。
如果讲一个具名函数赋值给一个变量,es5和es6的name属性都返回的的这个具体的函数名的名字。
Function构造函数返回的函数实例,name的属性的值为anonymous。

(new Function).name=anonymous


foo.bind({}).name//"bound foo"

(function(){}).bind({}).name//"bound"

bind返回的函数,name属性值会加上bound前缀。

7.5箭头函数

7.5.1基本用法

es6允许使用箭头函数

var f=v=>v;
上面的代码等于以下的代码
var f=function(v){
return v;
}

如果箭头函数不需要参数或者需要多个参数的话,就是用圆括号代表参数部分。

var  f=()=>5;
等同于
var f =function(){
return 5
}
var sun =(num1,num2)=>num1+num2;
等于
var sun =function(num1,num2){
return num1+num2;
}

如果箭头函数的代码块部分多于一条语句,就要使用大括号将其括起来,并使用return 语句返回。

var sum =(num1,num2)=>{return num1+num2}

由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号。

var get=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 number=(...nums)=>nums;
numnber(1,2,3,4,5)//1,2,3,4,5


const headTil=(head,...tail)=>[head ,tail]

headTil(1,2,3,4,5)//[1,[2,3,4,5]]

7.5.2注意事项

1.函数体内的this对象就是定时所在的对象,而不是使用时所在的对象。
2.不可以当做构造函数,也就是到货,不可以使用new命令,否则会抛出一个错误。
3.不可以使用arguments对象想,该对象在函数体内不存在,如果要用们可以用rest参数进行代替。
4.不可以使用yield命令,因此箭头函数不能用作Generator函数。

es5 中this的指向是可变的,但是在箭头函数中他是固定。除了this,一下3个函数在箭头函数中也是不存在的分别指向外层函数的对应变量:arguments super 和new.target。
另外,由于箭头函数没有自己的this。当果然也不能用call() /apply()/bind()这些方法改变this 的指向。

7.5.3嵌套的箭头函数

箭头函数还可以嵌套箭头函数。

下面是一个部署管道机制的例子,就是前一个函数的输出值是后一个函数的输入值。
const pipeline=(...funcs)=>
val=>funcs.reduce((a,b)=>b(a),val));
const plus1=a=>a+1;
const plus2=a=>a*2;
const  add=pipelline(plus1,plus2);


add(5);//12

还可以写成以下的形式
const plus1=a=>a+1;
const plus2=a=>a*2;
plus2(plus1(5))//12

7.6绑定this

箭头函数可以绑定this的对象,减少了显示绑定this对象的写法,call apply bind

函数绑定运算符是并排的双冒号::。双冒号左边是一个对象,右边是一个函数,该运算符会自动将左边的对象作为上下文环境绑定到右边的函数。

foo::bar ;
等同于、
bar .bind(foo)


如果双冒号左边是空的,,右边是一个对象,则等于将该方法绑定在对象上。


var method=obj::obj.foo
等于
var method=::obj.foo


let log =::console.log;
等于:
var log =console .log.bind(console);

由于双冒号运算符返回的是还是原对象,因此可以采用链式写法。

7.7尾调用优化

7.7.1

尾调用是函数式编程的一个重要概念,非常简单,就是指某个函数的最后一步是调用另一函数。


funcrion f( x){
return g(x);
}
上面代码中,函数f的最后一步是调用函数g,就叫做尾调用。

funcrion f( x){
let y=g(x);

return y;
}

因为最后一步的是赋值,所以不属于尾调用。,调用后还有操作的都不属于尾调用。

7.7.2尾调用优化

,尾调用之所以跟其他的不提用,就是因为他的特位置、。
只有不再用到外层函数的内部变量,内层函数的调用帧才会取到外层函数的调用帧,否则就无法进行"尾调用优化"

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

推荐阅读更多精彩内容