ES6語法詳解(一)

let變量

let聲明的變量在let命令所在的代碼塊中有效。不存在變量提高,只能先聲明後使用。javascript

暫存死區

若是區塊中存在letconst命令,這個區塊對這些命令聲明的變量,從一開始就造成了封閉做用域。凡是在聲明以前就使用這些變量。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常量

聲明常量必須立刻賦值且不能再改變。constlet有相似的特色:在塊級做用域內有效,聲明不提高,存在暫存死區,不可重複聲明。git

複合型數據如object,聲明後不可在從新賦值,但能夠修改這個值自己,好比修改屬性和新增屬性。凍結對象可使用Object.freeze方法。es6

const json = Object.freeze({});
//常規模式下修改json無效,嚴格模式下報錯

頂層變量

javascript的頂層對象是windownode的頂層對象是globalES6規定用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'

數值相關

Number對象擴展

ES6Number對象上提供了新的方法。

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對象擴展

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;

函數參數是默認聲明的,不能用letconst再次聲明,能夠用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屬性,將返回沒有指定默認值的參數個數。若是設置了默認值的參數不是尾參數,那麼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;    
}

rest參數

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屬性

函數的name屬性,返回該函數的函數名。若是將一個匿名函數賦值給一個變量,ES5name屬性,會返回空字符串,而 ES6name屬性會返回實際的函數名。

let fn = () => {}

//es5
fn.name  //''

//es6
fn.name  //'fn'

若是將一個具名函數賦值給一個變量,則 ES5ES6name屬性都返回這個具名函數本來的名字。

let fn = function a() {};
//es5 es6
fn.name    //'a'

箭頭函數

  • 函數體內的this對象,就是定義時所在的對象,而不是使用時所在的對象。
  • 不能夠看成構造函數,也就是說,不可使用new命令,不然會拋出一個錯誤。
  • 不可使用arguments對象,該對象在函數體內不存在。若是要用,能夠用 rest 參數代替。
  • 不可使用yield命令,所以箭頭函數不能用做 Generator 函數。

箭頭函數根本沒有本身的this,致使內部的this就是外層代碼塊的this

除了this,如下三個變量在箭頭函數之中也是不存在的,指向外層函數的對應變量:argumentssupernew.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()

Array.from方法用於將兩類對象轉爲真正的數組:相似數組的對象和可遍歷(iterable)的對象(包括 ES6 新增的數據結構 SetMap)。將類數組轉成數組

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方法用於將一組值,轉換爲數組。

Array.of(3,4) // [3,4]
Array.of(2)   // [2]

Array()方法不一樣,傳入一個值時,表示數組的長度。

Array(2)  //[undefinde, undefined]

find()和findIndex()

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() 方法

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() 是對鍵值對的遍歷。keys(), values(), entries() 返回一個遍歷器對象。能夠用 for...of 循環進行遍歷。

includes() 方法

includes() 判斷數組是否包含給定的值,返回布爾值,NaN 也能實現。它還有第二個參數,表示查找的起始位置,爲負數則表示從後往前。
indexOf() 方法對 NaN 無效,會返回-1;

includes 爲 ES2016 引入的方法。

相比於 indexOf,返回的是元素第一次出現的位置,再比較是否等於 -1,內部使用 === 判斷,對 NaN 不適用。

數組的空位

數組的空位指,數組的某一個位置沒有任何值。

Array(3);  //[,,]

ES5 對空位的處理不一致。大多數狀況下會被忽略。

  • forEach(), filter(), reduce(), every(), some() 會跳過空位。
  • map() 會跳過空位,但會保留這個值。
  • join() 和 toString() 會將空位視爲 undefined ,而 undefine 和 null 會被處理成空字符串。
// 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()

爲了解決相等運算符(==)和嚴格相等運算符(===)的缺點,Object.is 用來比較兩個值是否全等。

+0 === -0 //true
NaN === NaN // false

Object.is(+0, -0) // false
Object.is(NaN, NaN) // true

Object.assign()

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 或字符串,也不論是否可枚舉。

__ proto __屬性

用來讀取或設置當前對象的 prototype 對象。實現上,__proto__調用的是Object.prototype.__proto__

Object.keys(), Object.values(), Object.entries()

ES5 引入了 Object.keys 方法,返回一個數組,成員是參數對象自身的(不含繼承的)全部可遍歷(enumerable)屬性的鍵名。

ES6 引入了跟 Object.keys 配套的 Object.valuesObject.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,
};

Symbel

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 值必須放在方括號之中。

Module模塊

ES6 模塊經過export命令顯式指定輸出的代碼,再經過import命令輸入。使用模塊自動採用嚴格模式。嚴格模式詳解

export

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加載模塊。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;         //正確

importexport複合寫法:

export {foo, fn} from 'module';
//等同於
import {foo, fn} from 'module';
export {foo, fn};

模塊在瀏覽器中加載

加載javascript腳本使用<script>標籤,可以使用deferasync實現異步加載,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>
相關文章
相關標籤/搜索