ECMAScript6 新特征——“函数的扩大”

1 函数参数的默许值

ES6许可为函数的参数设置默许值,即直接写在参数定义的背面:

function log(x = "message.",y = "duration infomation.") {
    console.log(x, y);
}

log(); //message. duration infomation.
log("hello world.", "connecting."); //hello world. connecting.

参数变量是默许声明的,所以不能用let和const再次声明

function add(x = 0, y = 0) {
    let x; //报错
    const y; //报错
    console.log(x + y);
}
add();

与组织赋值默许值连系运用

function add({x = 0, y = 0}) {
    console.log(x + y);
}
add({}); //0
add({y: 1}); //1

//当add()时,则会报错
add(); //报错

//怎样才能在add()时不报错呢?
//这就须要用到两重默许值,即默许为函数传入一个对象
function add({x = 0, y = 0} = {}) {
    console.log(x + y);
}
add({}); //0
add({y: 1}); //1
add(); //0

以下:

function add({name = "your name here", age = "your age here"} = {}) {
    console.log(`${name}, ${age}`);
}
add(); //your name here, your age here
add({name: "Oliver"}); //Oliver, your age here
add({name: "Troy", age: 18}); //Troy, 18

函数的length属性

指定了默许值今后,函数的length属性,将返回没有指定默许值的参数个数。

function add(x,y = 0) {
    console.log(x + y);
}
console.log(add.length); //1 函数预期传入1个参数,因为有一个参数已有默许值了

作用域

假如参数默许值是一个变量,则该变量所处的作用域,与其他变量的作用域规则是一样的,即先是当前函数的作用域,然后才是全局作用域。

var x = 10;
function log(x, y = x) { //x已在内部天生,运用的将是内部的x
    console.log(y);
}
log(2); //2

var x = 10;
function log(y = x) { //x不存在,运用的将是外部的x
    console.log(y);
}
log(); //10

现实运用

省略参数抛出毛病:

function throwIfMissing() {
    throw new Error("Missing parameter.");
}
function foo(x = throwIfMissing()) {
    return x;
}
console.log(foo(10)); //10
console.log(foo()); //Uncaught Error: Missing parameter.

2 rest参数

rest参数(情势为“…变量名”),用于猎取函数的过剩参数,如许就不须要运用arguments对象了

function foo(...values) {
    let sum = 0;
    for(let val of values) sum += val;
    console.log(sum);
}
foo(1,2,3);

注重,rest参数以后不能再有其他参数(即只能是末了一个参数),不然会报错。

function foo(x, ...values) {
    let sum = 0;
    for(let val of values) sum += val;
    console.log(x, sum);
}
foo(1,2,3); //x是1,sum是2+3

function foo(x, ...values, y) {
    let sum = 0;
    for(let val of values) sum += val;
    console.log(x, sum);
}
foo(1,2,3); //Rest parameter must be last formal parameter

3 扩大运算符

扩大运算符(spread)是三个点(…)。它比方rest参数的逆运算,将一个数组转为用逗号分开的参数序列。

let a = [1,2,3,4,5,6,7];
console.log(...a); //1 2 3 4 5 6 7
a.push(...a);
console.log(a); //[1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7]

该运算符重要用于函数的挪用

let a = [1,2,3,4,5,6,7];
function add(...args) {
    let sum = 0;
    for (let val of args) console.log(sum += val);
    console.log(`done. final sum: ${sum}`);
}
add(...a); //顺次传入a数列中的值
//1
//3
//6
//10
//15
//21
//28
//done. final sum: 28

替换数组的apply要领

扩大运算符可以睁开数组,所以不再须要apply要领

//ES5
let a = [1,2,3,4,5,6,7];
console.log(Math.max.apply(null,a)); //7
//ES6
console.log(Math.max(...a)); //7

又比方push函数

let a = [];
let num = [1,2,3,4,5,6,7];
a.push(...num);
console.log(a.toString()); //1,2,3,4,5,6

扩大运算符的运用

兼并数组

let a = [];
let a1 = [1,2,3];
let a2 = [4,5];
let a3 = [6,7,8,9,10];
a = [...a1, ...a2, ...a3];
console.log(a.toString()); //1,2,3,4,5,6,7,8,9,10

与解构赋值连系

let [...rest] = [1,2,3,4,5,6];
console.log(rest); //[1,2,3,4,5,6]

函数的返回值

var dateFields = readDateFields(database);
var d = new Date(...dateFields);

字符串

console.log([...'hello']); //["h", "e", "l", "l", "o"]

扩大运算符可以辨认32位Unicode字符

可以准确返回字符串长度:

console.log([...'hello']); //["h", "e", "l", "l", "o"]
function len(...args) {
    for (let val of args) console.log([...val].length);
}
len("hello", "another one 哈哈"); //14

