阮一峯ES6全面回顧

9月抽空從新回顧了下ES6全部知識點,整個回顧過程既驚喜又感慨,感慨開發這麼久好像真的沒有好好的靜下心去讀一本好的書,大多狀況下只是在使用的時候用到了,不熟悉或者感興趣再去蜻蜓點水一通,感慨之餘也發現了一些自身的的問題,知識體系仍是不夠豐富、紮實,一句話:有空多讀書總沒錯,好了不閒扯了,下面咱們步入正題

關於JavaScript

現在前端知識突飛猛進,越是晚入門小夥伴,不少基礎層面的東西,接觸的真的是少之又少,各類前端框架層粗不窮 VueReactNg這三大帶有里程碑意義的框架 Api我想看的這麼文字的盆友應該都有接觸,基礎的 Api使用應該是沒有什麼難度,可是在遇到問題,解決問題、以及在原有組件以及自我封裝組件,搭建框架過程總會遇到一些莫名其妙的問題,解決這個問題, 看源碼是大衆都知道的一些方法,但我的認爲這是一種進階的方法,新手入門建議能夠先了解我們 JavaScript的發展史能夠比較輕鬆的認識咱們整個技術體系的發展和將來方向,避免一些認知錯誤

發展史

  1. 互聯網早期javascript

    • BS架構:1990年的12月25日,西方的聖誕節,Tim Berners-Lee在他的NeXT電腦上部署了第一套「主機-網站-瀏覽器」構成的Web系統,這標誌BS架構的網站應用軟件的開端,也是前端工程的開端。這個時候前端只是簡單的Html靜態文本簡單到基本動畫都沒有
    • 1995年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的官方標準。
  2. 互聯網發展期前端

    • 動態頁面伊始:因爲javascript推進,前端頁面開始走向動態化,那時流行的跑馬燈、懸浮廣告基本是各大門戶網站的標配,頁面基本都是經過PHP、JSP、ASP動態渲染出來,這也直接致使後端代碼的邏輯臃腫,服務端爲了更好的管理代碼,應運而生MVC模式
    • Ajax出現:前期的動態性徹底由服務端推進,每一次的動態更新都須要將頁面進行reload操做,無論交互仍是性能,都是不值當的 "這個問題直到谷歌在04年應用Ajax技術開發的Gmail和谷歌地圖的發佈,才獲得瞭解決。" 這背後的祕密就是Ajax技術中實現的異步HTTP請求,這讓頁面無需刷新就能夠發起HTTP請求,用戶也不用專門等待請求的響應,而是能夠繼續網頁的瀏覽或操做。
      Ajax開啓了web2.0的時代
    • 前端兼容問題:因爲更重瀏覽器差別性,兼容問題也是層出不窮,不一樣的瀏覽器技術標準有不小的差別,不利於兼容開發,這催生了Dojo、Mooltools、YUIExtJS、jQuery等前端兼容框架,其中jQuery應用最爲普遍。這些框架中不知道你們用過幾個
    • Html5誕生:部分瀏覽器廠商爲了解決適配問題提出過Web Forms 2.0Web Applications 1.0等規章最後整合成HTML五、各大瀏覽器都在爲適配瀏覽器不斷改善本身的瀏覽器
    • Node.js:2009年,Ryan Dahl以Chrome的V8引擎爲基礎開發了基於事件循環的異步I/O框架-Node.js。Node.js使得前端開發人員能夠利用javascript開發服務器端程序。很快,大量的Node.js使用者就建構了一個用NPM包管理工具管理的Node.js生態系統。node.js也能開發跨平臺的桌面應用
    Node 衍生出的 NPM包管理工具爲整個前端社區提供了一個規範良好的平臺
  3. 互聯網進擊java

    • 移動App、Hybrid App:移動互聯網的到來,飛速發展,原生app迭代遠遠知足不了,你們找到折中的方法,損耗部分性能,提升產品產出;jQuery Mobile、Sencha Touch、Framework7如魚得水;Hybrid技術指的是利用Web開發技術,調用Native相關的API,實現移動與Web兩者的有機結合,既能利用Web開發週期短的優點,又能爲用戶提供Native的體驗。
    • ECMAScript6:2015年6月,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技術。

ECMAScript簡介

提案規則

權重自上到下node

  • Stage 0 - Strawman(展現階段)
  • Stage 1 - Proposal(徵求意見階段)
  • Stage 2 - Draft(草案階段)
  • Stage 3 - Candidate(候選人階段)
  • Stage 4 - Finished(定案階段)

通常走到草案階段基本能夠在正式標準中看到,Tc39可查看各提案es6

