ES6中的剩余参数(不定参数)...arg,默认参数,以及解构赋值
2017-03-29 22:12

不定参数(剩余参数)

ES6中新增了不定参数的写法,在不确定函数需要多少个参数,或者函数传递的参数可以任意个的时候,可以使用不定参数。当然不定参数之前我们也可以这样传,那时我们是使用arguments对象来获取函数传递的参数。现在有了不定参数,可以说是有了专门处理这个参数个数不确定的正规途径,因为arguments对象除了可以处理函数中的参数外,还有其他的很多用途,比如Firfox中获取event对象,arguments.callee.caller.arguments[0]

但是arguments对象,在ES6的箭头函数中是不可用的,而不定参数是可以在箭头函数中使用的。

不定参数用法如下:

var cvs=document.getElementById("cvs");
var ctx=cvs.getContext("2d");
function drawline(x,y,...args){
    ctx.moveTo(x,y);
    for(var i=0;i<args.length;i++){
        ctx.lineTo(args[i].x,args[i].y);
    }
    ctx.stroke();
}
drawline(20,20,{x:30,y:70},{x:100,y:30},{x:200,y:150});
<canvas width="400px" height="200px" id="cvs">
</canvas>

效果如下:

blob.png

我们通过上面的代码,在画布中画了一条折线,drawline方法有三个形参,前两个x,y代表起始点,第三个...args表示不定参数,代表折线的点的位置。

不定参数一看就明白,写法就是"...args",在参数前面加三个点,args把剩余的参数组成一个数组传递给函数,在函数中可以像操作数组一样操作不定参数。

我们可以把上面的drawline函数用箭头函数的形式实现,它同样是可以传递不定参数的。

var cvs=document.getElementById("cvs");
var ctx=cvs.getContext("2d");
var drawline=(x,y,...args)=>{
    ctx.moveTo(x,y);
    for(var i=0;i<args.length;i++){
        ctx.lineTo(args[i].x,args[i].y);
    }
    ctx.stroke();

}
drawline(20,20,{x:30,y:70},{x:100,y:30},{x:200,y:150});

效果跟上面是一样的。但是,记住一点,不定参数只能作为函数的最后一个参数使用。

默认参数

ES6中除了不定参数,还引入了默认参数,就是可以给形参添加默认值。这样就可以简化我们的一些非空判断代码。

我们给上面的代码中添加一个绘制圆形的方法:

var cvs=document.getElementById("cvs");
var ctx=cvs.getContext("2d");
var drawline=(x,y,...args)=>{
    ctx.moveTo(x,y);
    for(var i=0;i<args.length;i++){
        ctx.lineTo(args[i].x,args[i].y);
    }
    ctx.stroke();
}
var drawCircle=(x,y,color="red",Lwidth=5,r=50,sAngle=0,eAngle=2*Math.PI,direct=true)=>{
    ctx.save();
    ctx.beginPath();
    ctx.strokeStyle=color;
    ctx.lineWidth=Lwidth;
    ctx.arc(x,y,r,sAngle,eAngle,direct);
    ctx.stroke();
    ctx.restore();
}
drawline(20,20,{x:30,y:70},{x:100,y:30},{x:200,y:150},{x:300,y:20});
drawCircle(200,100);

效果如下:

blob.png

drawCircle中除了坐标位置x,y之外,其他的参数都通过默认参数的形式给予了默认值,默认参数可以省去了我们在函数体内对参数进行非空判断设置默认值的操作。以前我们会这样做:

var color=color||"red";
var Lwidth=Lwidth||5;
var r=r||50;
.....

现在有了默认参数,我们就可以方便的使用默认参数来替代这些繁杂的判断了。但是要注意一点,默认参数虽然有默认值,但是我们实际传参过程中还是要按照参数的顺序,可以省略后面的参数使用默认值,不能省略前面的默认参数,如果你非要使用,你需要在对应的值的位置传入undefined作为参数,这样函数内部依然使用的参数的默认值。

drawCircle(50,50,undefined,2,30,undefined,Math.PI);

效果如下:

blob.png

画出一个小半圆来。undefined依然是被参数的默认值所替代,要跳过参数只能传undefined的,其他的都不行。

ES6的解构赋值

解构赋值是怎么回事呢?其实就是有点像给一个数组对象赋值的逆向操作。用来从对象或者数组中提出变量值。不能多解释,还是看代码容易理解。

var [a,b,c]=[1,2,3,4,5];
console.log(a);//1
console.log(b);//2
console.log(c);//3

这是对数组进行解构赋值操作,相当于按照数组的排列顺序,从数组中提取对应的元素赋值给定义的变量。

var {say,run}={say:"talking and talking",run:"runing and runing "};
console.log(say);
console.log(run);

打印结果如下:

blob.png

这是对一个对象进行解构赋值。记住,js中函数也是对象。