相似数组的对象

var nodeList = document.getElementsByTagName("p");
var array = [...nodeList];

含有Iterator接口对象

只需具有Iterator接口的对象,都可以运用扩大运算符

Map,Set,Generator等

4 name属性

函数的name属性,返回该函数的函数名。

假如将一个匿名函数赋值给一个变量,ES5的name属性,会返回空字符串,而ES6的name属性会返回现实的函数名。

var x = function() {};
console.log(x.name); //"" ES5返回空字符串,ES6返回x

将一个签字函数赋值给一个变量,则ES5和ES6的name属性都返回这个签字函数底本的名字。

var x = function y() {};
console.log(x.name); //"y"

Function组织函数返回的函数实例,name属性的值为“anonymous”。

console.log((new Function).name); //anonymous

bind返回的函数,name属性值会加上“bound ”前缀。

function foo() {};
foo.bind({}).name // "bound foo"

(function(){}).bind({}).name // "bound "

5 箭头函数

ES6许可运用“箭头”(=>)定义函数。

let add = (x,y) => x + y;
console.log(add(1,2)); //3

function add(x,y) {
    return x + y;
}
console.log(add(1,2)); //3

假如箭头函数的代码块部份多于一条语句,就要运用大括号将它们括起来,而且运用return语句返回。

let add = (x, y) => {
    console.log("done");
    return x + y;
};
console.log(add(1, 2)); //3

假如箭头函数直接返回一个对象,必需在对象表面加上括号。

let add = (x, y) => ({ result: x + y });
console.log(add(1, 2).result); //3

箭头函数可以与变量解构连系运用。

let add = ({ name, age }) => ({ result: `${name},${age}` });
console.log(add({ name: "Oliver", age: 18 }).result); //Oliver,18

箭头函数的一个用途是简化回调函数

var arr = [1, 2, 3, 4, 5];
arr.map(function(item, index, array) {
    console.log(item);
});

arr.map((item, index, array) => { console.log(item); });

//上面两种函数写法功用雷同,下面的显著较为简约

运用注重点

  • 函数体内的this对象,就是定义时地点的对象,而不是运用时地点的对象。

  • 不可以看成组织函数,也就是说,不可以运用new敕令,不然会抛出一个毛病。

  • 不可以运用arguments对象,该对象在函数体内不存在。假如要用,可以用Rest参数替代。

  • 不可以运用yield敕令,因而箭头函数不能用作Generator函数。

6 ES7函数绑定

ES7中函数绑定运算符(::)作用是替代call、apply、bind挪用。

7 尾挪用优化

尾挪用

尾挪用(Tail Call)就是指某个函数的末了一步是挪用另一个函数:

function g() {
    console.log("done.");
}

function j() {
    console.log("almost done.");
}

function log(x) {
    if (x > 0) {
        return g();
    }
    return j();
}
log(10); //done.
log(0); //almost done.

g()和j()的挪用都属于尾挪用,因为都是函数的末了一步

尾挪用优化

函数挪用会在内存构成一个“挪用纪录”,又称“挪用帧”(call frame),保存挪用位置和内部变量等信息。假如在函数A的内部挪用函数B,那末在A的挪用帧上方,还会构成一个B的挪用帧。比及B运转完毕,将效果返回到A,B的挪用帧才会消逝。假如函数B内部还挪用函数C,那就另有一个C的挪用帧,以此类推。一切的挪用帧,就构成一个“挪用栈”(call stack)。

尾挪用由因而函数的末了一步操纵,所以不须要保存外层函数的挪用帧,因为挪用位置、内部变量等信息都不会再用到了,只需直接用内层函数的挪用帧,庖代外层函数的挪用帧就可以了。

注重,只要不再用到外层函数的内部变量,内层函数的挪用帧才会庖代外层函数的挪用帧,不然就没法举行“尾挪用优化”。

function addOne(a) {
    var one = 1;

    function inner(b) {
        return b + one;
    }
    return inner(a);
}

尾递归

递归异常消耗内存,因为须要同时保存成千上百个挪用帧,很容易发作“栈溢出”毛病。但关于尾递归来讲,因为只存在一个挪用帧,所以永久不会发作“栈溢出”毛病。

所以确保末了只挪用本身就可以了,做法是将一切参数传入要挪用的函数中去:

// function log(n) {
//     if (n === 1) {
//         return 1
//     };
//     return n * log(n - 1);
// }
// console.log(log(5)); //120

function log(n, total) {
    if (n === 1) {
        return total
    };
    return log(n - 1, n * total);
}
console.log(log(5, 1)); //120

8 ES7函数参数的尾逗号

ES7提案许可函数的末了一个参数有尾逗号。

    原文作者:JS菌
    原文地址: https://segmentfault.com/a/1190000004909067
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