0%

ECMAScript6学习简记(三)- 函数扩展

1.函数参数默认值

以前我们经常会些下面的代码

function doS(e){
e = e|window.e;
//doSomeThing with e
}

通过这样的方法来给函数设置默认值,这样有一个缺点就是,如果传进来的参数对应的布尔值为false,比如空字符串或者0,那就尴尬了。

所以如果我们还想上面的代码得到正确的结果,就需要对e在做一个判断,判断它是否被赋值了。

这样会很麻烦,所以ES6有了新的方法,如下

function doS(e=window.e){
//doSomeThing with e
}

这样不尽代码简短了很多,而且可读性大大提高,看代码的人可以一样看到那些参数是有默认值的。

同时,默认值的设置也非常人性化

function get(url,{body='',method='GET'){
console.log(method);
}

上面的代码中,传入第二个参数是一个对象,我们可以给对象的属性设置默认值。

甚至还可以设置双重默认值。

fetch(url, { method = 'GET' } = {}){
console.log(method);
}

上面代码中,调用函数fetch时,如果不含第二个参数,则默认值为一个空对象;如果包含第二个参数,则它的method属性默认值为GET。

参数的默认值设置同样支持解构赋值,

function ha({x,y=5}){
console.log(x,y);
}
ha() //TypeError: Cannot read property 'x' of undefined
ha({}) //undefined 5
ha({x:1}) //1 5
ha({x:1,y:2}) //1 2

定义默认值的参数,必须在参数的尾部,因为有了默认之后参数可以被省略,而只有位于尾部,函数才能判断到底省略了那个参数。

如果给设置默认值的参数传入undefinednull,前者该函数会触发默认值,而后者不会。

function a(b=1,c=2){
console.log(b,c);
}
a(undefined,null);
//1 null

需要注意的是,如果设置了默认值,那么函数的length属性会失真

> (function a(a,b){}).length
2
> (function b(a,b,c){}).length
3
> (function c(a,b,c=1){}).length
2
> (function e(a,b=1,c=1){}).length
1

可以看到,没设置默认值的时候,函数的length等于它的参数个数,而设置了默认值之后,它的length值等于没有设置默认值的参数的个数。

2.rest参数

rest参数用于获取函数的多余变量,这样可以避免使用arguments对象。

function add(...values) {
let sum = 0;
values.forEach(function(value){
sum += value;
});
return sum;
}
> add(1,2,3,4,5)
15

可以看到,该函数可以返回传入参数的和。同时,注意到rest参数其实是一个数组,所以数组的方法它都可以使用,所以上面代码中的forEach是可以使用的。

需要注意的是,rest参数同参数的默认值一样,必须在参数的最后。而函数的length属性是不包括rest参数的。

(function(a) {}).length             // 1
(function(...a) {}).length // 0
(function(a, ...b) {}).length // 1

3.扩展运算符

扩展运算符,符号三个点(…),它可以看作是rest参数的你运算,可以讲一个数组转为用逗号分割的参数序列。

> let array = [1,2,34];
> console.log(...array)
1 2 34
> console.log(11,22,...array,4)
11 22 1 2 34 4

该运算符主要用于函数的调用。

function push(array, ...items) {
array.push(...items);
}
function add(x, y) {
return x + y;
}
var numbers = [4, 38];
add(...numbers) // 42

上面代码中,array.push(…items)和add(…numbers)这两行,都是函数的调用,它们的都使用了扩展运算符。该运算符将一个数组,变为参数序列。

由于扩展运算符可以展开数组,所以不再需要apply方法,将数组转为函数的参数了。

// ES5的写法
function f (x, y, z){}
var args = [0, 1, 2];
f.apply(null, args);
// ES6的写法
function f (x, y, z){}
var args = [0, 1, 2];
f(...args);

一个实际的例子:

> let a=[1,23,12,31,23,12,31,23,123,12,31,24,]
'use strict'
> Math.max(...a)
123
//ES5要实现同样的功能则需要
Math.max.apply(null,a);

扩展运算符可以简化很多种ES5的写法

// ES5
[1, 2].concat(more)
// ES6
[1, 2, ...more]

// ES5
list.push.apply(list, [3, 4])
// ES6
list.push(...[3, 4])

// ES5
list = [1,2,3,4]
var a = list[0], rest = list.slice(1)
a = 1,rest = [2,3,4]
// ES6 这里是用到了解构赋值
var [a, ...rest] = list
a = 1,rest = [2,3,4]
// ES5
new (Date.bind.apply(Date, [null, 2015, 1, 1]))
// ES6
new Date(...[2015, 1, 1]);

需要注意的是,如果将扩展运算符用于数组赋值,只能放在参数的最后,否则会报错。(这是肯定的嘛,否则程序怎么知道扩展运算符的长度是多少)。

扩展运算符可以将字符串转为数组(Array.from()也可以)。

> [...'hello']
[ 'h', 'e', 'l', 'l', 'o' ]

4.箭头函数

基本用法

使用‘箭头’来快速定义函数

let fn = f => f;

相当于

let fn = function(f){
return f;
}

当不需要参数的时候,或参数大于一个的时候,用括号代表参数部分:

var f = () => 5;
//等于
var f = function(){return 5};

var sum =(sum1,sum2) => num1 + num2;
//等于
var sum = function(sum1,sum2){
return sum1+sum2;
}

总之箭头后面就是函数要return的内容。
当箭头函数的代码块部分多余一条语句的时候,需要用大括号括起来,并且使用return返回。而由于大括号被解释为代码块,所以如果箭头函数需要返回对象的时候,必须在对象外面加上括号,否则会被解释为代码块。

var sum = (num1,num2) => {return num1+num2};
var sum1 = sumI => ({su1:'1',su2:'2'});

同样,箭头函数可以配合变量的解构赋值。

let person = ({you,i}) => you + 'love' + i;
> person({you:'y',i:'i'})
'ylovei'
//等于
var person = function(obj){
return obj.you +'love'+obj.i;
}

使用注意点
箭头函数有几个使用注意点。

(1)函数体内的this对象,绑定定义时所在的对象,而不是使用时所在的对象。

(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。

(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用Rest参数代替。

(4)不可以使用yield命令,因此箭头函数不能用作Generator函数。

上面四点中,第一点尤其值得注意。this对象的指向是可变的,但是在箭头函数中,它是固定的。下面的代码是一个例子,将this对象绑定定义时所在的对象。

版权

文章中所有代码皆来自或演变自:

阮一峰-ECMAScript 6 入门,
本文同样遵循署名-非商用许可证.

如果觉得此文章对你有帮助,可以请我喝咖啡O(∩_∩)O
抹桥 微信支付

微信支付

抹桥 支付宝

支付宝

抹桥 比特币

比特币