ES6对函数的扩展总要将两件事,一个是函数的参数,一个是箭头函数,这两点扩展为JS代码编写来说是两个大大的惊喜,未来我们会经常用到这两个新特性。
ES6中函数的参数
与之前的版本不同,ES6中函数的参数有几个值得注意的新特性.
1、ES6允许为函数的参数设置默认值
从前JS的函数不能像其他编程语言那样设置默认值,通常在写函数时首先要对参数进行判断,如果没传参数,给定一个默认值。
function fun1(param)
{
var param = param || "empty";
return param;
}
console.log(fun1(1),fun1(),fun1(undefined),fun1(0),fun1(""),fun1(false),fun1(null))
//1 "empty" "empty" "empty" "empty" "empty" "empty"
PS:||符号运算规则
如果“||”前面为true,不管“||”后面是true还是false,都返回“||”前面的值。
如果“||”前面为false,不管“||”后面是true还是false,都返回“||”后面的值。
这样写有个问题,那就是“||”运算时,会进行类型转换,导致传入空字符串、0、false、undefined和null时和没传递参数是一样的,而实际上从语义上来说,只有不传参,或传入undefined才算没有传参,如果要避免这个情况还要进行其他的判断。
ES6加入了能够为参数设置默认值,这样不仅在书写上更加方便,也避免了上述出现的问题
function fun2(param="empty")
{
return param;
}
console.log(fun2(1),fun2(),fun2(undefined),fun2(0),fun2(""),fun2(false),fun2(null)) //1 "empty" "empty" 0 "" false null
实际上这种写法是利用了函数的arguments对象,编译成ES5的语法是这样的:
function fun2() {
var param = arguments.length <= 0 || arguments[0] === undefined ? "empty" : arguments[0];
return param;
}
函数有多个参数时,如果只给部分的参数设置默认值,那么有默认值的参数要放到最后。如下面的例子中,因为a,b有默认值,如果希望只能c传值的话,第一种写法是错误的。
function fun1(a=1,b=2,c) {
console.log(a,b,c)
}
fun1(3); //3 2 undefined
function fun2(c,a=1,b=2) {
console.log(a,b,c)
}
fun2(3); //1 2 3
2、参数默认值可以与解构赋值的默认值,结合起来使用。
在ES6 声明与表达式中讲解构赋值的作用时,说过解构赋值可以定义函数参数并设置默认值,有这样一个例子
function fun({name,age,gender='male'}){
console.log(`姓名:${name},年龄:${age},性别:${gender}`);
}
fun({name:"Lily",age:"18",weight:"50"}); //姓名:Lily,年龄:18,性别:male
函数fun的参数是一个对象,这个例子中如果调用fun不传递参数的话,会报错(Uncaught TypeError),这是因为函数中参数的属性设置了默认值,但是没有给参数设置默认值
function fun({name,age,gender='male'}={}){
console.log(`姓名:${name},年龄:${age},性别:${gender}`);
}
fun(); //姓名:undefined,年龄:undefined,性别:male
3、剩余参数的使用
在介绍解构赋值的时候,说到过Rest运算符和扩展运算符( … ),可以去温习一下。
下面的例子中fun的形参…rest表示一个参数序列,rest表示一个数组,他们正好是相反的。
如下,在调用fun(…[1,2,3])时,看起来像是传递了一个数组,其实不是的,扩展运算符( … )将一个数组转为用逗号分隔的参数序列,fun(…[1,2,3])和fun(1,2,3)是一样的。
function fun(...rest)
{
console.log(rest,...rest);
}
arr=[1,2,3];
fun(...arr); //[1, 2, 3] 1 2 3
再看一个例子,本例中…rest是fun函数除第一个参数以外的所有参数的序列化。…rest在不确定参数数量时非常有用
function fun(first,...rest)
{
console.log(first,rest);
}
fun(1,2,3); //1 [2,3]
箭头函数
ES6标准新增了一种新的函数:Arrow Function(箭头函数)
过去定义一个函数可以使用函数声明或者函数表达式的方式,语法是:
function 函数名(){}
var 函数名 = function(){}
箭头函数的写法:
- function”关键字和函数名都删掉,并使用“=>”连接参数列表和函数体。
- 函数参数只有一个,括号可以省略;但是没有参数时,括号不可以省略。
- 箭头函数的函数体重如果只包含一个表达式,省略掉了{ … }和return,但是如果这个表达式是一个对象的话要用小括号包裹。
function fun1(x,y){
return x+y
}
var fun2=function(x,y){
return x+y;
}
//箭头函数写法
let fun3=(x,y)=>x+y;
//只有一个参数,省略小括号,函数体只有一个表达式,省略{}和return,只有一个参数
x=>x*x
//没有参数,不能省略()
var fun=()=>console.log('没有参数');
将x=>x*x编译成ES5,代码是这样的:
"use strict";
(function (x) {
return x * x;
});
匿名函数和箭头函数的区别
箭头函数相当于匿名函数,并且简化了这种函数定义,但是箭头函数和匿名函数函数有一定的区别的:
- 箭头函数中没有自己的this,箭头函数内的this就是箭头函数外的那个this。
- 箭头函数中没有arguments对象,箭头函数内的arguments就是箭头函数外的那个arguments。
下面的代码中希望如果对象p的国籍是中国的话,调用它的方法getfullName时,返回他的姓名而不是名姓。
var p={
firstName:"三",
lastName:"张",
nationality:"Chinese",
getFullName:function () {
console.log('getFullName()中:\n',this,arguments);
function connect() {
console.log('connect()中:\n',this,arguments);
if(this.nationality==="Chinese") return this.lastName+this.firstName
}
return connect();
}
}
//随便传入2个参数用于区分arguments对象
console.log(p.getFullName(1,2));
这个例子中,并没有的得到我们要的结果,并且函数getFullName和connect中都有自己的this和arguments。
还记得在函数入门篇关于函数的调用,有这样的说法吗?
1、函数调用模式: 函数名();
调用函数实际上就是调用某个对象的方法,如果函数名前没有对象,那么意味着调用的是window对象的方法,这时的this指向window。
2、方法调用模式: 对象.函数名();
this:谁调用就指向谁
在上面的例子中getFullName()作为对象p的方法调用,其内部的this就是p,但是方法中的connect是作为函数调用的,非严谨模式里面的this指向window,严谨模式this为undefined。
下面把代码稍微改造一下,在执行getFullName方法时,将此时的this赋值给一个变量_this,之后获取_this的属性来得到想要的结果
var p={
firstName:"三",
lastName:"张",
nationality:"Chinese",
getFullName:function () {
var _this=this;
console.log('getFullName()中:\n',this,arguments);
function connect() {
console.log('connect()中:\n',_this,arguments);
if(_this.nationality==="Chinese") return _this.lastName+_this.firstName
}
return connect();
}
}
console.log(p.getFullName(1,2)); //张三
现在改用箭头函数来写
var p={
firstName:"三",
lastName:"张",
nationality:"Chinese",
getFullName:function () {
console.log('getFullName()中:\n',this,arguments);
let connect=()=> {
console.log('connect()中:\n',this,arguments);
if(this.nationality==="Chinese") return this.lastName+this.firstName
}
return connect();
}
}
console.log(p.getFullName(1,2));
为什么会这样呢?实际上把上面的代码编译成ES5,就非常清楚了
var p = {
firstName: "三",
lastName: "张",
nationality: "Chinese",
getFullName: function getFullName() {
var _this = this,
_arguments = arguments;
console.log('getFullName()中:\n', this, arguments);
var connect = function connect() {
console.log('connect()中:\n', _this, _arguments);
if (_this.nationality === "Chinese") return _this.lastName + _this.firstName;
};
return connect();
}
};
console.log(p.getFullName(1, 2));