对象解构赋值中,参数名要和对象的属性名对应。

var a=20;
var b=10;
[a,b]=[b,a];
console.log(a);//10
console.log(b);//20

数组的解构赋值中,元素时变量的,可以实现变量值的互换。这个能用作排序时代码的简化。数组结构是按照顺序进行解构的。这里互换变量值正是利用了这一点。

var [,,c]=[1,2,3];
console.log(c);//3

在数组的解构赋值中你还可以像上面这样,跳过其中不需要的值。只攫取我们需要的值。

对象解构赋值中,变量名可以跟对象的属性名不同,但是需要采用下面的这种写法:

var {say:ss,run:rr}={say:"hello",run:"running"};
console.log(ss);//hello
console.log(rr);//running

这种以键值对的方式解构赋值对象,键值是对象的原属性名,value值是我们要复制的变量名。

此外,解构赋值,还可以使用上面的默认参数和不定参数,以及方括号形式的变量名计算表达式

并且解构赋值支持嵌套多个层次的赋值操作。

var key="age";
var obj={
        [key]:20,
        score:[
            {name:"yuwen",score:90},
            {name:"math",score:100},
            {name:"english",score:80}
         ],
        name:"mooshine",
        star:"five"
    };
var {[key]:howold,score:[,,{score:fen}],sex="female"}=obj;
console.log(howold);//20
console.log(fen);//80
console.log(sex);//female

上面的实例代码中,我们对于[key]使用了属性名计算表达式,对于fen使用了嵌套嵌套解构赋值的方式,对于sex使用了默认值,obj对象中没有这个属性,所以sex取了默认值。

var arr=[1,2,3,4,5];
var [a,...args]=arr;
console.log(args);//[2,3,4,5]

上面的代码中我们对数组的解构赋值使用了不定参数,不定参数包含数组中的剩余项。这里要提一下,网上有对ES6解构赋值中解读这里的"...args"为扩展运算符。

但是,我认为这里不是扩展运算符,而是不定参数。不定参数的作用是将多个变量整合成一个数组,而扩展运算符是将数组拆分成多个变量。

有两点可以证明我的观点:

1,不定参数只能放在最后一位,这里的”...args“只能放在最后,否则会报错。

2,args返回的结果是一个数组"[2,3,4,5]",这里符合不定参数的定义。

回过头来看我们的画布中实现的图像画折线方法中,可以使用解构赋值的操作

var cvs=document.getElementById("cvs");
var ctx=cvs.getContext("2d");
var drawline=(x,y,...args)=>{
    ctx.beginPath();
    ctx.moveTo(x,y);
    for(var {x:cx,y:cy} of args){
        ctx.lineTo(cx,cy);
    }
    ctx.stroke();
}
drawline(20,20,{x:30,y:70},{x:100,y:30},{x:200,y:150},{x:300,y:20});

效果和上面的例子是一样的。for...of是用来遍历Array,Map,set等集合对象的语法。在for...of遍历中通过解构赋值,可以简化变量值的获取。

当然,你也可以在普通for循环中的代码里面对args[i]对象进行解构赋值也是可以的。

var cvs=document.getElementById("cvs");
var ctx=cvs.getContext("2d");
var drawline=(x,y,...args)=>{
    ctx.beginPath();
    ctx.moveTo(x,y);
    for(var i=0;i<args.length;i++){
        var [cx,cy=0]=args[i];
        ctx.lineTo(cx,cy);
    }
    ctx.stroke();
}
drawline(20,20,[30,70],[100,30],[200,150],[300]);

这个代码,我们改变了画折线方法中传递点位置的形式,通过数组的方式传递,并且在结构赋值的时候,给cy=0添加了默认值,注意最后一个[300]没有传递cy值,cy取的默认值0。要实现上面同样的逻辑代码,不使用解构赋值和默认值的话,代码量会增加好几行呢。

效果如下:

blob.png

折线的最后一个点取了默认值,所以有所改变。

总结

默认值,不定参数也好,解构赋值也好,其目的都是为了简化我们的代码书写,提高我们的编程效率。如果你理解了默认值和不定参数,你应该会有些疑问。没错,你的疑问是对的,默认值和不定参数是不能同时使用的,他们两个本身就是互斥的。今天在群里,听大神们说,angularJs2中使用TypeScript开发,TypeScript不只提供了对js语法的静态验证(比如类型注解,接口之类的东西用于验证js代码的正确性),并且还提供了对ES6语法的支持。这么看来,学习掌握ES6的相关语法是很必要的。

原创文章,转载请注明来自:妹纸前端-www.webfront-js.com.
阅读(6593)
辛苦了,打赏喝个咖啡
微信
支付宝
妹纸前端
妹纸前端工作室 | 文章不断更新中
京ICP备16005385号-1