9月抽空從新回顧了下ES6全部知識點,整個回顧過程既驚喜又感慨,感慨開發這麼久好像真的沒有好好的靜下心去讀一本好的書,大多狀況下只是在使用的時候用到了,不熟悉或者感興趣再去蜻蜓點水一通,感慨之餘也發現了一些自身的的問題,知識體系仍是不夠豐富、紮實,一句話:有空多讀書總沒錯,好了不閒扯了,下面咱們步入正題
現在前端知識突飛猛進,越是晚入門小夥伴,不少基礎層面的東西,接觸的真的是少之又少,各類前端框架層粗不窮Vue
、React
、Ng
這三大帶有里程碑意義的框架Api
我想看的這麼文字的盆友應該都有接觸,基礎的Api
使用應該是沒有什麼難度,可是在遇到問題,解決問題、以及在原有組件以及自我封裝組件,搭建框架過程總會遇到一些莫名其妙的問題,解決這個問題,看源碼
是大衆都知道的一些方法,但我的認爲這是一種進階的方法,新手入門建議能夠先了解我們JavaScript的發展史
能夠比較輕鬆的認識咱們整個技術體系的發展和將來方向,避免一些認知錯誤
互聯網早期javascript
「主機-網站-瀏覽器」
構成的Web系統,這標誌BS架構
的網站應用軟件的開端,也是前端工程的開端。這個時候前端只是簡單的Html靜態文本
簡單到基本動畫都沒有javascript
的誕生:1995年,NetScape(網景)公司的工程師Brendan Eich設計了javascript腳本語言,並集成到了navigator2.0版本中。隨後微軟也意識到了javascript的潛力,並模仿開發VBScript和JScript應用到了IE中,這直接開啓了NetScape和微軟的瀏覽器競爭
。因爲微軟的IE集成在windows操做系統上的優點,NetScape的navigator很快在瀏覽器市場上落於下風。因而他們把javascript提交到了ECMA
,推進制訂了ECMAScript標準
,成功實現了javascript的標準國際化。雖然第一次瀏覽器戰爭最後IE大勝Navigator,可是NetScape的javascript主導了W3C的官方標準。互聯網發展期前端
javascript推進
,前端頁面開始走向動態化,那時流行的跑馬燈、懸浮廣告
基本是各大門戶網站的標配,頁面基本都是經過PHP、JSP、ASP
動態渲染出來,這也直接致使後端代碼的邏輯臃腫,服務端爲了更好的管理代碼,應運而生MVC模式
reload
操做,無論交互仍是性能,都是不值當的 "這個問題直到谷歌在04年應用Ajax技術開發的Gmail和谷歌地圖的發佈,才獲得瞭解決。" 這背後的祕密就是Ajax技術中實現的異步HTTP請求
,這讓頁面無需刷新就能夠發起HTTP請求,用戶也不用專門等待請求的響應,而是能夠繼續網頁的瀏覽或操做。Ajax開啓了web2.0的時代
Dojo、Mooltools、YUIExtJS、jQuery
等前端兼容框架,其中jQuery應用最爲普遍。這些框架中不知道你們用過幾個Web Forms 2.0
、Web Applications 1.0
等規章最後整合成HTML五、各大瀏覽器都在爲適配瀏覽器不斷改善本身的瀏覽器事件循環的異步I/O框架-Node.js
。Node.js使得前端開發人員能夠利用javascript開發服務器端程序。很快,大量的Node.js使用者就建構了一個用NPM包管理工具管理的Node.js生態系統。node.js也能開發跨平臺的桌面應用
Node 衍生出的
NPM
包管理工具爲整個前端社區提供了一個規範良好的平臺
互聯網進擊java
jQuery Mobile、Sencha Touch、Framework7
如魚得水;Hybrid技術指的是利用Web開發技術,調用Native相關的API,實現移動與Web兩者的有機結合,既能利用Web開發週期短的優點,又能爲用戶提供Native的體驗。ECMAScript 6.0
發佈,該版本增長了不少新的語法,極大的拓展了javascript的開發潛力;一些陳舊的瀏覽器能夠經過Babel進行降級轉義適配,ES6將JavaScript推向了另外一個歷史轉折點React、Vue、Anjular
三大框架利用js集合自身優點,徹底實現了目前的先後端分離的開發模式;開發體系發展到:NPM和Yarn爲表明的包管理工具;ES6及Babel和TypeScript構成的腳本體系;HTML5;CSS3和相應的處理技術;React、Vue、Anjular爲表明的框架;Webpack爲表明的打包工具;Node.js爲基礎的Express和KOA後端框架;Hybrid技術。權重自上到下node
通常走到草案階段基本能夠在正式標準中看到,Tc39可查看各提案es6
Tips:
這也是在babel中配置presets
的來由(可能咱們使用了一些仍然在草案甚至徵求意見階段的API)的時候需babel墊片web
// 基本格式 { "presets":[] "plugins":[] }
不一樣環境支持不一樣的轉換方法正則表達式
通常咱們使用的腳手架默認配置好,可是咱們須要配置的什麼意思,以及爲何要配置編程
改寫require
命令,爲每一個require引入的資源進行Babel轉義windows
Babel僅會轉換新的語法,可是已有的Api中的Iterator、Generator、Set、Map、Proxy、Reflect、Symbol、Promise
是須要用這個墊片處理後端
暴露出Babel的Api,進行特殊操做
基礎篇咱們主要從es6中添加的一些命令,以及對已有數據類型拓展的彙總
特性以下
var
的塊級做用域// 下面這塊很好的體現了`塊級做用域` var a = []; for (var i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); // 10 var a = []; for (let i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); // 6
特殊說明下暫時性死區的概念
,就是:在塊中,let 聲明變量以前都是不能使用的
const 和 let 特性基本一致,區別於,使用const定義的是顯式的常量
,一經定義,不可更改
es5以前是有全局做用域、函數做用域
,es6推出的塊級做用域但凡一個{}
就是一個做用域;
外層塊級做用域能在內層使用,內層定義在外層訪問不到
Tips:解構賦值
對應的還有拓展操做符
,解構不成功則爲undefined;一看就懂,一用代碼就簡潔
ES6 容許按照必定模式,從數組和對象中提取值,對變量進行賦值(Iterator類型),這被稱爲解構(Destructuring)
let [foo, [[bar], baz]] = [1, [[2], 3]]; foo // 1 bar // 2 baz // 3 let [ , , third] = ["foo", "bar", "baz"]; third // "baz" let [x, , y] = [1, 2, 3]; x // 1 y // 3 let [head, ...tail] = [1, 2, 3, 4]; head // 1 tail // [2, 3, 4] let [x, y, ...z] = ['a']; x // "a" y // undefined z // []
let { bar, foo } = { foo: 'aaa', bar: 'bbb' }; foo // "aaa" bar // "bbb" let { baz } = { foo: 'aaa', bar: 'bbb' }; baz // undefined
let obj = { p: [ 'Hello', { y: 'World' } ] }; let { p: [x, { y }] } = obj; x // "Hello" y // "World"
// 設置默認值 function move({x = 0, y = 0} = {}) { return [x, y]; } move({x: 3, y: 8}); // [3, 8] move({x: 3}); // [3, 0] move({}); // [0, 0] move(); // [0, 0]
注:
還有字符串解構(轉換成數組)、字符/布爾解構(轉換成對象),解構遵循的宗旨是模式、數據格式一致,便可解構,解構失敗undefined;進行賦值的過程,無論是數組仍是對象解構均可以設置默認值
;圓括號()
只能在賦值語句的非模式部分便可
用途優點
函數中直接返回多個值
let [a,b,c] = fn()
字符串中改動仍是蠻多的有添加Unicode表示
、JSON.stringify()適配非UTF-8編碼
,下面介紹平常開發實用改變
for of
遍歷器(es6新增)僅對擁有Iterator接口的適配
`` 反引號 節省咱們字符串拼接的痛點
let str1 = 'There are <b>' + basket.count + '</b> ' + 'items in your basket, '; let str2 = `There arebasket.count ${variable}</b>items in your basket, `;
上面字符串拼接自上到下的升級,同時也可使用${}
動態注入變量
<%...%>
中放置JavaScript代碼,以下
let template = ` <ul> <% for(let i=0; i < data.supplies.length; i++) { %> <li><%= data.supplies[i] %></li> <% } %> </ul> `;
能夠利用字符串匹配<%...%>
封裝template轉換函數
0xFFFF
的字符codePointAt()
charAt() // UTF-8 codePointAt() // UTF-16
includes(), startsWith(), endsWith()
includes():返回布爾值,表示是否找到了參數字符串。 startsWith():返回布爾值,表示參數字符串是否在原字符串的頭部。 endsWith():返回布爾值,表示參數字符串是否在原字符串的尾部。
0b(0B)二進制;0o(0O)八進制
右結合即右邊先運算
)**
、**=
操做符 進行指數運算
//指數拓展符 let a = 2; a ** 2 **4 // 2 * (2 * 4) a **= 3 // a = 2 * 2 * 2
...
將一個數組轉成用逗號分隔的參數排列
console.log(1,2 ...[3,4]) // 1,2,3,4
Array.form()
// 將類數組轉換成數組Array.of()
// 用於將一組值,轉換爲數組-1
返回bool值
flat()、flatMap()
// 扯平數組
[1, 2, , [4, 5]].flat() //[1, 2, 4, 5] 默認拉平一層,參數num、Infinity自定義拉平層數目 // flatMap() 至關於先進行Map再進行flat操做 // 至關於 [[2, 4], [3, 6], [4, 8]].flat() [2, 3, 4].flatMap((x) => [x, x * 2]) // [2, 4, 3, 6, 4, 8]
ES6中明確將空位裝換成undefined;數組實例方法、map、擴展操做符存在差別
總之避免空位的出現是很必要的
對象中的屬性、方法只要key、value名字一致,便可簡寫成一個以下
// 屬性 let a = 'a'; let b = 'b'; let obj = { a, b } // 等同於 let a = 'a'; let b = 'b'; let obj = { a:a, b:b } // 方法 let obj = { a, b, c(){ console.log('這是一個對象方法') } } // 等同於 let obj = { a, b, c:function(){ console.log('這是一個對象方法') } }
let propKey = 'foo'; let obj = { [propKey]: true, ['a' + 'bc']: 123 }; // 須要注意的是若是屬性名是一個對象默認會裝換成[object Object]
// 合併對象 let ab = { ...a, ...b }; // 等同於 let ab = Object.assign({}, a, b); // 同數組拓展操做符後可跟表達式 如: const obj = { ...(x > 1 ? {a: 1} : {}), b: 2, };
每一個屬性都有一個描述對象,用來控制屬性的行爲Object.getOwnPropertyDescriptor(obj,'key')
可獲取對應屬性的描述行爲,
描述中enumerable
標識是否可遍歷
總之:操做中引入繼承的屬性會讓問題複雜化,大多數時候,咱們只關心對象自身的屬性。因此,儘可能不要用for...in循環,而用Object.keys()代替
Object.getOwnPropertyNames()
Object.getOwnPropertySymbols()
Reflect.ownKeys()
Object.is()
==
或者===
,前者會強制類型轉換,後者NAN不等於自身,並+0等於-0
,此方法就解決了上述問題Object.assign()
第一個參數就是目標對象
,只會處理可枚舉的數據類型,並Symbol值屬性也會被拷貝Object.getOwnPropertyDescriptors()
原型操做方法替代__proto__
對象鍵值對獲取
Object.fromEntries()
// Object.fromEntries()方法是Object.entries()的逆操做,用於將一個鍵值對數組轉爲對象遍歷規則以下:
指向當前對象的原型對象。
const proto = { x: 'hello', foo() { console.log(this.x); }, }; const obj = { x: 'world', foo() { super.foo(); } } Object.setPrototypeOf(obj, proto); obj.foo() // "world"
上面代碼中,super.foo指向原型對象proto的foo方法,可是綁定的this卻仍是當前對象obj,所以輸出的就是world。
進階篇,咱們主要對新增的Symbol、ArrayBuffer
以及Set和Map
數據結構介紹、Promise 到 async
的演變和差別,異步遍歷的思想,以及Class、Module的使用
;
ES6引入的新的數據類型,保證了數據的獨一無二的特性,能夠用來標識對象的額惟一key值
// 新建類型 let a = Symbol() // 添加描述(用於標識Symbol值) let a = Symbol('描述文件')
特性:
方法:
Set 數據結構。它相似於數組,可是成員的值都是惟一的,沒有重複的值。
特性:
去重
屬性
方法
和 Set
的區別
不進入垃圾回收機制
Map 的數據類型相似對象,可是對象的key值能夠是任意類型的Map:值-值
,不一樣於傳統Object:字符串-值
屬性
屬性
方法
和Map的結構相似
和Map
的差別
用途
在 DOM 對象上保存相關數據
數據緩存
const cache = new WeakMap();function countOwnKeys(obj) { if (cache.has(obj)) { console.log('Cached'); return cache.get(obj); } else { console.log('Computed'); const count = Object.keys(obj).length; cache.set(obj, count); return count; }}
操做二進制數據的一個接口。早就存在,屬於獨立的規格(2011 年 2 月發佈),ES6 將它們歸入了 ECMAScript 規格,而且增長了新的方法。它們都是以數組的語法處理二進制數據,因此統稱爲
二進制數組
注意:
二進制數組並非真正的數組,而是相似數組的對象。
屬性類型
數據存放規則
規格定義區別
存儲二進制數據的一段內存,不能直接進行讀寫,須要經過視圖進行操做
new ArrayBuffer(32) //分配一個32位字節的內存
- byteLength 返回分配區域的字節長度
- slice() 操做ArrayBuffer 對象 生成一個新的內存地址 - isView() bool值返回是不是TypedArray視圖實例(是不是一個視圖)
經過構造方法生成 視圖
注:
存在溢出問題
TypedArray(buffer, byteOffset=0, length?)
- buffer // 返回 ArrayBuffer 對象 - byteLength // 佔據內存長度(成員長度) - byteOffset // 視圖從ArrayBuffer中開始位置 - length // 字節長度
- set() // 複製數組 - subarray() // 返回新的視圖 - slice() // 返回新的視圖 - of() // 用於將參數轉爲一個TypedArray實例 - from() // from接受一個可遍歷的數據結構(好比數組)做爲參數,返回一個基於這個結構的TypedArray實例。 可有兩個參數,第二個參數是fun
- buffer // 返回 ArrayBuffer 對象 - byteLength // 佔據內存長度(成員長度) - byteOffset // 視圖從ArrayBuffer中開始位置
Canvas
讀取二進制像素數據File
new FileReader() 讀取 ArrayBuffer對象Promise 異步編程的解決方案,社區的提案, async 結局了Promise的回調地獄
有 padding(進行中)、fulfilled(成功)、rejected(失敗)三種狀態,狀態已經改變就並不會變更
方法
any()
allSettled()
注意:
Async
async 只是對 promise 的寫法上的一種語法糖
async
: 函數 返回一個Promise對象,return 返回Promise的結果
await: 後面默認是一個Promise對象
try catch(): 捕獲錯誤
解決異步模塊加載的問題
將傳統
實例對象經過構造方法生成的過程放到class的語法糖中, 以下例
// 傳統方法 function Point(x, y) { this.x = x; this.y = y; } Point.prototype.toString = function () { return '(' + this.x + ', ' + this.y + ')'; }; var p = new Point(1, 2); // class 方法 class Point { constructor(x, y) { this.x = x; this.y = y; } toString() { return '(' + this.x + ', ' + this.y + ')'; } }
差別點:
嚴格模式、不存在變量提高、this指向
與 ES5 同樣,在「類」的內部可使用get和set關鍵字,對某個屬性設置存值函數和取值函數,攔截該屬性的存取行爲
靜態方法不會被繼承
//現有 class Foo { } Foo.prop = 1; Foo.prop // 1 // 提案 Static prop = 1
私有方法/私有屬性
私有方法只能經過命名規則或者Symbol數據類型定義,私有屬性有個提案使用的是
#
ES6 提出的Moduel
是前端發展過程當中演變從CommonJs
遞進
循環加載問題