Tips:這也是在babel中配置presets的來由(可能咱們使用了一些仍然在草案甚至徵求意見階段的API)的時候需babel墊片web

Babel轉碼器

配置.babelrc/babel.config.js
// 基本格式
{
    "presets":[]
    "plugins":[]
}

不一樣環境支持不一樣的轉換方法正則表達式

  • 命令行 //@babel/cli
  • 瀏覽器環境 //HTML中引入對應腳本
  • node環境 //Traceur模塊

通常咱們使用的腳手架默認配置好,可是咱們須要配置的什麼意思,以及爲何要配置編程

@babel/register、babel-core/register

改寫require命令,爲每一個require引入的資源進行Babel轉義windows

@babel/polyfill

Babel僅會轉換新的語法,可是已有的Api中的Iterator、Generator、Set、Map、Proxy、Reflect、Symbol、Promise是須要用這個墊片處理後端

@babel/core

暴露出Babel的Api,進行特殊操做


ES6基礎篇

基礎篇咱們主要從es6中添加的一些命令,以及對已有數據類型拓展的彙總

clipboard.png

let & const

let

特性以下

  1. 區別於var的塊級做用域
  2. 不存在變量提高問題
  3. 具備暫時性死區
  4. 不能重複命名
// 下面這塊很好的體現了`塊級做用域`

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

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()
  • 函數入參清晰多參數
  • JSON對象快速提取對應值
  • 函數設置默認值

字符串

字符串中改動仍是蠻多的有添加Unicode表示JSON.stringify()適配非UTF-8編碼,下面介紹平常開發實用改變

添加Iterator接口

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轉換函數

字符串方法

  • String.fromCodePoint()// 識別大於0xFFFF的字符
  • String.raw() // 返回斜槓都轉義的字符
  • codePointAt()

    charAt() // UTF-8
        codePointAt() // UTF-16
  • normalize() //處理合成字符串
  • includes(), startsWith(), endsWith()

    includes():返回布爾值,表示是否找到了參數字符串。
    startsWith():返回布爾值,表示參數字符串是否在原字符串的頭部。
    endsWith():返回布爾值,表示參數字符串是否在原字符串的尾部。
  • repeat() // 返回一個新字符,參數是重複次數
  • padStart(),padEnd() // 頭/尾部補全字符 兩個參數第一個長度、第二個填補的str
  • trimStart(),trimEnd() // 消除頭/尾部空格
  • matchAll() // 字符正則匹配 參數正則表達式

數值類型

二進制、八進制表示法

0b(0B)二進制;0o(0O)八進制

方法

  • Number.isFinite(), Number.isNaN()
    判斷是否有限、判斷參數類型是否爲NAN
  • Number.parseInt(), Number.parseFloat()
    將全局方法移植到內置對象下
  • Number.isInteger() 判斷是不是整數
  • Number.EPSILON // 常量 表示 1 與大於 1 的最小浮點數之間的差。
  • Math.trunc() // 返回整數
  • Math.sign() // 判斷是否正數、負數、零
  • Math.cbrt() // 計算數組的立方根
  • Math.clz32() // 返回 32位前置零個數
  • Math.imul // 返回兩個數以 32 位帶符號整數形式相乘的結果
  • ...

拓展符號(右結合即右邊先運算)

****= 操做符 進行指數運算

//指數拓展符
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() // 用於將一組值,轉換爲數組

實例方法拓展

  • find()、findIndex() // find找到第一個知足條件的值,findIndex和前者相似,可是返回是下標,找不到返回-1
  • fill() 數組填充(params0:填充的值,params1:開始下座標,params2:結束下座標)
  • entries(),keys() 和 values() // 返回數組的鍵值對
  • includes() //是否包含某個值,返回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]
  • sort() //ES2019 明確要求排序的穩定性

數組的空位

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()代替

