let
、const
關鍵字在 ES6
以前,JavaScript
中變量默認是全局性的,只存在函數級做用域,聲明函數曾經是創造做用域的惟一方法。這點和其餘編程語言存在差別,其餘語言大多數都存在塊級做用域。因此在 ES6
中,新提出的 let
和 const
關鍵字使這個缺陷獲得了修復。javascript
if (true) { let a = 'name'; } console.log(a); // ReferenceError: a is not defined
同時還引入的概念 const
,用來定義一個常量,一旦定義之後不能夠修改,若是是引用類型,那麼能夠修改其引用屬性,不能夠修改其引用。html
const MYNAME = 'liangyin'; MYNAME = 'doke'; // TypeError: Assignment to constant variable. const MYNAME = { first: 'liang' }; MYNAME.last = 'yin'; // {first: "liang", last: "yin"}
有如下幾點須要注意:前端
let
和 const
代替 var
const
以防止後期無心覆蓋const
定義的變量使用大寫形式箭頭函數是一種更簡單的函數聲明方式,能夠把它看做是一種語法糖,箭頭函數永遠是匿名的。java
let add = (a, b) => { return a + b; } // 當後面是表達式(expression)的時候,還能夠簡寫成 let add = (a, b) => a + b; // 等同於 let add = function(a, b) { return a + b; } // 在回調函數中應用 let number = [1, 2, 3]; let doubleNumber = number.map(number => number * 2); console.log(doubleNumber); // [2, 4, 6] 看起來很簡便吧
this
在箭頭函數中的使用在工做中常常會遇到 this
在一個對象方法中嵌套函數做用域的問題。express
var age = 2; var kitty = { age: 1, grow: function() { setTimeout(function() { console.log(++this.age); }, 100) } }; kitty.grow(); // 3
其實這是由於,在對象方法的嵌套函數中,this
會指向 global
對象,這被看作是 JavaScript
在設計上的一個重大缺陷,通常都會採用一些 hack
來解決它。編程
let kitty = { age: 1, grow: function() { const self = this; setTimeout(function() { console.log(++self.age); }, 100); } } // 或者 let kitty = { age: 1, grow: function() { setTimeout(function() { console.log(this.age); }.bind(this), 100) } }
如今有了箭頭函數,能夠很輕鬆地解決這個問題。數組
let kitty = { age: 1, grow: function() { setTimeout(() => { console.log(this.age); }, 100) } }
可是箭頭函數並非萬能的,任何事物都具備兩面性,語言的新特性經常被誤解、濫用,好比箭頭函數的使用就存在不少誤區。 你們能夠移步☞ES6箭頭函數使用注意點。app
ES6
出現之前,面對默認參數都會讓人感到很痛苦,不得不採用各類 hack
手段,好比說:values = values || []
。如今一切都變得輕鬆不少。編程語言
function desc(name = 'liangyin', age = 18) { return name + '已經' + age + '歲了' } desc(); // liangyin已經18歲了
Rest
參數當一個函數的最後一個參數有...
這樣的前綴,它就會變成一個參數的數組。模塊化
function test(...args) { console.log(args); } test(1, 2, 3); // [1,2,3] function test2(name, ...args) { console.log(args); } test2('liangyin', 2, 3); // [2,3]
它和 arguments
參數有以下區別:
Rest
參數只是沒有指定變量名稱的參數數組,而 arguments
是全部參數的集合。arguments
對象並非一個真正的數組,而 Rest
參數是一個真正的數組,可使用各類數組方法,好比 sort
,map
等。剛剛講到了 Rest
操做符來實現函數參數的數組,其實這個操做符的能力不只如此。它被稱爲展開操做符,容許一個表達式在某處展開,在存在多個參數(用於函數調用),多個元素(用於數組字面量)或者多個變量(用於解構賦值)的地方就會出現這種狀況。
以前在 JavaScript
中,想讓函數把一個數組依次做爲參數進行調用,通常會採起如下措施:
function test(x, y, z) {}; var args = [1, 2, 3]; test.apply(null, args);
有了 ES6
的展開運算符,能夠簡化這個過程:
function test(x, y, z) {}; let args = [1, 2, 3]; test(...args);
在以前的版本中,若是想建立含有某些元素的新數組,經常會用到 splice
、concat
、push
等方法:
var arr1 = [1, 2, 3]; var arr2 = [4, 5, 6]; var arr3 = arr1.concat(arr2); console.log(arr3); // [1,2,3,4,5,6]
使用展開運算符之後就簡便了不少:
let arr1 = [1, 2, 3]; let arr2 = [4, 5, 6]; let arr3 = [...arr1, ...arr2]; console.log(arr3); // [1,2,3,4,5,6]
ES7
)數組的展開運算符簡單易用,那麼對象有沒有這個特性?
let uzi = { name: 'uzi', age: 50 }; uzi = { ...uzi, sex: 'male' }; console.log(uzi); // {name: "uzi", age: 50, sex: "male"}
這是 ES7
的提案之一,它可讓你以更簡潔的形式將一個對象可枚舉屬性複製到另一個對象上去。
在 ES6
以前的時代,字符串拼接老是一件使人很很很不爽的一件事,可是在ES6
的時代,這個痛點終於被治癒了!!!
// 以前的作法 var name = 'uzi'; var a = 'My name is ' + uzi + '!'; // 多行字符串 var longStory = 'This is a long story,' + 'this is a long story,' + 'this is a long story.' // 有了 ES6 以後咱們能夠這麼作 let name = 'uzi'; let a = `My name is ${name} !`; let longStory = `This is a long story, this is a long story, this is a long story.`
解構語法能夠快速從數組或者對象中提取變量,能夠用一個表達式讀取整個結構。
let number = ['one', 'two', 'three']; let [one, two, three] = number; console.log(`${one},${two},${three}`); // one,two,three
let uzi = { name: 'uzi', age: 20 }; let { name, age } = uzi; console.log(`${name},${age}`); // uzi,20
解構賦值能夠看作一個語法糖,它受 Python
語言的啓發,提升效率之神器。
衆所周知,在 JavaScript
的世界裏是沒有傳統類的概念,它使用的是原型鏈的方式來完成繼承,可是聲明方式老是怪怪的(很大一部分人不遵照規則用小寫變量聲明一個類,這就致使類和普通方法難以區分)。
在 ES6
中提供了 class
這個語法糖,讓開發者模仿其餘語言類的聲明方式,看起來更加明確清晰。須要注意的是, class
並無帶來新的結構,只是原來原型鏈方式的一種語法糖。
class Animal { // 構造函數 constructor(name, age) { this.name = name; this.age = age; } shout() { return `My name is ${this.name}, age is ${this.age}`; } // 靜態方法 static foo() { return 'this is static method'; } } const cow = new Animal('uzi', 2); cow.shout(); // "My name is uzi, age is 2" Animal.foo(); // "this is static method" class Dog extends Animal { constructor(name, age = 2, color = 'black') { // 在構造函數中直接調用 super 方法 super(name, age); this.color = color; } shout() { // 非構造函數中不能直接使用 super 方法 // 可是能夠採用 super. + 方法名調用父類方法 return super.shout() + `, color is ${this.color}`; } } const uzisDog = new Dog('uzi'); uzisDog.shout(); // "My name is uzi, age is 2, color is black"
Object.assign
方法用來將源對象的全部可枚舉屬性複製到目標對象.
let target = { a: 1 }; // 後邊的屬性值,覆蓋前面的屬性值 Object.assign(target, { b: 2, c: 3 }, { a: 4 }); console.log(target); // {a: 4, b: 2, c: 3}
class add { constructor(obj) { Object.assign(this, obj); } } let p = new add({ x: 1, y: 2 }); console.log(p); // add {x: 1, y: 2}
Object.assign(add.prototype, { getX() { return this.x; }, setX(x) { this.x = x; } }); let p = new add(1, 2); console.log(p.getX()); // 1
function cloneObj(origin) { return Object.assign({}, origin); }
Set
、Map
和Array.from
Set
Set
裏面的成員的值都是惟一的,沒有重複的值,Set加入值時不會發生類型轉換,因此5和"5"是兩個不一樣的值。
// 數組去重 function dedupe(array) { return Array.from(new Set(array)); } console.log(dedupe([1, 2, 2, 3])); // 1, 2, 3
Map
Map
相似於對象,也是鍵值對的集合,可是"鍵"的範圍不限於字符串,各類類型的值(包括對象)均可以當作鍵.
let m = new Map(); let o = { p: 'Hello World' }; m.set(o, 'content'); m.get(o); // content m.has(o); // true m.delete(o); // true m.has(o); // false m.set(o, 'my content').set(true, 7).set('foo', 8); console.log(m); // Map(3) {{…} => "my content", true => 7, "foo" => 8} // Map/數組/對象 三者之間的相互轉換 console.log([...m]); // (3) [Array(2), Array(2), Array(2)]
Array.from
Map
Map
對象的鍵值對轉換成一個一維數組。
const map1 = new Map(); map1.set('k1', 1); map1.set('k2', 2); map1.set('k3', 3); console.log(Array.from(map1)) // [Array(2), Array(2), Array(2)]
Set
const set1 = new Set(); set1.add(1).add(2).add(3); console.log(Array.from(set1)); // [1, 2, 3]
能夠把ascii
的字符串拆解成一個數據,也能夠準確的將unicode
字符串拆解成數組。
console.log(Array.from('hello world')); console.log(Array.from('\u767d\u8272\u7684\u6d77')); // ["h", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d"] // ["白", "色", "的", "海"]
一個類數組對象必需要有length
,他們的元素屬性名必須是數值或者能夠轉換成數值的字符。
注意:屬性名錶明瞭數組的索引號,若是沒有這個索引號,轉出來的數組中對應的元素就爲空。
console.log(Array.from({ 0: '0', 1: '1', 3: '3', length:4 })); // ["0", "1", undefined, "3"]
若是對象不帶length
屬性,那麼轉出來就是空數組。
console.log(Array.from({ 0: 0, 1: 1 })); // []
對象的屬性名不能轉換成索引號時,轉出來也是空數組。
console.log(Array.from({ a: '1', b: '2', length: 2 })); // [undefined, undefined]
Array.from
能夠接受三個參數Array.from(arrayLike[, mapFn[, thisArg]])
arrayLike
:被轉換的的對象。
mapFn
:map函數。
thisArg
:map函數中this指向的對象。
JavaScript
模塊化是一個很古老的話題,它的發展從側面反映了前端項目愈來愈複雜、愈來愈工程化。在 ES6
以前,JavaScript
沒有對模塊作出任何定義,知道 ES6
的出現,模塊這個概念才真正有了語言特性的支持,如今來看看它是如何被定義的。
// hello.js 文件 // 定義一個命名爲 hello 的函數 function hello() { console.log('Hello ES6'); } // 使用 export 導出模塊 export {hello}; // main.js // 使用 import 加載這個模塊 import { hello } from './hello'; hello(); // Hello ES6
上面的代碼就完成了模塊的一個最簡單的例子,使用 import
和 export
關鍵字完成模塊的導入和導出。固然也能夠完成一個模塊的多個導出:
// hello.js export const PI = 3.14; export function hello() { console.log('Hello ES6'); } export let person = { name: 'uzi' }; // main.js // 使用對象解構賦值加載這3個變量 import { PI, hello, person } from './hello'; // 也能夠將這個模塊所有導出 import * as util from './hello'; console.log(util.PI); // 3.14
還可使用 default
關鍵字來實現模塊的默認導出:
// hello.js export default function() { console.log('Hello ES6'); } // main.js import hello from './hello'; hello(); // Hello ES6