let
聲明的變量在let
命令所在的代碼塊中有效。不存在變量提高,只能先聲明後使用。javascript
若是區塊中存在let
和const
命令,這個區塊對這些命令聲明的變量,從一開始就造成了封閉做用域。凡是在聲明以前就使用這些變量。html
var a = 1; { a = 2; //ReferenceError let a = 'a'; console.log(a); //'a'; }
在相同塊級做用域中,不能用let
重複聲明同一變量。即便已存在的變量是經過var
聲明的。java
let a = 1; let a = 2; //報錯 let a = 1; var a = 2; //報錯,var聲明有變量提高做用
在塊級做用域中,用let
聲明的變量只在當前做用域中有效,且不會受到外部的影響,因此塊級做用域能夠替代自執行函數表達式。node
理論上,函數在塊級做用域中聲明行爲和let
相似,但在es6瀏覽器環境中,爲了兼容老版本,函數聲明與var
聲明變量相似,會提高到全局做用域頭部,和當前塊級做用域的頭部,爲了不差別,能夠將函數聲明寫成函數表達式。react
let fn = function () {}; //函數表達式
聲明常量必須立刻賦值且不能再改變。const
和let
有相似的特色:在塊級做用域內有效,聲明不提高,存在暫存死區,不可重複聲明。git
複合型數據如object
,聲明後不可在從新賦值,但能夠修改這個值自己,好比修改屬性和新增屬性。凍結對象可使用Object.freeze
方法。es6
const json = Object.freeze({}); //常規模式下修改json無效,嚴格模式下報錯
javascript
的頂層對象是window
,node
的頂層對象是global
,ES6
規定用let
const
class
聲明的變量不在是頂層對象的屬性。github
let a = 1; window.a //undefined
從數組和對象中提取值,對變量進行賦值,稱爲解構(destructuring)web
數組的解構賦值,按照對應的順序賦值,若是值數量超出則多餘的值被拋棄,若是值不夠則爲undefined
。正則表達式
let arr = [1, [2, 3]]; let [a, [b, c]] = arr;
對象的解構賦值必需要屬性名相同,順序毫無影響。若是屬性名不一樣,須要寫成以下形式。
let {a: b} = {c: 1}; b //1
實際上對象解構賦值的是後者。
let {a} = {a: 1} //簡寫 let {a: a} = {a: 1} //全寫
字符串解構賦值和數組相似。
let [a, b, c] = 'hello'; console.log(a,b,c) //h,e,l
數組解構賦值默認值,當等號右邊的值 === undefined
時,默認值生效。
let [a = 1, b = 2] = [undefined, null]; console.log(a, b); //1 null
以上代碼邏輯是:
if ([undifined, null][0] === undefined) { a = 1; } else { a = [undifined, null][0] }
對象解構賦值默認值,當對象屬性值嚴格等於undefined
時。
let {a, b=2} = {1, undefined} a,b //1,2 let {a: b=1} = {a: undefined} b //1
事實上,只要某種數據結構具備 Iterator
接口,均可以採用數組形式的解構賦值。
函數參數的解構賦值,傳入的參數不是數組或對象,而是變量。
let fn = ( [a, b] ) => { return a + b; }; fn ([1, 2]); //3
[[1,2],[3,4]].map([a,b]=> a+b); //[3,7]
函數參數也可以使用默認值
let fn({a=1, b=2} = {}) { return [a,b]} fn({a:10}) // [10,2]
等號右邊若是不是對象,會先轉成對象,轉換失敗則報錯。
let {toString: s} = 123; s === Number.prototype.toString let {toString: s} = true; s === Blooean.prototype.toString
undefined
null
不能轉成對象,結構賦值報錯。
let {a} = undefined; //TypeError let {b} = null; //TypeError
解構賦值應用:
//交換變量的值 let a = 1, b = 2; [a,b] = [b, a]; //函數返回多個值 let fn = () => {x: 1, y: 2} //提取json數據 let {a, b} = obj;
ES6
提供for...of
方法遍歷字符串。
新增的其餘方法:startsWidth()
endsWidth()
includes()
。
let s = 'hello word!'; s.startsWith('hello'); //true s.endsWidth('word'); //true s.includes('o'); //true
charAt()
用於返回給定位置的字符,對於編碼大於0xFFFF的字符用at()
方法。
'ab'.charAt(0) //'a' '𠮷a'.charAt(0) //'\uD842' '𠮷a'.at(0) //'𠮷'
用於字符串拼接,{}
中能夠進行運算、引用對象、調用函數,非字符串類型會被轉成字符串。能夠嵌套使用,{}
中能夠再使用模版字符串。若是字符串中有反引號要用反斜槓轉義。
let name = 'zq'; `your name is ${name}`;
模版字符串中空格和和縮緊都會被保留,能夠用trim()
方法消除。
`<ul> <li><li> </ul>`.trim();
RegExp
構造函數參數有兩種狀況。
//參數一:字符串,參數二:修飾符 let reg = new RegExp('abc','i'); //參數一:正則表達式 let reg = new RegExp(/abc/);
以上代碼中,第二種只能傳一個參數,返回原有正則的拷貝,不容許傳第二個參數添加修飾符。
let reg = RegExp(/abc/, 'i'); //報錯
ES6
容許給RegExp
構造函數傳入第二個參數添加修飾符,即便第一個參數是正則,但會覆蓋原有正則表達式的修飾符。
let reg = new RegExp(/abc/g, i).flags //'i'
新增flags
屬性,返回正則表達式的修飾符。
//ES5的source屬性 /abc/i.source //'abc' //ES6的flags屬性 /abc/i.flags //'i'
ES6
在Number
對象上提供了新的方法。
Number.isFinite()
判斷是否爲有限數值。
Number.isFinite('1') //false Number.isFinite(NaN) //false Number.isFinite(1.01) //true Number.isFinite(Infinity) //false
Number.isNaN()
檢測一個值是否爲NaN
,只有NaN
纔會返回true
,其餘值一概返回false
。
全局方法isFinite()
和isNaN()
會將傳入的值轉成數字類型再判斷,Number.isFinite()
和Number.isNaN()
方法參數必須是數值類型,不然直接返回false
。
isNaN('NaN') //true Number.isNaN('NaN') //false
ES6
將全局方法parseInt()
和parseFloat()
放到Number
對象上,行爲不變。
Number.isInteger()
用來判斷一個數是否爲整數。
小數和整數採用相同的存儲方式,小數點後全爲零也爲整數。
Number.isInteger(2) //true Number.isInteger(2.0) //true
Math.trunc()
方法返回數值的整數部分。
Math.trunc(1.1) //1 Math.trunc(-1.1) //-1 Math.trunc('1.1') //1 Math.trunc('a') //NaN
可使用Math.floor()
和Math.ceil()
方法模擬Math.trunc()
。
Math.trunc = Math.trunc || function(x) { return x < 0 ? Math.ceil(x) : Math.floor(x); };
ES6
新增了三角函數:
Math.sinh(x)
返回x的雙曲正弦Math.cosh(x)
返回x的雙曲餘弦Math.tanh(x)
返回x的雙曲正切Math.asinh(x)
返回x的反雙曲正弦Math.acosh(x)
返回x的反雙曲餘弦Math.atanh(x)
返回x的反雙曲正切ES6
新增了指數運算符**
。
let a = 2; a = a**3; //8 //能夠簡寫成 a **= 3
ES6
容許爲函數的參數設置默認值,即直接寫在參數定義的後面。使用默認值時,不能有同名參數。
function (x = 1) {} function (x, x=1) {} //報錯
默認參數不是傳值,而是每次都從新計算。
let y = 10; function fn (x = y+1) { console.log(x); } fn(); //11; y++; fn(); //12;
函數參數是默認聲明的,不能用let
或const
再次聲明,能夠用var
再次聲明。
function (x) { let x = 1; //報錯 var x = 1; //正常 }
函數默認值與解構賦值默認值結合使用。
//只使用解構賦值默認值 function fn ({a, b = 2}) { console.log (a, b); } fn ({a:1}); //1, 2 fn ({a:1, b:3}); //1, 3 fn (); //報錯 //使用解構賦值默認值和函數參數默認值 function fn ({a, b = 2} = {}) { console.log (a, b); } fn() //undefined, 2
函數默認值參數不是最後一個參數,則不能省略,能夠用undefined
代替,不能用null
代替。
function fn (x, y=1, z) { console.log(x, y, z); }; fn(1,2) //1,2,undefined fn(1,undefined,2); //1,1,2
將函數參數默認值設成undefined
表示此參數能夠省略。
function fn (x=undefined, y) {} fn(,2);
指定了默認值之後,函數的length
屬性,將返回沒有指定默認值的參數個數。若是設置了默認值的參數不是尾參數,那麼length
屬性也再也不計入後面的參數。
function fn (x, y=1, z) {}; fn(1,2,3).length; //1
一旦設置了參數的默認值,函數進行聲明初始化時,參數會造成一個單獨的做用域(context)與函數內部不是同一個做用域。等到初始化結束,這個做用域就會消失。這種語法行爲,在不設置參數默認值時,是不會出現的。
var x = 1; function f(x, y = x) { console.log(y); } f(2) // 2 //參數做用域以下: { let x = 2; let y = x; }
ES6
引入 rest
參數(形式爲...變量名
),用於獲取函數的多餘參數,rest
參數搭配的變量是一個數組,該變量將多餘的參數放入數組中。...變量
後不能再有參數,不然報錯。
函數的length
屬性不包括rest
參數。
function fn(x, ...rest) { console.log(Array.isArray(rest)); console.log(rest); }; fn(1,2,3).length; //1 //true //[2,3]
從 ES5
開始,函數內部能夠設定爲嚴格模式。ES7
規定只要函數參數使用了默認值、解構賦值、或者擴展運算符,那麼函數內部就不能顯式設定爲嚴格模式,不然會報錯。
函數的name
屬性,返回該函數的函數名。若是將一個匿名函數賦值給一個變量,ES5
的name
屬性,會返回空字符串,而 ES6
的name
屬性會返回實際的函數名。
let fn = () => {} //es5 fn.name //'' //es6 fn.name //'fn'
若是將一個具名函數賦值給一個變量,則 ES5
和 ES6
的name
屬性都返回這個具名函數本來的名字。
let fn = function a() {}; //es5 es6 fn.name //'a'
this
對象,就是定義時所在的對象,而不是使用時所在的對象。new
命令,不然會拋出一個錯誤。arguments
對象,該對象在函數體內不存在。若是要用,能夠用 rest
參數代替。yield
命令,所以箭頭函數不能用做 Generator
函數。箭頭函數根本沒有本身的this
,致使內部的this
就是外層代碼塊的this
。
除了this
,如下三個變量在箭頭函數之中也是不存在的,指向外層函數的對應變量:arguments
、super
、new.target
。
不能用call()
、apply()
、bind()
這些方法去改變this的指向。
擴展運算符用三個點號表示,功能是把數組或類數組對象展開成一系列用逗號隔開的值(數組),和...rest相反。
擴展運算符後面還能夠放置表達式。
let x = 1; ...(x > 0 ? ['a','b'] : []) //'a','b'
若是擴展運算符後面是一個空數組,則不產生任何效果。
[...[], 1] //[1]
擴展運算符能夠展開數組,因此再也不須要apply方法,將數組轉爲函數的參數。
Math.max.apply(null, [14, 3, 77]) // ES6 的寫法 Math.max(...[14, 3, 77])
擴展運算符可用於複製數組,合併數組。
let arr1 = [1,2]; //ES5 let arr2 = arr1.concat(); //ES6 let arr2 = [...arr1]; //ES6 let [...arr2] = arr1;
擴展運算符還能夠將字符串轉爲真正的數組。
[...'hello'] // [ "h", "e", "l", "l", "o" ]
任何 Iterator
接口的對象, 均可以用擴展運算符轉爲真正的數組。
經過 push
函數,將一個數組添加到另外一個數組的尾部。
let arr1 = [1,2,3]; let arr2 = [4,5]; arr1.push(...arr2);
擴展運算符其餘應用: 複製數組,合併數組,展開字符串(有Iterato接口的對象),**
let arr = [1,2]; let arr1 = [...arr]; //複製數組 let arr2 = [...arr, ...[3,4]]; //合併數組 let arr3 = [...'hello']; //展開字符串
Array.from
方法用於將兩類對象轉爲真正的數組:相似數組的對象和可遍歷(iterable
)的對象(包括 ES6
新增的數據結構 Set
和 Map
)。將類數組轉成數組
let arrayLike = { '0': 'a', '1': 'b', '2': 'c', length: 3 }; // ES5的寫法 var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c'] // ES6的寫法 let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
只要有length
屬性的對象就叫作相似數組的對象,就能夠被轉化。
let obj = {length: 2} Array.form(obj) //[undefined, undefined]
對於尚未部署該方法的瀏覽器,能夠用 Array.prototype.slice
方法替代。
const toArray = (() => Array.from ? Array.from : obj => [].slice.call(obj) )();
實際應用中,常見的相似數組的對象是 DOM 操做返回的 NodeList
集合,以及函數內部的 arguments
對象。Array.form()
均可以轉換。
Array.from
還能夠接受第二個參數,做用相似於數組的 map
方法,用來對每一個元素進行處理,將處理後的值放入返回的數組。若是 map
函數裏面用到了 this
關鍵字,還能夠傳入 Array.from
的第三個參數,用來綁定 this
。
Array.from([1, 2, 3], (x) => x * x); //等同於 Array.from([1,2,3]).map(x => x * x);
若是參數是一個真正的數組,Array.from
會返回一個如出一轍的新數組。
Array.from([1,2,3]) //[1,2,3]
Array.of
方法用於將一組值,轉換爲數組。
Array.of(3,4) // [3,4] Array.of(2) // [2]
和Array()
方法不一樣,傳入一個值時,表示數組的長度。
Array(2) //[undefinde, undefined]
find
方法找出第一個符合條件的數組成員。它的參數是一個回調函數,全部數組成員依次執行該回調函數,直到找出第一個返回值爲 true
的成員,而後返回該成員。若是沒有符合條件的成員,則返回 undefined
。
[1,2,3].find(v => v>2); //3 [1,2,3].find((v, i, arr) => { return v>2 });
數組實例的 findIndex
方法的用法與 find
方法很是相似,返回第一個符合條件的數組成員的位置,若是全部成員都不符合條件,則返回-1。
這兩個方法均可以接受第二個參數,用來綁定回調函數的 this
對象。
fill
方法使用給定值,填充一個數組。還能夠接受第二個和第三個參數,用於指定填充的起始位置和結束位置。
[1,2,3].fill('a'); //['a', 'a', 'a'] [1,2,3,4,5].fill('a', 2, 4); //[1, 2, 'a', 'a', 5]
若是填充的類型爲對象,那麼被賦值的是同一個內存地址的對象,而不是深拷貝對象。
let arr = new Array(2).fill({name: 'Jim'}); arr[0].name = 'Tim'; // [{name: 'Tim'}, {name: 'Tim'}]
keys()
是對鍵名的遍歷,values()
是對鍵值的遍歷,entries()
是對鍵值對的遍歷。keys(), values(), entries()
返回一個遍歷器對象。能夠用 for...of
循環進行遍歷。
includes()
判斷數組是否包含給定的值,返回布爾值,NaN
也能實現。它還有第二個參數,表示查找的起始位置,爲負數則表示從後往前。
而 indexOf()
方法對 NaN
無效,會返回-1;
includes 爲 ES2016 引入的方法。
相比於 indexOf,返回的是元素第一次出現的位置,再比較是否等於 -1,內部使用 === 判斷,對 NaN 不適用。
數組的空位指,數組的某一個位置沒有任何值。
Array(3); //[,,]
ES5 對空位的處理不一致。大多數狀況下會被忽略。
// forEach方法 [,'a'].forEach((x,i) => console.log(i)); // 1 // filter方法 ['a',,'b'].filter(x => true) // ['a','b'] // every方法 [,'a'].every(x => x==='a') // true // reduce方法 [1,,2].reduce((x,y) => return x+y) // 3 // some方法 [,'a'].some(x => x !== 'a') // false // map方法 [,'a'].map(x => 1) // [,1] // join方法 [,'a',undefined,null].join('#') // "#a##" // toString方法 [,'a',undefined,null].toString() // ",a,,"
ES6 會將空位轉爲 undefined。
Array.from 方法、擴展運算符(...)、entries()、keys()、values()、find() 和 findIndex() 會將數組的空位,轉爲 undefined ;for···of 會遍歷空位。
直接寫入變量和函數,做爲對象的屬性和方法。
let a = 1; let obj = { a, method() { return this.a } }
這種寫法用於函數的返回值。
function getPoint() { const x = 1; const y = 10; return {x, y}; }
定義對象有兩種方法。
obj.a = 1; obj['c' + 'd'] = 2;
若是使用字面量方式定義對象(使用大括號),在 ES5 中只能使用方法一。ES6 容許字面量定義對象時,用方法二(表達式)做爲對象的屬性名,即把表達式放在方括號內。
let lastWord = 'last word'; const a = { 'first word': 'hello', [lastWord] : 'world' }; a['first word'] // "hello" a[lastWord] // "world" a['last word'] // "world"
屬性名錶達式若是是一個對象,默認狀況下會自動將對象轉爲字符串[object Object]。
let obj1 = { a: 1 }; let obj2 = { b: 2 } let json = { [obj1] : 'value1', [obj2] : 'value2' } json //Object {[object Object]: 'value2'}
[obj1] 會把 [obj2] 覆蓋掉,而 json 最後只有一個 [object Object] 屬性。
爲了解決相等運算符(==)和嚴格相等運算符(===)的缺點,Object.is 用來比較兩個值是否全等。
+0 === -0 //true NaN === NaN // false Object.is(+0, -0) // false Object.is(NaN, NaN) // true
Object.assign 方法用於對象的合併,將源對象(source)的全部可枚舉屬性,複製到目標對象,屬於淺拷貝。
此方法的第一個參數是目標對象,後面的參數都是源對象。
若是目標對象與源對象有同名屬性,或多個源對象有同名屬性,則後面的屬性會覆蓋前面的屬性。
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}
若是隻有一個參數,Object.assign 會直接返回該參數。
const obj = {a: 1}; Object.assign(obj) === obj // true
若是首參不是對象,則會先轉成對象,而後返回,undefined 和 null 沒法轉成對象,報錯。若是不是首參,只有字符串會以數組形式拷貝入目標對象,其餘都不會產生效果。
typeof Object.assign(2) // "object"
let obj = {a: 1}; Object.assign(obj, undefined) === obj // true Object.assign(obj, null) === obj // true const v1 = 'abc'; const v2 = true; const v3 = 10; const obj = Object.assign({}, v1, v2, v3); console.log(obj); // { "0": "a", "1": "b", "2": "c" }
對象的每一個屬性都有一個描述對象(Descriptor),用來控制該屬性的行爲。Object.getOwnPropertyDescriptor 方法能夠獲取該屬性的描述對象。
let obj = { foo: 123 }; Object.getOwnPropertyDescriptor(obj, 'foo') // { // value: 123, // writable: true, // enumerable: true, // configurable: true // }
描述對象的 enumerable 屬性,稱爲」可枚舉性「,若是該屬性爲 false,就表示某些操做會忽略當前屬性。
有四個操做會忽略 enumerable 爲 false 的屬性。
for...in
循環:只遍歷對象自身的和繼承的可枚舉的屬性。Object.keys()
:返回對象自身的全部可枚舉的屬性的鍵名。JSON.stringify()
:只串行化對象自身的可枚舉的屬性。Object.assign()
: 忽略 enumerable 爲 false 的屬性,只拷貝對象自身的可枚舉的屬性。for...in 循環遍歷對象自身的和繼承的可枚舉屬性(不含 Symbol 屬性)。
Object.keys 返回一個數組,包括對象自身的(不含繼承的)全部可枚舉屬性(不含 Symbol 屬性)的鍵名。
Object.getOwnPropertyNames 返回一個數組,包含對象自身的全部屬性(不含 Symbol 屬性,可是包括不可枚舉屬性)的鍵名。
Object.getOwnPropertySymbols 返回一個數組,包含對象自身的全部 Symbol 屬性的鍵名。
Reflect.ownKeys 返回一個數組,包含對象自身的全部鍵名,無論鍵名是 Symbol 或字符串,也不論是否可枚舉。
用來讀取或設置當前對象的 prototype
對象。實現上,__proto__
調用的是Object.prototype.__proto__
。
ES5 引入了 Object.keys
方法,返回一個數組,成員是參數對象自身的(不含繼承的)全部可遍歷(enumerable)屬性的鍵名。
ES6 引入了跟 Object.keys
配套的 Object.values
和 Object.entries
,做爲遍歷一個對象的補充手段,供 for...of
循環使用。
Object.values() 方法返回一個數組,成員是參數對象自身的(不含繼承的)全部可遍歷(enumerable)屬性的鍵值。
Object.entries() 方法返回一個數組,成員是參數對象自身的(不含繼承的)全部可遍歷(enumerable)屬性的鍵值對數組。
const obj = { foo: 'bar', baz: 42 }; Object.entries(obj) // [ ["foo", "bar"], ["baz", 42] ]
ES7 將擴展運算符引入了對象。
可用於解構賦值:
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; x // 1 y // 2 z // { a: 3, b: 4 }
解構賦值不是最後一個參數,因此會報錯。解構賦值要求等號右邊是一個對象,不然報錯。
解構賦值的拷貝是淺拷貝,且不能複製繼承自原型對象的屬性。
用於拷貝對象 和 合併對象
let z = { a: 3, b: 4 }; let n = { ...z }; n // { a: 3, b: 4 }
這等同於使用 Object.assign
方法。
let ab = { ...a, ...b }; // 等同於 let ab = Object.assign({}, a, b);
與數組的擴展運算符同樣,對象的擴展運算符後面能夠跟表達式。
const obj = { ...(x > 1 ? {a: 1} : {}), b: 2, };
ES5 的對象屬性名都是字符串,這容易形成屬性名的衝突,爲了保證每一個屬性的名字都是獨一無二的,這樣就從根本上防止屬性名的衝突。這就是 ES6 引入Symbol的緣由。
它是 JavaScript 語言的第七種數據類型,前六種是:undefined、null、布爾值(Boolean)、字符串(String)、數值(Number)、對象(Object)。
let s = Symbel(); typeof s // 'Symbel'
s 是一個獨一無二的值。
Symbol 函數前不能使用 new
命令,不然會報錯。這是由於生成的 Symbol 是一個原始類型的值,不是對象。也就是說,因爲 Symbol 值不是對象,因此不能添加屬性。基本上,它是一種相似於字符串的數據類型。
Symbol 函數能夠接受一個字符串做爲參數,表示對 Symbol 實例的描述,主要是爲了在控制檯顯示,或者轉爲字符串時,比較容易區分。
let s1 = Symbol('foo'); s1 // Symbol(foo) s1.toString() // "Symbol(foo)"
若是 Symbol 的參數是一個對象,就會調用該對象的toString方法,將其轉爲字符串,而後才生成一個 Symbol 值。
Symbol 函數的參數只是表示對當前 Symbol 值的描述,所以相同參數的Symbol函數的返回值是不相等的。
Symbol 值不能與其餘類型的值進行運算,會報錯。可是,Symbol 值能夠顯式轉爲字符串。也能夠轉爲布爾值,可是不能轉爲數值。
let sym = Symbol('My symbol'); String(sym) // 'Symbol(My symbol)' sym.toString() // 'Symbol(My symbol)' Boolean(sym) // true !sym // false
let mySymbol = Symbol(); // 第一種寫法 let a = {}; a[mySymbol] = 'Hello!'; // 第二種寫法 let a = { [mySymbol]: 'Hello!' }; // 第三種寫法 let a = {}; Object.defineProperty(a, mySymbol, { value: 'Hello!' }); // 以上寫法都獲得一樣結果 a[mySymbol] // "Hello!"
Symbol 值做爲對象屬性名時,不能用點運算符。
在對象的內部,使用 Symbol 值定義屬性時,Symbol 值必須放在方括號之中。
ES6
模塊經過export
命令顯式指定輸出的代碼,再經過import
命令輸入。使用模塊自動採用嚴格模式。嚴格模式詳解
export
用於規定模塊的對外接口,輸出變量,函數,類。
//寫法1 export let a = 1; export function b () {}; //寫法2 let a = 1; function b () {}; export {a, b}; //報錯 let a = 1; export a;
一般輸出的變量就是原本的名字,能夠用 as
修改。
function a () {}; let b = 1; export { a as fnA, b as vB };
export
輸出的接口和模塊內部的變量是動態綁定關係,變量值改變,經過接口獲取的值也相應改變。
//test.js export let a = 1; setTimeout(() => a=2, 1000); import {a} from './test' //a = 1, 1s後變成2
export
必須處於模塊頂層,若是處於塊級做用域會報錯。import
也是如此。
function () { export let a = 1; //報錯 }
使用import
加載模塊。import - MDN
import {a, b} from './test'
import
後跟一個大括號,括號內指定須要導入的變量,變量名需對應。但能夠經過as
修改。
import {a as vA, b as vB} from './test';
import
後的from
用來指定模塊的路徑,絕對路徑或相對路徑,.js
能夠省略。若是模塊有配置文件,則不帶路徑。
import react, {Component} from 'react';
import
有提高效果,會提高到模塊頭部,先執行。
因爲import
是靜態執行,不能使用表達式和變量。好比from
後的路徑不能用一個變量代替。
import
會執行所加載的模塊,能夠直接跟模塊名。但屢次加載相同模塊只執行一次,import
語句是單例模式。
import 'module_name'; import {a} from './test'; import {b} from './test'; //等同於 import {a,b} from './test';
模塊總體加載:
import * as myModule from './my_module.js'; //以myModule爲命名空間,在myMoudle下能夠找到全部接口,不容許修改。
導入默認值 :
export default function () {}; import fn from './test';
- 導入默認值可使用任意名字代替輸出值。
import
後不用大括號。export default
後跟的變量名或函數名稱在模塊外部無效。- 一個模塊只能有一個默認輸出,
export default
只能使用一次。export default
表示將後面的值賦給default
,再輸出一個叫default
的變量或函數。export default
後不能有變量聲明語句。
//test.js function fn () {}; export default fn; //等同於 export {fn as default};
import {default as foo} from './test'; //等同於 import foo from './test';
export default let a = 1; //報錯 export default 10; //正確
import
和export
的複合寫法:
export {foo, fn} from 'module'; //等同於 import {foo, fn} from 'module'; export {foo, fn};
加載javascript
腳本使用<script>
標籤,可以使用defer
或async
實現異步加載,defer
會等到頁面渲染完,其餘腳本執行完再執行,async
只要資源加載完就終斷頁面渲染當即執行,不能保證多個async
腳本按順序執行。
在瀏覽器中可使用<script>
標籤加載模塊,但須要type='module'
屬性。
<script src='path/test.js' type='module'></script>
帶有type='module'
的<script>
都是異步加載,等同於自動打開了defer
屬性,也能夠加async
屬性,讓模塊加載完當即執行。
也能夠直接在<script>
標籤內加載模塊。
<script type='module'> import a from './test.js'; </script>