ES6函数的改变不算太大,都是一些其余语言早就有的功能,而Javascript一直比较欠缺的,好比函数参数默认值,任意参数的表示法,最大的变化应该是支持箭头函数(其余语言称之为LAMBDA表达式),一种对匿名函数的一种简写方式,如下来探讨一下函数在ES6中的一些改变:
数组
1. 默认参数(default parameters) 2. 任意参数(rest parameters ...) 3. spread 操做符(...) 4. new.target 元属性 5. 箭头函数( => ) 6. 其余一些改动(miscellaneous)
ES6以前一直是经过其余方法来模拟默认参数的,例如逻辑或||符号,ES6版本真正意义上支持这种便利的写法。app
// ES5模拟默认参数 function person(name, age) { name = name || "James"; age = age || "18"; console.log(name + " " + age); } // 通常状况下这种写法是没问题的,当逻辑或前面的值为falsy值,整个表达式返回后面的值 // 例如: person("Louis"); // ok person(); // ok person(undefined, 20); // ok person("baby", 0); // "baby 18" error, 0为falsy值
上面能够看出这种写法是有必定问题的,各类JS库给出了另外一种写法函数
function person(name, age) { if (typeof name === "undefined") { name = name || "James"; } if (typeof age === "undefined") { age = age || "18"; } console.log(name + " " + age); } person(undefined, 0); // ok "James 0"
ES6写法性能
function person(name = "James", age = 18) { console.log(name + " " + age); } // 1各类写法 默认参数出如今中间 function getRequest(url, timeout = 2000, callback) { // do something } gerRequest("/foo", undefined, function() { }); // 2默认参数表达式 let value = 5; function getValue() { return value++; } function add(first, second = getValue()) { return first + second; } add(3); // 8 add(3); // 9 add(1, 1); // 2 // 3后面参数引用前面参数 function add(first, second = first) { return first + second; } add(2); // 4 add(3, 4); // 7
默认参数TDZ(暂时死区)状况:优化
// 上面的第三种写法,若写成第一个参数引用第二个参数 function add(first = second, second) { return first + second; } add(1, 1); // ok 2 add(undefined, 4); // THROW AN ERROR 第二个参数未声明就引用就会抛出错误 // 就至关于 let first = second; // error let second = 4;
ES6任意参数用 ...
表示,任意参数和arguments之间的差异
ES5使用arguments参数来实现对象属性拷贝:ui
function pick(object) { var result = Object.create(null); // 建立一个对象 // 从第二个参数开始 for (var i = 1, len = arguments.length; i < len; i++) { result[arguments[i]] = object[arguments[i]]; } return result; } // arguments将object也计入,因此除开第一个参数要减1 var book = { title: "understanding ES6", author: "Nicholas C.Zakes", year: 2016 }; var o = pick(book, "author", "year"); o.author; // "Nicholas C.Zakes" o.year; // 2016
上面的pick函数看上去不够直观,由于除第一个参数外不知道要添加几个参数,使用新语法this
function pick(object, ...keys) { var result = Object.create(null); // 建立一个对象 for (var i = 0, len = keys.length; i < len; i++) { result[keys[i]] = object[keys[i]]; } return result; } // keys将object不计入在其内 var book = { title: "understanding ES6", author: "Nicholas C.Zakes", year: 2016 }; var o = pick(book, "author", "year"); o.author; // "Nicholas C.Zakes" o.year; // 2016
使用rest parameters注意事项:
1.要将任意参数放到函数的最后,不能放在中间位置
2.不能用于对象字面量setter中url
function pick(object, ...keys, last) { //... } // 语法错误 let object = { set name(...value) { // do something } }; // 语法错误
spread操做符和rest parameters同样,都使用 ...
表示,spread操做符容许咱们将数组中的参数一个一个传入函数中
例如:prototype
// Math.max()函数, 通常能够加入任意个参数 Math.max(12, 13, 14, 15); // 15 // 以数组的形式 var arr = [1, 2, 3, 4]; Math.max.apply(null, arr); // 4 // 使用 "..." Math.max(...arr); // 4 // 还能够加入其它的一些参数 Math.max(...arr, 5, 10); // 10
将一个数组去重:调试
var arr = [1, 2, 2, 4, 4]; // 使用Set将重复的去掉,而后将set对象转变为数组 var mySet = new Set(arr); // mySet {1, 2, 4} // 方法1,使用Array.from转变为数组 // var arr = Array.from(mySet); // [1, 2, 4] // 方法2,使用spread操做符 var arr = [...arr]; // [1, 2, 4] // 方法3, 传统forEach var arr2 = []; mySet.forEach(v => arr2.push(v));
函数内部有两个方法 [[call]] 和 [[construct]] (箭头函数没有这个方法),当使用new 操做符时, 函数内部调用 [[construct]], 建立一个新实例,this指向这个实例; 不使用new 操做符时, 函数内部调用 [[call]]。
判断一个函数是否使用new操做符,ES5的方法:
function Person(name) { if (this instanceof Person) { this.name = name; } else { throw new Error("You must use new operator"); } } var p = new Person("James"); // ok var p = Person("James"); // error // 可是能够经过其余方式绕过这种错误 var notPerson = Person.call(p, "Nicholas"); // works
ES6 经过new.target 来判断是否使用new,元属性 是指一个提供目标相关额外信息(好比new)的非对象属性。
function Person(name) { if (typeof new.target !== "undefined") { this.name = name; } else { throw new Errow("You must use new operator"); } } var p = new Person("James"); // ok var notPerson = Person.call(p, "Louis"); // error
箭头函数有如下几个方面的特色:
1.箭头函数语法
// 语法很简单 let sum = (n1, n2) => n1 + n2; // 至关于 let sum = function(n1, n2) { return n1 + n2; }; let getTempItem = id => ({ id: id, name: "Temp" }); // 至关于 let getTempItem = function(id) { return { id: id, name: "Temp" }; };
2.没有this绑定
let PageHandler = { id: "123456", init: function() { document.addEventListener("click", function(event) { this.doSomething(event.type); // error }, false); }, doSomething: function(type) { console.log("Handling " + type + " for " + this.id); } }; // init函数中的this.doSomething,this指向的是函数内部document对象, // 而不是PageHandler对象
使用箭头函数改写:
let PageHandler = { id: "123456", init: function() { document.addEventListener("click", event => this.doSomething(evnet.type) }, false); }, doSomething: function(type) { console.log("Handling " + type + " for " + this.id); } }; // 此处箭头函数this指向包含它的函数,即init,init为PageHandler的方法, // this指向PageHandler对象实例
3.不能使用new
var MyType = () => {}; var obj = new MyType(); // Error
4.没有arguments对象
箭头函数没有arguments对象,可是能够使用包含函数中的arguments对象
function createArrowFunctionReturningFirstArg() { // arguments 为 createArrowFunctionReturningFirstArg中的对象 return () => arguments[0]; } var arrowFunction = createArrowFunctionReturningFirstArg(10); arrFunction(); // 10
其余的一些变化:
总结
整体来讲,这些改动都是为编写程序提供了极大的便利,不用再使用workaround来解决语法存在的问题,总体来说,更加符合语言的书写习惯。