抹桥的博客
Language
Home
Archive
About
GitHub
Language
主题色
250
1200 words
6 minutes
ECMAScript 6 Learning Notes (Part 3) - Function Extensions

1. Function Parameter Default Values#

Previously, we often wrote code like this:

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

This method of setting default values for function parameters has a drawback: if the passed-in parameter’s boolean equivalent is false, such as an empty string or 0, it can lead to unexpected behavior.

Therefore, if we still want the above code to produce the correct result, we need to add another check for e to determine if it has been assigned a value.

This can be cumbersome, so ES6 introduced a new method, as follows:

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

Not only does this significantly shorten the code, but it also greatly improves readability. Anyone reading the code can immediately see which parameters have default values.

Furthermore, setting default values is very flexible:

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

In the code above, the second parameter passed in is an object, and we can set default values for its properties.

You can even set nested default values.

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

In the code above, when calling the fetch function, if the second parameter is omitted, it defaults to an empty object; if the second parameter is included, its method property defaults to GET.

Parameter default value settings also support destructuring assignment:

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

Parameters with default values must be placed at the end of the parameter list. This is because once a default value is set, the parameter can be omitted, and only if it’s at the end can the function determine which parameter was omitted.

If undefined or null is passed to a parameter with a default value, the former will trigger the default value, while the latter will not.

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

It’s important to note that if default values are set, the function’s length property can be inaccurate.

> (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

As you can see, when no default values are set, the function’s length equals the number of its parameters. However, after setting default values, its length equals the number of parameters without default values.

2. Rest Parameters#

Rest parameters are used to capture excess arguments passed to a function, thus avoiding the need for the arguments object.

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

As you can see, this function can return the sum of the passed-in arguments. Also, note that a rest parameter is essentially an array, so all array methods can be used on it, which is why forEach in the above code works.

It’s important to note that, similar to default parameters, rest parameters must be at the end of the parameter list. Also, the function’s length property does not include rest parameters.

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

3. Spread Operator#

The spread operator, denoted by three dots (...), can be thought of as the inverse of the rest parameter. It can convert an array into a comma-separated sequence of arguments.

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

This operator is primarily used in function calls.

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

In the code above, both array.push(...items) and add(...numbers) are function calls, and both use the spread operator. This operator transforms an array into a sequence of arguments.

Because the spread operator can expand arrays, the apply method is no longer needed to convert an array into function arguments.

// 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);

A practical example:

> 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);

The spread operator can simplify many ES5 patterns:

```javascript
// 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]);
```

It’s important to note that if the spread operator is used for array assignment, it must be placed at the end of the array literal; otherwise, it will throw an error. (This makes sense, as how else would the program know the length of the spread operator’s expansion?).

The spread operator can convert a string into an array (as can Array.from()).

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

4. Arrow Functions#

Basic Usage#

Use ‘arrows’ to quickly define functions:

let fn = (f) => f;

Equivalent to:

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

When no parameters are needed, or when there is more than one parameter, use parentheses for the parameter part:

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

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

In short, whatever follows the arrow is what the function will return. When the arrow function’s code block contains more than one statement, it needs to be enclosed in curly braces, and an explicit return statement must be used. Since curly braces are interpreted as a code block, if an arrow function needs to return an object, the object must be wrapped in parentheses; otherwise, it will be interpreted as a code block.

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

Similarly, arrow functions can be combined with destructuring assignment.

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

Points to Note for Usage Arrow functions have several important points to consider.

(1) The this object inside the function body is bound to the object where it is defined, not where it is used.

(2) They cannot be used as constructors; that is, you cannot use the new keyword with them, otherwise, an error will be thrown.

(3) The arguments object cannot be used; it does not exist within the function body. If you need similar functionality, you can use rest parameters instead.

(4) The yield keyword cannot be used, therefore arrow functions cannot be used as Generator functions.

Among the four points above, the first one is particularly noteworthy. The this object’s binding is usually mutable, but in arrow functions, it is fixed. The following code provides an example of this being bound to the object where it is defined.

Copyright#

All code in this article is sourced from or adapted from:

阮一峰-ECMAScript 6 入门, and this article also adheres to the Attribution-NonCommercial License.

ECMAScript 6 Learning Notes (Part 3) - Function Extensions
https://blog.kisnows.com/en-US/2015/09/09/learning-ecmascript6-three/
Author
Kisnows
Published at
2015-09-09