默认参数值让函数参数在未传递值或未定义时用默认值初始化。
function join(arr=[], sep=','){
return arr.join(sep);
}
join();//""
join([1,2,3]); //"1,2,3"
join(["Javascript", "is", "awesome"], " "); //"Javascript is awesome"
我们也可以指定一个函数作为默认值。
import rp from 'request-promise';
function jsonParser(body, response) {
if (/^application\/json.*/i.test(response.headers['content-type'])){
return JSON.parse(body);
}
return body;
}
function fetch(url, transform=jsonParser) {
return rp({
url: url,
transform: jsonParser
});
}
另一种具有默认参数值的技术是允许函数声明所需的参数。在设计需要参数验证的API时,这确实很有用。
function required(param){
throw new Error(`${param} is required`);
}
const Storage = {
setItem: function setItem(key = required('key'), value=required('value')){
//implentation code goes here
},
getItem: function getItem(key = required('key')){
}
}
Storage.setItem();//Uncaught Error: key is required
Storage.setItem('key1');//Uncaught Error: value is required
Storage.setItem('key1', 'value1'); //OK
在ES5中,我们可以使用Array#concat或Array#slice来制作数组的副本。
var arr = [1, 2, 3, 4, 5];
var arr2 = arr.slice(0); //1, 2, 3, 4, 5
var arr3 = [].concat(arr); //1, 2, 3, 4, 5
在ES6中,使用扩展运算符复制数组甚至更容易。
const arr = [1, 2, 3, 5, 6];
const arr2 = [...arr]; //1, 2, 3, 5, 6
const b = [...arr.slice(0, 3), 4, ...arr.slice(3)];//1, 2, 3, 4, 5, 6
在ES5中,我们可以借用一个实用函数,如jQuery#extend,_.assign来制作一个对象的副本:
var o = {
name: 'John',
age: 30,
title: 'Software Engineer',
}
var o2 = _.assign({}, o);
var o3 = _.assign({}, o, {age: 25});
在ES6中,我们可以使用内置函数object.assign:
const o = {
name: 'John',
age: 30,
title: 'Software Engineer',
}
const o2 = Object.assign({}, o);
const o3 = Object.assign({}, o, {age: 25});
另一种方法是使用扩展(…)运算符:
const o2 = {
...o
}
const o3 = {
...o,
age: 25
}
注意:ES6不支持对象的扩展运算符。希望,这将包括在ES7。如果你用的是像巴贝尔这样的转译器,你就被保护了。
一些函数如Math.max,Math.min,Date等需要参数列表。
Math.max(1, 100, 90, 20);
new Date(2016, 7, 13);
如果我们有一个包含在数组中的参数值列表呢?解决方法是使用function.prototype.apply(thisArg,[])
var numbers = [1, 100, 90, 20];
Math.max.apply(null, numbers); // 100
在ES6中,使用扩展运算符:
var numbers = [1, 100, 90, 20];
Math.max(...numbers);
var parts = [2016, 7, 13];
var d = new Date(...parts);
arguments是一个类似数组的对象,可在函数调用中使用。它表示调用函数时传入的参数列表。有一些问题:
function doSomething(arguments) {
console.log(arguments);
}
doSomething(); //undefined
doSomething(1); //1
function doSomething2() {
var arguments = 1;
console.log(arguments);
}
doSomething2();// 1
doSomething2(2, 3, 4); // 1
在ES6中,我们完全可以忘记参数。使用rest(…)运算符,我们可以收集传递函数调用的所有参数:
function doSomething(...args) {
console.log(args);
}
doSomething(1, 2, 3, 4); //[1, 2, 3, 4]
使用rest运算符,传递给doSomething的所有参数都被收集到args中。不仅如此,args是一个数组,因此我们不需要像参数那样额外地转换为数组。
在这一部分中,我们将在一个复杂的案例中使用上述技术。让我们实现fetchAPI。为了简单起见,我们将API构建在request-promise模块。
function fetch(url, options){
}
第一步是参数检查:
//ES5
import rp from 'request-promise';
function fetch(url, options){
var requestURL = url || '';
var opts = options || {};
...
}
//ES6
import rp from 'request-promise';
function fetch(url='', options={}){
...
}
我们还需要检查options对象的一些属性:
function jsonParser(body, response) {
if (/^application\/json.*/i.test(response.headers['content-type'])){
return JSON.parse(body);
}
return body;
}
//ES5
import rp from 'request-promise';
function fetch(url, options){
var requestURL = url || '';
var opts = options || {};
var method = options.method || 'get';
var headers = opts.headers || {'content-type': 'application/json'};
var transform = jsonParser;
...
}
//ES6
import rp from 'request-promise';
function fetch(url='', {method='get',
headers={'content-type': 'application/json'},
transform=jsonParser}){
}
在API的ES6版本中,我们使用析构来提取一些属性(method,headers和transform)并设置一些默认值。如果我们不传递options对象,这将不起作用,因为我们无法将模式与未定义的:
fetch();//TypeError: Cannot match against 'undefined' or 'null'
这可以通过默认值来修复:
//ES6
import rp from 'request-promise';
function fetch(url='', {method='get',
headers={'content-type': 'application/json'},
transform=jsonParser} = {}){
return rp({
url: url,
method: method,
headers: headers,
transform: transform
});
}
因为客户端代码可以传递除方法,标题,和转换时,我们需要复制所有剩余的属性:
//ES5
import rp from 'request-promise';
function fetch(url, options){
var requestURL = url || '';
var opts = options || {};
var method = options.method || 'get';
var headers = opts.headers || {'content-type': 'application/json'};
var transform = jsonParser;
//copy all properties and then overwrite some
opts = _.assign({}, opts, {method: method, headers: headers, transform: transform})
return rp(opts);
}
在ES6中,我们需要通过使用rest运算符来收集剩余的属性:
function fetch(url='', {method='get',
headers={'content-type': 'application/json'},
transform=jsonParser,
...otherOptions} = {}){
}
。。。并使用扩展运算符将这些属性传递给目标函数:
function fetch(url='', {method='get',
headers={'content-type': 'application/json'},
transform=jsonParser,
...otherOptions} = {}){
return rp({
url: url,
method: method,
headers: headers,
transform: transform,
...otherOptions
});
}
最后,使用对象文字速记法,我们可以这样写:
function fetch(url='', {method='get',
headers={'content-type': 'application/json'},
transform=jsonParser,
...otherOptions} = {}){
return rp({
url,
method,
headers,
transform,
...otherOptions
});
}