遍歷方法
  1. for in
  2. Object.getOwnPropertyNames()

    1. 返回一個數組,包含對象自身的全部屬性(不含 Symbol 屬性,可是包括不可枚舉屬性)的鍵名。
  3. Object.getOwnPropertySymbols()

    1. 返回一個數組,包含對象自身的全部 Symbol 屬性的鍵名。
  4. Reflect.ownKeys()

    1. 返回一個數組,包含對象自身的全部鍵名,無論鍵名是 Symbol 或字符串,也無論是否可枚舉。
  5. Object.is()

    1. 傳統判斷值是否相等使用==或者===,前者會強制類型轉換,後者NAN不等於自身,並+0等於-0,此方法就解決了上述問題
  6. Object.assign()

    1. Object.assign方法用於對象的合併,將源對象(source)的全部可枚舉屬性,複製到目標對象(target),第一個參數就是目標對象,只會處理可枚舉的數據類型,並Symbol值屬性也會被拷貝
    2. 數組處理將值一一對應成對象類型
  7. Object.getOwnPropertyDescriptors()

    1. 對ES5中Object.getOwnPropertyDescriptor()的拓展,返回對象中全部屬性(非繼承)的值
  8. 原型操做方法替代__proto__

    1. Object.setPrototypeOf()(寫操做)、
    2. Object.getPrototypeOf()(讀操做)、
    3. Object.create()(生成操做
  9. 對象鍵值對獲取

    1. Object.keys(),
    2. Object.values(),
    3. Object.entries()
    4. Object.fromEntries() // Object.fromEntries()方法是Object.entries()的逆操做,用於將一個鍵值對數組轉爲對象

遍歷規則以下:
  • 首先遍歷全部數值鍵,按照數值升序排列。
  • 其次遍歷全部字符串鍵,按照加入時間升序排列。
  • 最後遍歷全部 Symbol 鍵,按照加入時間升序排列。
Super 關鍵字

指向當前對象的原型對象。

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。


ES6進階篇

進階篇,咱們主要對新增的 Symbol、ArrayBuffer以及 Set和Map數據結構介紹、 Promise 到 async的演變和差別,異步遍歷的思想,以及 Class、Module的使用

Symbol類型

ES6引入的新的數據類型,保證了數據的獨一無二的特性,能夠用來標識對象的額惟一key值
// 新建類型
let a = Symbol()
// 添加描述(用於標識Symbol值)
let a = Symbol('描述文件')

特性:

  1. 不能new操做 注意Symbol()是一個相似string類型的值,不是對象
  2. 不能與其餘類型值進行計算
  3. 能夠顯性的轉換成字符類型/布爾值
  4. 座位對象的屬性的時候須要注意和字符型屬性,賦值、取值區別開來

方法:

  1. Symbol.for()、Symbol.keyFor()
    返回同一個標識的Symbol類型,keyFor返回當前Symbol類型的惟一標識
  2. Symbol.isConcatSpreadable
    判斷數組concat()操做的時候是否能夠會別唄展開
  3. Symbol.match
  4. Symbol.replace
  5. Symbol.search
  6. Symbol.match
  7. Symbol.iterator
  8. Symbol.toPrimitive
  9. Symbol.toStringTag
  10. Symbol.unscopables

Set、Map數據結構

Set

Set 數據結構。它相似於數組,可是成員的值都是惟一的,沒有重複的值。

特性:

  1. 去重
    Set() 去重的判斷相等依據和 === 基本一致,可是在判斷NAN的時候會判斷相等​​​,而且兩個對象老是不相等的​​​
  2. 屬性

    • size Set實例成員的總數
  3. 方法

    • add()
    • delete()
    • has() bool值,是不是set成員
    • clear() 清除全部set成員

WeakSet

Set 的區別

  • 只能存儲對象類型,不能是其餘數據類型
  • 不進入垃圾回收機制
  • 沒有size屬性,同時不能遍歷

Map

Map 的數據類型相似對象,可是對象的key值能夠是任意類型的 Map:值-值,不一樣於傳統 Object:字符串-值
屬性
  1. 屬性

    • size 成員總數
  2. 方法

    • set()
    • get()
    • has()
    • delete()
    • clear()

WeakMap

和Map的結構相似

Map的差別

  • 只接收對象做爲鍵名
  • WeakMap的鍵名所指向的對象,不計入垃圾回收機制

用途

  • 在 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;    }}
  • 私有變量

ArrayBuffer

操做二進制數據的一個接口。早就存在,屬於獨立的規格(2011 年 2 月發佈),ES6 將它們歸入了 ECMAScript 規格,而且增長了新的方法。它們都是以數組的語法處理二進制數據,因此統稱爲 二進制數組

注意:二進制數組並非真正的數組,而是相似數組的對象。

與Array的區別

  • 屬性類型

    • Array 能夠是基礎數據類型,也能夠是複雜數據類型
    • ArrayBuffer 只能是 0 和 1 組成的二進制數據
  • 數據存放規則

    • Array 複雜數據類型存放在堆中
    • ArrayBuffer 存放在棧中,讀取數據更快
  • 規格定義區別

    • Array 無需初始定義大小,而且在使用的時候能夠縮放大小
    • ArrayBuffer 初始化須要定義大小,並不能再次修改

ArrayBuffer 對象

存儲二進制數據的一段內存,不能直接進行讀寫,須要經過視圖進行操做
new ArrayBuffer(32) //分配一個32位字節的內存
屬性
- byteLength 返回分配區域的字節長度
方法
- slice() 操做ArrayBuffer 對象 生成一個新的內存地址
- isView() bool值返回是不是TypedArray視圖實例(是不是一個視圖)

