simple's Studio.

ES6中的默默认值和解构

2017/11/03

默认值和解构数组
你可以将默认函数参数和解构结合到一起, 创建非常强大的函数!

function createGrid([width = 5, height = 5]) {
  return `Generates a ${width} x ${height} grid`;
}

createGrid([]); // Generates a 5 x 5 grid
createGrid([2]); // Generates a 2 x 5 grid
createGrid([2, 3]); // Generates a 2 x 3 grid
createGrid([undefined, 3]); // Generates a 5 x 3 grid

Returns:
Generates a 5 x 5 grid
Generates a 2 x 5 grid
Generates a 2 x 3 grid
Generates a 5 x 3 grid

createGrid() 函数预期传入的是数组。它通过解构将数组中的第一项设为 width,第二项设为 height。如果数组为空,或者只有一项,那么就会使用默认参数,并将缺失的参数设为默认值 5。

但是存在一个问题,下面的代码将不可行:

createGrid(); // throws an error
Uncaught TypeError: Cannot read property 'Symbol(Symbol.iterator)' of undefined

出现错误,因为 createGrid() 预期传入的是数组,然后对其进行解构。因为函数被调用时没有传入数组,所以出现问题。但是,我们可以使用默认的函数参数!

function createGrid([width = 5, height = 5] = []) {
  return `Generating a grid of ${width} by ${height}`;
}

看到函数参数中的新 = [] 了吗?如果 createGrid() 在被调用时没有任何参数,它将使用这个默认的空数组。因为数组是空的,因此没有任何内容可以解构为 width 和 height,因此将应用它们的默认值!通过添加 = [] 为整个参数设定一个默认值,下面的代码将可行:

createGrid(); // Generates a 5 x 5 grid
Returns: Generates a 5 x 5 grid

看看下面的代码:

function houseDescriptor([houseColor = 'green', shutterColors = ['red']]) {
  return `I have a ${houseColor} house with ${shutterColors.join(' and ')} shutters`;
}

下面的哪些选项可以正常运行,不会出现错误?

1.houseDescriptor('red', ['white', 'gray', 'pink']);

2.houseDescriptor(['green', ['white', 'gray', 'pink']]);

3.houseDescriptor(['blue', 'purple']);

4.houseDescriptor(['green']);//答案为2和4

#####默认值和解构对象
就像使用数组默认值解构数组一样,函数可以让对象成为一个默认参数,并使用对象解构:

function createSundae({scoops = 1, toppings = ['Hot Fudge']}) {
  const scoopText = scoops === 1 ? 'scoop' : 'scoops';
  return `Your sundae has ${scoops} ${scoopText} with ${toppings.join(' and ')} toppings.`;
}

createSundae({}); // Your sundae has 1 scoop with Hot Fudge toppings.
createSundae({scoops: 2}); // Your sundae has 2 scoops with Hot Fudge toppings.
createSundae({scoops: 2, toppings: ['Sprinkles']}); // Your sundae has 2 scoops with Sprinkles toppings.
createSundae({toppings: ['Cookie Dough']}); // Your sundae has 1 scoop with Cookie Dough toppings.

Returns:
Your sundae has 1 scoop with Hot Fudge toppings.
Your sundae has 2 scoops with Hot Fudge toppings.
Your sundae has 2 scoops with Sprinkles toppings.
Your sundae has 1 scoop with Cookie Dough toppings.

就像上面的数组示例,如果尝试调用函数时不传入参数,将不可行:

createSundae(); // throws an error
Uncaught TypeError: Cannot match against 'undefined' or 'null'.

我们可以通过向函数提供默认对象来防止出现此问题:

function createSundae({scoops = 1, toppings = ['Hot Fudge']} = {}) {
  const scoopText = scoops === 1 ? 'scoop' : 'scoops';
  return `Your sundae has ${scoops} ${scoopText} with ${toppings.join(' and ')} toppings.`;
}

通过添加空对象作为默认参数,以防未提供参数,现在调用函数时没有任何参数将可行。

createSundae(); // Your sundae has 1 scoop with Hot Fudge toppings.
Returns: Your sundae has 1 scoop with Hot Fudge toppings.

习题 2/2

看看下面的代码:

function houseDescriptor({houseColor = 'green', shutterColors = ['red']} = {}) {
  return `I have a ${houseColor} house with ${shutterColors.join(' and ')} shutters`;
}

下面的哪些选项可以正常运行,不会出现错误?

1.houseDescriptor({houseColor: 'red', shutterColors: ['white', 'gray', 'pink']});

2.houseDescriptor({houseColor: 'red'});

3.houseDescriptor();

4.houseDescriptor({shutterColors: ['orange', 'blue']});

5.houseDescriptor({});
//所有函数都能运行

数组默认值与对象默认值
默认函数参数只是个简单的添加内容,但是却带来很多便利!与数组默认值相比,对象默认值具备的一个优势是能够处理跳过的选项。看看下面的代码:

function createSundae({scoops = 1, toppings = ['Hot Fudge']} = {}) { … }

在 createSundae() 函数使用对象默认值进行解构时,如果你想使用 scoops 的默认值,但是更改 toppings,那么只需使用 toppings 传入一个对象:

createSundae({toppings: ['Hot Fudge', 'Sprinkles', 'Caramel']});

将上述示例与使用数组默认值进行解构的同一函数相对比。

function createSundae([scoops = 1, toppings = ['Hot Fudge']] = []) { … }

对于这个函数,如果想使用 scoops 的默认数量,但是更改 toppings,则必须以这种奇怪的方式调用你的函数:

createSundae([undefined, toppings: ['Hot Fudge', 'Sprinkles', 'Caramel']]);

因为数组是基于位置的,我们需要传入 undefined 以跳过第一个参数(并使用默认值)来到达第二个参数。

除非你有很充足的理由来使用数组默认值进行数组解构,否则建议使用对象默认值进行对象解构!

CATALOG