Nick Justice是GitHub開發者計畫的一員。早在ES6語言標準發布之前,他就借助像Babel這樣的轉譯器以及最新版本的瀏覽器在自己的專案中使用ES6特性。他認為,ES6的新特性將大幅改變JavaScript的編寫方式。
ES6(ECMAScript 6)是即將到來的新版本JavaScript語言的標準,代號harmony(和諧之意,顯然沒有跟上我國的步伐,我們已經進入中國夢版本了)。上一次標準的製訂還是2009年推出的ES5。目前ES6的標準化工作正在進行中,預計14年12月會放出正式敲定的版本。但大部分標準已經就緒,且各瀏覽器對ES6的支援也正在實現中。
技術雖然發展太快,但是我們不停下學習的步伐,就不會被新技術淘汰,下面我們一起來學習es6的新特徵吧。
箭頭操作符
如果你會C#或Java,你一定知道lambda表達式,ES6新增的箭頭操作符=>便有異曲同工之妙。它簡化了函數的書寫。操作符左邊為輸入的參數,而右邊則是進行的操作以及傳回的值Inputs=>outputs。
我們知道在JS中回調是經常的事,而一般回調又以匿名函數的形式出現,每次都需要寫一個function,甚是繁瑣。當引入箭頭操作符後可以方便地寫回調了。請看下面的範例:
var array = [1,2,3]; // 传统写法写法 array.forEach(function(v) { console.log(v); }); // ES6写法 array.forEach(v => console.log(v));
類的支援
ES6中加入了對類別的支持,引入了class關鍵字(其實class在JavaScript中一直是保留字,目的就是考慮到可能在以後的新版本中會用到,現在終於派上用場了) 。 JS本身就是物件導向 的,ES6提供的類別其實只是JS原型模式的包裝。現在提供原生的class支援後,物件的創建,繼承更加直觀了,並且父類方法的調用,實例化,靜態方 法和構造函數等概念都更加形象化。
下面程式碼展示了類別在ES6中的使用:
// 类的定义 class Animal { // ES6中新型构造器 constructor(name) { this.name = name; } // 实例方法 sayName() { console.log('My name is ' + this.name); } } // 类的继承 class Programmer extends Animal { constructor(name) { // 直接调用父类构造器进行初始化 super(name); } program() { console.log("I'm coding..."); } } // 测试我们的类 var animal = new Animal('dummy'), wayou = new Programmer('wayou'); animal.sayName(); // 输出 'My name is dummy' wayou.sayName(); // 输出 'My name is wayou' wayou.program(); // 输出 'I'm coding...'
增強的物件字面量
物件字面量被增強了,寫法更加簡潔與靈活,同時在定義物件的時候能夠做的事情更多了。具體表現在:
1.可以在物件字面量裡面定義原型
2.定義方法可以不用function關鍵字
3.直接呼叫父類別方法
這樣一來,物件字面量與前面提到的類別概念更加吻合,在編寫物件導向的JavaScript時更加輕鬆方便了。
// 通过对象字面量创建对象 var human = { breathe() { console.log('breathing...'); } }; var worker = { __proto__: human, // 设置此对象的原型为human, 相当于继承human company: 'freelancer', work() { console.log('working...'); } }; human.breathe(); // 输出 'breathing...' // 调用继承来的breathe方法 worker.breathe(); // 输出 'breathing...'
字串範本
字串範本相對簡單易懂些。 ES6中允許使用反引號 ` 來建立字串,此種方法建立的字串裡面可以包含由美元符號加花括號包裹的變數 ${vraible}。如果你使用過像C#等後端強類型語言的話,對此功能應該不會陌生。
// 产生一个随机数 var num = Math.random(); // 将这个数字输出到console console.log(`your num is ${num}`);
解構
自動解析數組或物件中的值。例如若一個函數要傳回多個值,常規的做法是傳回一個對象,將每個值做為這個對象的屬性回傳。但在ES6中,利用解構這個特性,可以直接傳回一個數組,然後數組中的值會自動被解析到對應接收該值的變數中。
function getVal() { return[1,2]; } var [x,y] = getVal(), // 函数返回值的解构 console.log('x:' + x + ', y:' + y); // 输出:x:1, y:2 [name,,age] = ['wayou','male','secrect']; // 数组解构 console.log('name:' + name + ', age:' + age); //输出:name:wayou, age:secrect
參數預設值,不定參數,拓展參數
預設參數值
現在可以在定義函數的時候指定參數的預設值了,而不用像以前那樣透過邏輯或運算子來達到目的了。
function sayHello(name) { // 传统的指定默认参数的方式 var name = name || 'dude'; console.log('Hello ' + name); } sayHello(); // 输出:Hello dude sayHello('Wayou'); // 输出:Hello Wayou // 运用ES6的默认参数 function sayHello2(name = 'dude') { console.log(`Hello${name}`); } sayHello2(); // 输出:Hello dude sayHello2('Wayou'); // 输出:Hello Wayou
不定參數
不定參數是在函數中使用命名參數同時接收不定數量的未命名參數。這只是一種語法糖,在以前的JavaScript程式碼中我們可以透過arguments變數來達到這個目的。不定參數的格式是三個句點後面跟著代表所有不定參數的變數名稱。
例如下面這個範例中,…x代表了所有傳入add函數的參數。
// 将所有参数相加的函数 function add(...x) { return x.reduce((m,n) => m+n); } // 传递任意个数的参数 console.log(add(1,2,3)); // 输出:6 console.log(add(1,2,3,4,5)); // 输出:15
拓展參數
拓展參數則是另一種形式的語法糖,它允許傳遞數組或類別數組直接做為函數的參數而不用通過apply。
var people = ['Wayou','John','Sherlock']; // sayHello函数本来接收三个单独的参数人一,人二和人三 function sayHello(people1, people2, people3) { console.log(`Hello${people1}, ${people2}, ${people3}`); } // 但是我们将一个数组以拓展参数的形式传递,它能很好地映射到每个单独的参数 sayHello(...people); // 输出:Hello Wayou,John,Sherlock // 而在以前,如果需要传递数组当参数,我们需要使用函数的apply方法 sayHello.apply(null, people); // 输出:Hello Wayou,John,Sherlock
let與const 關鍵字
可以把let看成var,只是它定義的變數被限定在特定範圍內才能使用,而離開這個範圍則無效了。 const則很直觀,用來定義常數,也就是無法被改變值的變數。
for (let i=0; i<2; i++) { console.log(i); // 输出: 0,1 } console.log(i); // 输出:undefined,严格模式下会报错
for of 值遍历
我们都知道for in循环用于遍历数组,类数组或对象,ES6中新引入的for of循环功能相似,不同的是每次循环它提供的不是序号而是值。
var someArray = ["a","b","c"]; for (v of someArray) { console.log(v); // 输出 a,b,c }
iterator, generator
1.iterator: 它是这么一个对象,拥有一个next方法,这个方法返回一个对象{done,value},这个对象包含两个属性,一个布尔类型的done和包含任意值的value
2.iterable: 这是这么一个对象,拥有一个obj[@@iterator]方法,这个方法返回一个iterator
3.generator: 它是一种特殊的iterator。反的next方法可以接收一个参数并且返回值取决与它的构造函数(generator function)。generator同时拥有一个throw方法
4.generator函数: 即generator的构造函数。此函数内可以使用yield关键字。在yield出现的地方可以通过generator的next或throw方法向外界传递值。generator 函数是通过function*来声明的
5.yield关键字:它可以暂停函数的执行,随后可以再进进入函数继续执行
模块
在ES6标准中,JavaScript原生支持module了。这种将JS代码分割成不同功能的小块进行模块化的概念是在一些三方规范中流行起来的,比如CommonJS和AMD模式。
将不同功能的代码分别写在不同文件中,各模块只需导出公共接口部分,然后通过模块的导入的方式可以在其他地方使用。
// point.js module "point" { export class Point { constructor(x,y) { public x=x; public y=y; } } } // myapp.js // 声明引用的模块 module point from "/point.js"; // 这里可以看出,尽管声明了引用的模块,还是可以通过指定需要的部分进行导入 import Point from "point"; var origin = new Point(0,0); console.log(origin); Map,Set 和 WeakMap,WeakSet
这些是新加的集合类型,提供了更加方便的获取属性值的方法,不用像以前一样用hasOwnProperty来检查某个属性是属于原型链上的呢还是当前对象的。同时,在进行属性值添加与获取时有专门的get,set方法。
// Sets var s = new Set(); s.add("hello").add("goodbye"); s.size === 2; s.has("hello") === true; // Maps var m = new Map(); m.set("hello", 42); m.set(s, 34); m.get(s) == 34; 有时候我们会把对象作为一个对象的键用来存放属性值,普通集合类型比如简单对象会阻止垃圾回收器对这些作为属性键存在的对象的回收,有造成内存泄漏的危险。而WeakMap,WeakSet则更加安全些,这些作为属性键的对象如果没有别的变量在引用它们,则会被回收释放掉,具体还看下面的例子: // Weak Maps var wm = new WeakMap(); wm.set(s, {extra: 42}); wm.size === undefined // 对象释放了 // Weak Sets var ws = new WeakSet(); ws.add({data: 42}); // 因为添加到ws的这个临时对象没有其他变量引用它,所以ws不会保存它的值,也就是说这次添加其实没有意思 Proxies Proxy可以监听对象身上发生了什么事情,并在这些事情发生后执行一些相应的操作。一下子让我们对一个对象有了很强的追踪能力,同时在数据绑定方面也很有用处。 // 定义被侦听的目标对象 var engineer = {name: 'Joe Sixpack', salary: 50}; // 定义处理程序 var interceptor = {set: function(receiver, property, value) { console.log(property, 'is changed to', value); receiver[property] = value; } }; // 创建代理以进行侦听 engineer = Proxy(engineer, interceptor); //做一些改动来触发代理 engineer.salary = 60; // 控制台输出:salary is changed to 60
上面代码我已加了注释,这里进一步解释。对于处理程序,是在被侦听的对象身上发生了相应事件之后,处理程序里面的方法就会被调用,上面例子中我们设置了set的处理函数,表明,如果我们侦听的对象的属性被更改,也就是被set了,那这个处理程序就会被调用,同时通过参数能够得知是哪个属性被更改,更改为了什么值。
Symbols
我们知道对象其实是键值对的集合,而键通常来说是字符串。而现在除了字符串外,我们还可以用symbol这种值来做为对象的键。Symbol是一种 基本类型,像数字,字符串还有布尔一样,它不是一个对象。Symbol 通过调用symbol函数产生,它接收一个可选的名字参数,该函数返回的symbol是唯一的。之后就可以用这个返回值做为对象的键了。Symbol还可以用来创建私有属性,外部无法直接访问由symbol做为键的属性值。
(function() { // 创建 symbol var key = Symbol("key"); function MyClass(privateData) { this[key] = privateData; } MyClass.prototype = { doStuff: function() { ...this[key]... } }; })(); var c = new MyClass("hello"); c["key"] === undefined //无法访问该属性,因为是私有的 Math,Number,String,Object 的新API 对Math,Number,String还有Object等添加了许多新的API。 // Number // 不同的两个Number之间的最小的差 Number.EPSILON // 判断是否是整数 Number.isInteger(Infinity) // false // 判断是否为非数字 Number.isNaN("NaN") // false // Math Math.acosh(3) // 1.762747174039086 Math.hypot(3,4) // 5 Math.imul(Math.pow(2,32)-1, Math.pow(2,32)-2) // 2 // String "abcde".contains("cd") // true "abc".repeat(3) // "abcabcabc" // Array // 将一个类数组对象或可迭代对象转换成真实的数组 Array.from(document.querySelectorAll('*')) // 将它的任意类型的多个参数放在一个数组里并返回 Array.of(1,2,3) // 将一个数组中指定区间的所有元素的值, 都替换成或者说填充成为某个固定的值 [0,0,0].fill(7,1) // [0,7,7] // 用来查找数组中某指定元素的索引, 如果找不到指定的元素, 则返回 -1 [1,2,3].findIndex(x => x == 2) // 1 // 返回一个 Array Iterator 对象,该对象包含数组中每一个索引的键值对 ["a","b","c"].entries() // iterator [0, "a"], [1,"b"], [2,"c"] // 返回一个数组索引的迭代器 ["a","b","c"].keys() // iterator 0, 1, 2 // 返回一个新的 Array Iterator 对象,该对象包含数组每个索引的值 ["a","b","c"].values() // iterator "a", "b", "c" // Object Object.assign(Point, {origin: new Point(0,0)}) Promises Promises是处理异步操作的一种模式,之前在很多三方库中有实现,比如jQuery的deferred 对象。当你发起一个异步请求,并绑定了.when(), .done()等事件处理程序时,其实就是在应用promise模式。 // 创建 promise var promise = new Promise(function(resolve,reject) { // 进行一些异步或耗时操作 if(/*如果成功 */) { resolve("Stuff worked!"); } else { reject(Error("It broke")); } }); // 绑定处理程序 promise.then(function(result) { // promise成功的话会执行这里 console.log(result); // "Stuff worked!" }, function(err) { // promise失败会执行这里 console.log(err); // Error: "It broke" });
有关ES6的新特性就给大家介绍这么多,希望对大家有所帮助!