TypedArray 視圖

構造方法
經過構造方法生成 視圖

注:存在溢出問題

  • TypedArray(buffer, byteOffset=0, length?)
  • TypedArray(length) // 直接分配內存
  • TypedArray(typedArray) // 直接複製一個視圖的值,生成一個新的視圖
  • TypedArray(arrayLikeObject) // 直接生成TypedArray實例
實例屬性
- buffer // 返回 ArrayBuffer 對象
- byteLength // 佔據內存長度(成員長度)
- byteOffset // 視圖從ArrayBuffer中開始位置
- length // 字節長度
實例方法
- set() // 複製數組
- subarray() // 返回新的視圖
- slice() // 返回新的視圖
- of() // 用於將參數轉爲一個TypedArray實例
- from() // from接受一個可遍歷的數據結構(好比數組)做爲參數,返回一個基於這個結構的TypedArray實例。​ 可有兩個參數,第二個參數是fun

DataView 視圖

實例屬性
- buffer // 返回 ArrayBuffer 對象
- byteLength // 佔據內存長度(成員長度)
- byteOffset // 視圖從ArrayBuffer中開始位置

應用場景

  1. 網絡請求中 blob 數據類型
  2. Canvas 讀取二進制像素數據
  3. WebSocket 傳輸二進制數據
  4. File new FileReader() 讀取 ArrayBuffer對象

Promise/async

Promise 異步編程的解決方案,社區的提案, async 結局了Promise的回調地獄

Promise

有 padding(進行中)、fulfilled(成功)、rejected(失敗)三種狀態,狀態已經改變就並不會變更
回調
  1. then() 返回結果
  2. catch() 捕獲異常
  3. finally() 異步回調後都會執行,無論成功仍是失敗
方法
  1. all(<array>)
    多個promise回調 等待內部全部Promise都返回成功結果/凡是一個返回reject才執行then(),多異步方法同時執行,全部都回調了再執行then() 方法
  2. race(<array>)
    同all,區別在於,只返回最早返回結果的異步請求,無論成功仍是失敗
  3. any()
    和recede 區別是一組Promise中只有全部都reject以後纔會返回失敗
  4. allSettled()
    不一樣於all的點是無論成功仍是失敗都須要等全部異步都返回接口才會返回,因此他的狀態永遠是fulfilled

注意:

  1. 在reject、resolve中使用return,避免後續代碼執行問題
  2. Promise.all 若是 子Promise已經擁有了 catch() 則 all() 的 catch() 再也不觸發​​

Async

async 只是對 promise 的寫法上的一種語法糖

async: 函數 返回一個Promise對象,return 返回Promise的結果

await: 後面默認是一個Promise對象

try catch(): 捕獲錯誤

頂層await
解決異步模塊加載的問題

class

將傳統 實例對象經過構造方法生成的過程放到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指向

取值函數(getter)和存值函數(setter)

與 ES5 同樣,在「類」的內部可使用get和set關鍵字,對某個屬性設置存值函數和取值函數,攔截該屬性的存取行爲

靜態方法 Static

靜態方法不會被繼承

靜態屬性

//現有
class Foo {
}

Foo.prop = 1;
Foo.prop // 1

// 提案
Static prop = 1

私有方法/私有屬性

私有方法只能經過命名規則或者Symbol數據類型定義,私有屬性有個提案使用的是 #

Module

ES6 提出的 Moduel是前端發展過程當中演變從 CommonJs遞進

Module 語法

  1. 靜態化 (編譯時加載)
  2. 嚴格模式 遵循ES5的嚴格模式
  3. export 和 export default 暴露模塊
  4. import 引入模塊
  5. import() 解決了按需加載/條件加載/動態模塊路徑的問題
  6. export * from <moduel> 實現模塊的繼承

Module 的加載實現

  1. defer、async
    defer是「渲染完再執行」,async是「下載完就執行」。另外,若是有多個defer腳本,會按照它們在頁面出現的順序加載,而多個async腳本是不能保證加載順序的。
  2. ES6 和 Commonjs 差別
    CommonJS 模塊輸出的是一個值的拷貝,ES6 模塊輸出的是值的引用。CommonJS 模塊是運行時加載,ES6 模塊是編譯時輸出接口。
  3. 循環加載問題

    1. Commonjs
      CommonJS 模塊遇到循環加載時,返回的是當前已經執行的部分的值,而不是代碼所有執行後的值,二者可能會有差別。因此,輸入變量的時候,必須很是當心。
    2. ES6使用 函數 提高的優點解決報錯
相關文章
相關標籤/搜索