ECMAScript
和JavaScript
ECMAScript
是JavaScript
的標(biāo)準(zhǔn)化規(guī)范泼各,實(shí)際上JavaScript
是ECMAScript
的擴(kuò)展語(yǔ)言恳啥,ECMAScript
提供最基本語(yǔ)法喷面,停留在語(yǔ)言層面星瘾;而JavaScript
在此基礎(chǔ)上做擴(kuò)展,瀏覽器端的JavaScript
等于ECMAScript
加Web
所提供的API
(DOM
和BOM
)乖酬;Node
環(huán)境中的JavaScript
等于ECMAScript
加Node
所提供的API
ECMAScript
的發(fā)展過程
ECMAScript 2015
可以叫做ES6
死相,主要有4個(gè)大類的提升
- 解決原有語(yǔ)法上的一些問題或不足(
let
、const
提供塊級(jí)作用域) - 對(duì)原有語(yǔ)法進(jìn)行增強(qiáng)咬像、更易用(解構(gòu)、展開運(yùn)算符生宛、模板字符串县昂、函數(shù)默認(rèn)值等等)
- 全新的對(duì)象、全新的方法陷舅、全新的功能 (
Promise
倒彰、Proxy
、Object.assign
) - 全新的數(shù)據(jù)類型和數(shù)據(jù)結(jié)構(gòu)(
Set
莱睁、Map
)
新特性
-
let
和const
解決塊沒有單獨(dú)作用域問題,
let
和const
定義的變量只能在當(dāng)前作用域使用if (true) { var foo = 'foo' } console.log(foo) if (true) { let foo = 'foo' } console.log(foo) // foo is not undefined // 循環(huán)綁定事件待讳,事件處理函數(shù)中獲取正確索引 var ele = [{}, {}, {}] for (var i = 0;i < ele.length; i++) { // ele[i].onclick = function() { // console.log(i) //} // 使用閉包創(chuàng)建函數(shù)作用域 擺脫全局作用域影響 elements[i].onclick = (function (i) { return function () { console.log(i) } })(i) } ele[2].onclick() // 3 ele[2].onclick() // 2 // 使用let塊級(jí)作用域 for (let i = 0;i < ele.length; i++) { ele[i].onclick = function() { console.log(i) } }
let
沒有變量提升console.log(foo) var foo = 'sdf' console.log(foo) let foo = 'sdf' // foo is not undefined
const
常量,只讀的let仰剿,聲明之后不能再修改(指不能修改指向的內(nèi)存地址创淡,可以修改其中的屬性成員)// 恒量只是要求內(nèi)層指向不允許被修改 const obj = {} // 對(duì)于數(shù)據(jù)成員的修改是沒有問題的 obj.name = 'zce' obj = {} // Assignment to constant variable.
-
數(shù)組的解構(gòu)
Destructruing
const arr = [100, 200, 300] const [foo, bar, baz] = arr // 100 200 300 const [foo, ...rest] = arr console.log(rest) // [ 200, 300 ]
-
對(duì)象的解構(gòu)
Destructuring
// 簡(jiǎn)單對(duì)象 const obj = { name: 'wang', age: 24 } const { name, age } = obj // wang 24 // 嵌套對(duì)象 const obj2 = { worker: { name: 'wang', sex: '男' }, address: 'zhognguo' } const { worker: { name }, address } // wang zhognguo // 默認(rèn)值 const obj3 = { name: 'wang', age: 24 } const { name, age, sec = '女' } = obj // wang 24 女
-
模板字符串字面量
Template literals
// 反引號(hào)包裹 const a = `hello world` // hello world // 允許換行 const b = `hello es2015, this is a \`string\`` // hello es2015, this is a `string` // 輸出模板 $('#contioner').append(` There are <b>${count}</b> items in your basket, <em>${onSale}</em> are on sale! `); // 可以使用 ${} 插入表達(dá)式 const fruits = 'apple' const c = `this is ${fruits}` // this is apple
-
模板字符串標(biāo)簽函數(shù)
Tagged Templates
// 模板字符串標(biāo)簽是一個(gè)特殊的函數(shù) 使用這個(gè)標(biāo)簽就是調(diào)用這個(gè)函數(shù) const str = console.log`hello world` // ["hello world", raw: Array(1)] // strings:字符串?dāng)?shù)組南吮,以${}分隔符分割得到的數(shù)組 // 其余的參數(shù)與表達(dá)式相關(guān) ${}的值 function Tag(strings, str琳彩,str2,...) const name = 'tom' const gender = false function myTagFunc (strings, name, gender) { const sex = gender ? 'man' : 'woman' return strings[0] + name + strings[1] + sex + strings[2] } const result = myTagFunc`hey, ${name} is a ${gender}.` // hey, tom is a woman.
-
字符串的擴(kuò)展用法
// includes 返回布爾值,表示是否找到參數(shù)字符串 // startsWith 返回布爾值部凑,表示參數(shù)字符串是否在源字符串開頭 // endsWith 返回布爾值露乏,表示參數(shù)字符串是否在源字符串尾部 const message = 'Error: foo is not defined.' console.log( message.startsWith('Error'), // true message.endsWith('.'), // true message.includes('foo') // true ) // 支持兩個(gè)參數(shù) 表示開始搜索位置 let s = 'Hello world!'; s.startsWith('world', 6) // true s.endsWith('Hello', 5) // true s.includes('Hello', 6) // false
-
參數(shù)默認(rèn)值Default parameters
// ES6之前 函數(shù)默認(rèn)值使用短路運(yùn)算符 function log (x, y) { // 如果y傳入false 則下面賦值無(wú)效 // 需要先判斷y是否被賦值 if (typeof y === 'undefined') y = 'world' y = y || 'world' console.log(y) } // 通常情況 函數(shù)默認(rèn)值應(yīng)該在函數(shù)的尾參數(shù) function foo(a, enable = true) // 非尾部設(shè)置 這個(gè)參數(shù)需要穿undefined function foo(a = 'a', enable = true) { console.log('foo invoked - enable: ') console.log(enable) console.log(a) } // 只有參數(shù)值為undefied時(shí)才會(huì)使用默認(rèn)值 foo(undefined, false) // 函數(shù)length屬性 返回沒有指定默認(rèn)值的參數(shù)個(gè)數(shù) foo.length // 0
-
剩余參數(shù)
Rest parameters
// ...rest剩余參數(shù) 用于獲取函數(shù)的多余參數(shù) 代替arguments // rest參數(shù)之后不能再有其他參數(shù) function foo (first, ...args) { console.log(args) } foo(1,2 ,3, 4) // [2, 3, 4] // 使用rest替代arguments例子 function sortNumbers () { return Array.prototype.slice.call(arguments).sort() } const sortNumbers = (...numbers) => numbers.sort() sortNumbers(1, 2, 4, 6, 2, 3) // [1, 2, 2, 3, 4, 6]
-
展開數(shù)組
Spread
// 擴(kuò)展運(yùn)算符... 好比reset參數(shù)的逆運(yùn)算 console.log(...[1,2,3]) // 1 2 3 // 1.復(fù)制數(shù)組 const a1 = [1, 2] const a3 = [3] // const a2 = a1 // 復(fù)制指向底層數(shù)據(jù)結(jié)構(gòu)的指針 并不是克隆全新的數(shù)組 const a2 = [...a1] // const [...a2] = a1 console.log(a2) // 2.合并數(shù)組 // ES5的合并 // let a4 = a1.concat(a3) // [1, 2, 3] // ES6的合并 let a4 = [...a1, ...a3] console.log(a4) console.log(a2 === a1, a4[0] === a1[0]) // 上述兩種都是淺拷貝 // 3.與解構(gòu)賦值結(jié)合 const list = [1, 2, 3, 4, 5] let [a, ...rest] = list console.log(a, rest) // 1 [ 2, 3, 4, 5 ] const [first, ...last] = [] console.log(first, last) // undefined [] // 4.轉(zhuǎn)換字符串為真正數(shù)組 console.log([...'hello']) // ...運(yùn)算符能識(shí)別四個(gè)字節(jié)的Unicode字符 js會(huì)將Unicode字符轉(zhuǎn)換為2個(gè)字符 console.log('x\uD83D\uDE80y'.length) // 4 console.log([...'x\uD83D\uDE80y'].length) // 3 // 5.// 任何實(shí)現(xiàn)了Iterator接口的對(duì)象 都可以使用擴(kuò)展運(yùn)算符 Number.prototype[Symbol.iterator] = function* () { let i = 0 const num = this.valueOf() while (i < num) { yield i++ } } console.log([...5]) // [ 0, 1, 2, 3, 4 ] // Map、Set結(jié)構(gòu)和Generator函數(shù) let map = new Map([ [1, 'one'], [2, 'two'], [3, 'three'], ]) let keys = [...map.keys()] console.log(keys) // [ 1, 2, 3 ] let set = new Set([1, 2, 3, 4, 5, 2, 21, 1]) console.log([...set]) // [ 1, 2, 3, 4, 5, 21 ] const go = function* () { yield 1 yield 2 yield 3 } console.log([...go()]) // [ 1, 2, 3 ]
-
const arr = [1, 2, 3, 4, 5, 6, 7] // arr.filter(function (item) { // return item % 2 // }) // 常用場(chǎng)景涂邀,回調(diào)函數(shù) console.log(arr.filter((i) => i % 2)) // [ 1, 3, 5, 7 ] // 1.函數(shù)體內(nèi)this對(duì)象瘟仿,定義時(shí)的對(duì)象,而不是使用時(shí)的對(duì)象 // 2.arguments對(duì)象在函數(shù)體內(nèi)不存在比勉,可以使用rest參數(shù)替代 // 3.不能使用yield命令劳较,箭頭函數(shù)不能用作Generator對(duì)象 // 箭頭函數(shù)與 this // 箭頭函數(shù)不會(huì)改變 this 指向 const person = { name: 'tom', // sayHi: function () { // console.log(`hi, my name is ${this.name}`) // } // 定義對(duì)象的方法,且該方法內(nèi)部包括this 不應(yīng)該使用箭頭函數(shù) sayHi: () => { console.log(`hi, my name is ${this.name}`) }, sayHiAsync: function () { // const _this = this // setTimeout(function () { // console.log(_this.name) // }, 1000) console.log(this) setTimeout(() => { // console.log(this.name) console.log(this) }, 1000) } } person.sayHi() // hi, my name is undefined person.sayHiAsync()
-
對(duì)象字面量增強(qiáng)
Enhanced object literals
// 對(duì)象字面量 const bar = '345' const obj = { foo: 123, // bar: bar // 屬性名與變量名相同敷搪,可以省略 : bar bar, // method1: function () { // console.log('method111') // } // 方法可以省略 : function method1 () { console.log('method111') // 這種方法就是普通的函數(shù)兴想,同樣影響 this 指向。 console.log(this) }, // 屬性名表達(dá)式 [bar]: 123, ['a' + 'bc']: 123 }
-
對(duì)象擴(kuò)展方法
Object.assign
赡勘、Object.is
// Object.assign() 用于對(duì)象的合并 將源對(duì)象可枚舉屬性 復(fù)制到目標(biāo)對(duì)象 const target = { a: 1, b: 1 } const source1 = { b: 2, c: 2 } const source2 = { c: 3 } Object.assign(target, source1, source2) target // {a:1, b:2, c:3} // 也可用于對(duì)象深拷貝 const obj = { name: 'global obj' } const funcObj = Object.assign({}, obj) funcObj.name = 'func obj' console.log(funcObj) //{ name: 'func obj' } console.log(obj) // { name: 'global obj' } // Object.is用于比較兩個(gè)值嚴(yán)格相等 與===一致 Object.is('foo', 'foo') // true Object.is({}, {}) // false // 不同之處 +0 === -0 //true NaN === NaN // false Object.is(+0, -0) // false Object.is(NaN, NaN) // true
-
Proxy
代理對(duì)象// 為對(duì)象設(shè)置訪問代理器 可以理解為在目標(biāo)對(duì)象之前架設(shè)一層“攔截” 外界訪問該對(duì)象 都必須通過這層攔截 // 輕松監(jiān)視對(duì)象的屬性讀寫 const person = { name: 'zce', age: 20, } const personProxy = new Proxy(person, { // 監(jiān)視屬性讀取 get(target, property) { // 先判斷屬性是否存在 return property in target ? target[property] : 'default' // console.log(target, property) // return 100 }, // 監(jiān)視屬性設(shè)置 set(target, property, value) { if (property === 'age') { if (!Number.isInteger(value)) { throw new TypeError(`${value} is not an int`) } } target[property] = value // console.log(target, property, value) }, }) personProxy.age = 100 personProxy.gender = true console.log(personProxy.name) // zce console.log(personProxy.xxx) // default
-
Proxy
vsObject.defineProperty()
// Object.defineProperty()只能監(jiān)視對(duì)象中的屬性讀寫 Proxy能監(jiān)視更多對(duì)象操作 const personProxy = new Proxy(person, { deleteProperty (target, property) { console.log('delete', property) delete target[property] } }) delete personProxy.age console.log(person) // { name: 'zce' } // Proxy更好的支持?jǐn)?shù)組對(duì)象的監(jiān)視 const list = [] const listProxy = new Proxy(list, { set(target, property, value) { console.log('set', property, value) target[property] = value return true // 表示設(shè)置成功 }, }) listProxy.push(100) // set 0 100 set length 1 // Proxy 非侵入方式監(jiān)管對(duì)象讀寫 已定義好的對(duì)象 不需要對(duì)對(duì)象本身做操作 就可監(jiān)視對(duì)象的操作 Object.defineProperty(person,'name',{ get(){ console.log("name 被訪問..."); return person._name; }, set(newValue){ console.log("name 被設(shè)置 ..."); person._name = newValue; } }) person.name = 'wang'// name 被設(shè)置 ... console.log(person.name) // name 被訪問 ... wang const personProxy = new Proxy(person, { get(target, property) { return target[property]; }, set(target, property, value) { return (target[property] = value); } });
-
Reflect
// Reflect封裝一些列對(duì)對(duì)象的底層操作 // 現(xiàn)階段嫂便,某些方法同時(shí)在Object和Reflect對(duì)象上部署,未來的新方法將只部署在Reflect對(duì)象上 // 價(jià)值 提供一套用于操作對(duì)象的API const obj = { name: 'zce', age: 18 } console.log('name' in obj) console.log(delete obj['age']) console.log(Object.keys(obj)) // 讓Objkect操作都變成函數(shù)行為 console.log(Reflect.has(obj, 'name')) console.log(Reflect.deleteProperty(obj, 'age')) console.log(Reflect.ownKeys(obj))闸与、
-
Class
類// class 關(guān)鍵詞 // 生成實(shí)例對(duì)象的傳統(tǒng)方法是通過構(gòu)造函數(shù) function Person(name) { this.name = name } Person.prototype.say = function () { console.log(`hi, my name is ${this.name}`) } class Person { // constructor()方法是類的默認(rèn)方法 通過new命令生成對(duì)象實(shí)例時(shí)毙替,自動(dòng)調(diào)用該方法 constructor(name) { this.name = name } // 靜態(tài)方法 不會(huì)被實(shí)例繼承 直接通過類調(diào)用 static create(name) { return new Person(name) } say() { console.log(`hi, my name is ${this.name}`) } } const p = new Person('tom') p.say() const xiaoming = Person.create('xiaoming') xiaoming.say() // 類的繼承 class Student extends Person { constructor (name, number) { super(name) // 父類構(gòu)造函數(shù) this.number = number } hello () { super.say() // 調(diào)用父類成員 console.log(`my school number is ${this.number}`) } } const s = new Student('jack', '100') s.hello() // hi, my name is jack my school number is 100
-
Set數(shù)據(jù)結(jié)構(gòu)
// 類似于數(shù)組岸售,但是成員的值都是唯一的 const s = new Set() [2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x)); for (let i of s) { console.log(i) } // 作用去除數(shù)組的重復(fù)成員 const array = [1,2,3,4,2,1,23,4] [...new Set(array)] // [1,2,3,4,23]
-
Map數(shù)據(jù)結(jié)構(gòu)
// Object對(duì)象 鍵值對(duì)集合 只能通過字符串作為鍵 // Map數(shù)據(jù)結(jié)構(gòu) “鍵”的范圍不限于字符串 const m = new Map() const tom = { name: 'tom' } m.set(tom, 90) console.log(m) // Map(1) { { name: 'tom' } => 90 } console.log(m.get(tom)) // 90 // map操作 // 1.轉(zhuǎn)為數(shù)組 const arr = [...m] console.log(arr) // [ [ { name: 'tom' }, 90 ], [ { name: 'tom' }, 80 ] ] // 2.數(shù)組轉(zhuǎn)為map console.log(new Map([arr])) // Map(1) { [ { name: 'tom' }, 90 ] => [ { name: 'tom' }, 80 ] } // 3.Map轉(zhuǎn)為對(duì)象 Map的鍵被轉(zhuǎn)為字符串 function strMapToObj(strMap) { let obj = Object.create(null) for (let [k, v] of strMap) { obj[k] = v } return obj } console.log(strMapToObj(m)) // [Object: null prototype] { '[object Object]': 80 } 同名屬性被覆蓋 // 4.對(duì)象轉(zhuǎn)Map let obj = { a: 1, b: 2 } let map = new Map(Object.entries(obj)) console.log(map) // Map(2) { 'a' => 1, 'b' => 2 }
-
Symbol
// ES6 引入 原始數(shù)據(jù)類型Symbol,表示獨(dú)一無(wú)二的值 // 數(shù)據(jù)類型:undefined厂画、null凸丸、布爾值(Boolean)、字符串(String)袱院、數(shù)值(Number)屎慢、對(duì)象(Object)、Symbol // 對(duì)象屬性名:一種原有字符串 另一種新增的 Symbol 類型(保證不會(huì)與其他屬性名產(chǎn)生沖突) const s = Symbol() console.log(s) // Symbol() console.log(typeof s) // symbol // 兩個(gè) Symbol 永遠(yuǎn)不會(huì)相等 console.log(Symbol() === Symbol()) // false // 使用 Symbol 為對(duì)象添加用不重復(fù)的鍵 const obj = {} obj[Symbol()] = '123' obj[Symbol()] = '456' console.log(obj) // { Symbol(): "123", Symbol(): "456" } // 內(nèi)置 Symbol 常量 console.log(Symbol.iterator) console.log(Symbol.hasInstance) const obj = { [Symbol.toStringTag]: 'XObject' } console.log(obj.toString()) // Symbol 屬性名獲取 const obj = { [Symbol()]: 'symbol value', [Symbol()]: 'symbol vaasdlue', foo: 'normal value', } console.log(Object.getOwnPropertySymbols(obj)) // [ Symbol(), Symbol() ]
-
Iterator
(遍歷器)和for...of
循環(huán)// Iterator是一種接口 為所有不同的數(shù)據(jù)結(jié)構(gòu)提供統(tǒng)一訪問機(jī)制 只要部署Iterator接口 就可以完成遍歷操作 // 只要實(shí)現(xiàn)Iterator接口 就可以被for...of消費(fèi) // 對(duì)象實(shí)現(xiàn)可迭代接口 const obj = { store: ['foo','bar','baz'], [Symbol.iterator]: function() { let index = 0 const self = this return { next: function () { const result = { value: self.store[index], down: index >= self.store.length } index++ return result } } } } for (let item of obj) { console.log(item) } // foo bar baz // for...of循環(huán)內(nèi)部調(diào)用的是數(shù)據(jù)結(jié)構(gòu)的Symbol.iterator方法 // for...of循環(huán)可以使用的范圍包括數(shù)組忽洛、Set 和 Map 結(jié)構(gòu)腻惠、某些類似數(shù)組的對(duì)象(比如arguments對(duì)象、DOM NodeList 對(duì)象)欲虚、后文的 Generator 對(duì)象集灌,以及字符串 // 與其他遍歷語(yǔ)法比較 const arr = [1, 2, 3, 4] for (var i = 0; o < array.length; i++) { console.log(array[i]) } // 寫法較麻煩 使用forEach array.forEach((value, index) => { console.log(value, index) }) // 此時(shí) 無(wú)法跳出forEach循環(huán) break和return命令都不能奏效 for (let value of array) { console.log(value) } // 優(yōu)點(diǎn):它可以與break、continue和return配合使用 // 提供了遍歷所有數(shù)據(jù)結(jié)構(gòu)的統(tǒng)一操作接口
-
ES Modules
待補(bǔ)充复哆。欣喧。。