函数的扩展
目录
一.函数参数的默认值
1. 基本用法
-
ES6之前,不能直接为函数的参数设置默认值,只能在函数体内进行判断并给它赋默认值
//判断y是否存在,不存在则给它默认值 'world' function func(x,y){ y ? y : 'world'; console.log(x + y); }
-
ES6允许为函数的参数设置默认值,即直接写在参数定义的后面**
- 注意:
- 函数的参数是默认声明的,不能使用 let 和 const 再次声明
- 参数默认值是惰性求值,只有当需要用到的时候,才会重新计算
function func(x,y = 'world'){ console.log(x + y); } func('hello'); //helloworld func("hello",""); //hello
2.与解构赋值默认值结合使用
-
参数的默认值可以和解构赋值的默认值结合使用
-
思考:下面两种写法,有什么区别
function m1({x = 0,y = 0} = {}){ console.log(`[${x},${y}]`) } function m2({x,y} = {x:0,y:0}){ console.log(`[${x},${y}]`) }
- 第一种写法,函数参数的默认值是空对象,但是,设置了对象解构的默认值
- 第二种写法,设置了函数参数的默认值,但是没有设置对象解构的默认值
m1(); //[0,0] m2(); //[0,0] m1({x:3}); //[3,0] m2({x:3}); //[3,undefined] m1({x:3,y:5}); //[3,5] m2({x:3,y;5}); //[3,5] m1({}); //[0,0] m2({}); //[undefined,undefined]
3.参数默认值的位置
-
看如下示例
function func(x=0,y){ console.log(`[${x},${y}]`); } func(); //[0,undefined] func(1); //[1,undefined] func(,3); //报错 func(undefined,3); //[0,3]
-
第二个示例
function func(x,y=0,z){ console.log(`[${x},${y},${z}]`) } func(); //[undefined,0,undefined] func(1) //[1,0,undefined] func(1,,2) //报错 func(1,undefined,2) //[1,0,2]
-
总结如上两个示例,可以发现
- 如果非尾部的参数设置默认值,实际上这个参数是没办法省略的,至少得指定undefined,否则报错
- 当默认参数在最后的位置的时候,可不用指定
-
综上所述,拥有默认值的参数,一般放在参数列表的最后面
4.函数的length属性
-
指定了参数默认值的情况下,函数的length属性将只返回没有没有默认值的参数个数
(function func(x,y){}).length; //2 (function func(x=0,y){}).length; //1
5.默认参数的作用域
-
一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域,等到初始化结束,作用域就会消失。这种语法行为,在不设置参数默认值的时候,是不会出现的
- 如下示例:
var x = 1; function foo(x,y=function(){x=2;}){ var x = 3; y(); console.log(x); } foo(); //3 console.log(x); //1
- 示例解析:在以上示例中,函数的参数形成了一个单独的作用域,在作用域内部,声明了一个变量x,声明了变量y,y的默认值为一个函数,这个函数内部的x指向同一个作用域的第一个参数x。在函数内部,又声明了一个x,该变量与参数内部的x不是同一个作用域,所以不是同一个变量,因此执行y后,函数内部的x变量和函数外部的x变量都没有发生变化
- 如果去掉函数内部的 var 声明,则函数内部的x变量和函数的第一个参数x是同一个变量,所以执行完y()方法之后,内部的x返回2
var x = 1; function foo(x,y=function(){x=2;}){ x = 3; y(); console.log(x); } foo(); //2 console.log(x); //1
6. 应用
- 可以将函数的某些参数的默认值设置为一个抛出异常的函数,当这些参数为undefined的时候,就会抛出异常
- 将参数的默认值设置为undefined,说明该参数可以被忽略
二.rest参数
-
ES6引入了rest参数,形式为(...变量名)。用户获取函数的多余参数,这样就不需要使用arguments对象了
- 注意:rest之后不能有其它参数,否则会报错
- rest参数就是一个数组,就函数多余的参数放入数组中
- 函数的length属性,不包含rest参数
function func(...numbers){ console.log(numbers); } func(1,2,3); //[1,2,3] console.log(func.length) //0
三.严格模式
-
从ES5开始,函数内部可以设置严格模式
function func(){ 'user strict'; //code... }
-
ES6做了一点修改,规定只要函数参数使用了默认值,解构赋值,或者扩展运算符,那么函数内部就不能设定为严格模式,否则会报错
function func(x=10){ 'use strict' //...报错 }
四.name属性
-
函数的name属性,返回该函数的函数名,这个属性很早就被浏览器支持,但是在ES6中,才将其写入标准
- 注意:
- 如果将一个匿名函数赋值给一个变量,ES5的name属性将会返回一个空串,在ES6中,会返回被赋值的变量名
- 如果将一个拥有名字的函数赋值给一个变量,不论是ES5还是ES6,其name属性会返回该函数原来的名字
const f = function bar(){} f.name; // bar
- Function 构造函数返回的实例,name属性值为 anonymous
(new Function).name //annoymous
五.箭头函数
1. 基本用法
- ES6允许使用“箭头”(=>)定义函数
var f = v => v;
//等同于
var f = function(v){
return v;
}
- 如果箭头函数不需要参数或者需要多个参数,就可以 使用一个圆括号代表参数部分
var f = () => 5
//等价于
var f = function(){
return 5;
}
var f = (x,y) => x + y
//等价于
var f = function(x,y){
return x + y;
}
- 如果箭头函数直接返回一个对象,必须在对象外面加上圆括号,否则会报错
//报错
let getTempItem = id => {id:id,name:'temp'}
//不报错
let getTempItem = id => ({id:id,name:'temp'})
- 箭头函数可以和变量解构结合使用
let func = {first,lasst} => first + ',' + last
//等价于
function func({first,lasst}){
return person.last + "," + person.last;
}
- 箭头函数可以简化回调函数
- 箭头函数可以和rest参数一起使用
2. 使用注意点
-
函数内的this对象,就是定义时所在的对象,而不是使用时所在的对象
-
不可以当做构造函数,也就是说不可以使用new进行实例化,否则报错
-
不可以使用arguments对象,但是可以使用rest参数代替
-
不可以使用yield命令,因此箭头函数不能用作Generator函数
-
箭头函数中的this,详细说明
- 箭头函数没有自己的this,所以箭头函数的this总是指向定义该箭头函数的那个对象
- 箭头函数让this的指向固定化
- 除了this,以下变量在箭头函数中也是不存在的,arguments,super,new.target
示例说明
var handle = { id:'123456', init:function(){ document.addEventListener('click',event => this.doSomeThing(event.type),false) }, doSomeThing:function(type){ console.log('Handing' + type + 'for' + this.id) } };
示例解析:
- 上面代码中的init函数中使用了箭头函数,这导致箭头函数里面的this,永远指向handler对象,否则,使用this.doSomeThing调用的时候,就会报错
3. 不适用场合
- 由于箭头函数把this由动态变为静态,所以在以下场合,不应该使用箭头函数
- 定义对象的方法
- 需要动态this的时候
六.尾调用优化
1. 什么是尾调用
- 在某个函数的最后一步是调用另一个函数
function f(x){
return g(x);
}
- 没有按照上例中返回函数调用的,都不算尾调用
//非尾调用示例
function f(x){
let y = g(x);
return y;
}
function f(x){
return g(x) + 1;
}
function f(x){
g(x);
}
七.函数参数的尾逗号
- ES2017允许函数的最后一个参数可以有逗号,此前,这个都是不被允许的
总结
- ES6中,可以为函数添加默认值,默认值可以和解构赋值一起使用
- 函数默认值的位置最好放在函数参数的最后面,否则还是要在参数中使用undefined来使用默认参数,这使得默认参数没有什么意义
- 使用默认参数的函数,length返回只会返回没有默认值参数的个数
- 一旦设置了函数的默认参数,参数会形成一个单独的作用域
- ES6中新增了rest参数,rest参数可以接受所有未在函数参数列表中声明的参数,还可以代替arguments对象
- 使用了参数默认值,解构赋值和扩展运算符的函数,内部都不能指定严格模式,否则报错
- 函数的name属性可以返回函数名,将具名函数赋值给变量之后,name属性获取的还是函数的原始名
- 箭头函数可以简化函数的书写,但是得注意,箭头函数的this永远指向定义它的外城对象,箭头函数将动态的this变为了固定的