ES6 新特性

let const var

  1. var 存在變量提升自赔,變量可以在聲明前被使用妈嘹,值為undefinedlet ``var不可以在聲明前被使用绍妨,否則會報(bào)錯(cuò)润脸,ES6 明確規(guī)定,如果區(qū)塊中存在letconst`命令他去,這個(gè)區(qū)塊對這些命令聲明的變量毙驯,從一開始就形成了封閉作用域。凡是在聲明之前就使用這些變量灾测,就會報(bào)錯(cuò)爆价。
function test() {
    console.log(a); //undefind
    var a = 1;
    console.log(b); //Uncaught ReferenceError: Cannot access 'b' before initialization
    let b = 2;
}

這就引發(fā)了一個(gè)叫暫時(shí)性死區(qū)的現(xiàn)象,所謂暫時(shí)性死區(qū)媳搪,就是只要在同一作用域內(nèi)铭段,包括函數(shù)和塊級全局,letconst 就會綁定在這個(gè)區(qū)域秦爆,在這之前使用的話序愚,都會報(bào)錯(cuò),直到聲明過后等限。舉個(gè)例子:

var num = 2
function test() {
    console.log(num); //Uncaught ReferenceError: Cannot access 'num' before initialization
    const num = 1;
}
  1. var不存在塊級作用域爸吮,letconst存在塊級作用域。ES6前精刷,Javascript只區(qū)分全局作用域(整個(gè)script標(biāo)簽內(nèi)部或者一個(gè)獨(dú)立的js文件)和函數(shù)作用域(局部作用域)拗胜,ES5不存在塊級作用域(凡是用{}包起來的都算),所以對于var來說:
function test() {
    for(var i=0; i<10; i++) {}
    console.log(i); //10
}

對于let來說:

function test() {
    for(let i=0; i<10; i++) {}
    console.log(i); // Uncaught ReferenceError: i is not defined
}
  1. 初始值
    var let 可以不設(shè)置初始值怒允,const必須設(shè)置初始值
const a; // Uncaught SyntaxError: Missing initializer in const declaration
  1. 重復(fù)聲明
    var 可以重復(fù)聲明埂软, let const不允許
  2. 數(shù)據(jù)修改
    varlet允許修改數(shù)據(jù)或者重新賦值,const定義的如果是基本數(shù)據(jù)類型,是不允許修改的勘畔,如果是引用數(shù)據(jù)類型所灸,那么保存在棧中的堆地址是不可以修改的,真正的數(shù)據(jù)可以修改炫七。

解構(gòu)

  1. 數(shù)組解構(gòu)
const [a, b, c, d] = [1,2,3,4]
console.log(a,b,c,d); // 1 2 3 4
  1. 對象解構(gòu)
const {a, b, c, d} ={a: 1, b: 2, c: 3, d: 4}
console.log(a,b,c,d); // 1 2 3 4

模版字符串

var names = ["Tom", "Jane", "Tim"]
var name =  `${names} are coming.`

箭頭函數(shù)

  1. 3分鐘理解箭頭函數(shù)的this
  2. 沒有arguments
function test(){
  console.log(arguments)
}
test(1,2,3); // Arguments(3) [1, 2, 3, callee: ?, Symbol(Symbol.iterator): ?]
const test2 = () =>{
  console.log(arguments)
}
test2(); // Uncaught ReferenceError: arguments is not definedat test2
  1. 不能通過 new 關(guān)鍵字調(diào)用, 根據(jù)new的原理來看爬立,箭頭函數(shù)不具備調(diào)用的條件:
test.prototype
// {constructor: ?}
test2.prototype
// undefined

這里簡單描述一下new Test('abc')的調(diào)用過程:

  • 創(chuàng)建一個(gè)空對象obj
  • obj__proto__指向Test的原型對象prototype,此時(shí)便建立了obj對象的原型鏈:obj->Animal.prototype->Object.prototype->null
  • obj對象的執(zhí)行環(huán)境調(diào)用Test函數(shù)并傳遞參數(shù)'abc'万哪。 相當(dāng)于var result = obj.Test('abc').
  • 考察第3步返回的返回值侠驯,如果無返回值或者返回一個(gè)非對象值,則將obj返回作為新對象奕巍;否則會將返回值作為新對象返回吟策。

形參默認(rèn)值

有默認(rèn)值的形參位置要放到最后

function add(a,b,c=2) {
    console.log(a + b + c);
}
add(1,2) //5

與解構(gòu)賦值結(jié)合使用 結(jié)構(gòu)賦值的先后不影響

function connect({name, age=18, sex}) {
    console.log(name);
    console.log(age);
    console.log(sex);
  }
  connect({
    name:'小寶',
    sex: 'man'
  })

Symbol

Symbol是ES6新引入的一種原始數(shù)據(jù)類型,表示獨(dú)一無二的值的止,常用于命名不能沖突的場景檩坚,比如對象的key,或者定義常量替換無意義的字符串诅福,創(chuàng)建時(shí)直接Symbol()匾委,不能使用new
作為key:

const MY_KEY = Symbol();
let obj = {};
obj[MY_KEY] = 123;
console.log(obj[MY_KEY]); // 123
let obj2 = {
  [MY_KEY]: 123
};
console.log(obj2[MY_KEY]); // 123
let obj3 = {
  [MY_KEY]() {
    return 'bar';
  }
};
console.log(obj3[MY_KEY]()); // bar

作為常量

const levels = {
  DEBUG: Symbol('debug'),
  INFO: Symbol('info'),
  WARN: Symbol('warn'),
}

function log(type, message) {
  switch (type) {
    case levels.DEBUG:
      console.log(message)
      break
    case levels.INFO:
      console.log(message)
      break
    case levels.WARN:
      console.log(message)
      break
    default:
      console.log('default')
      break
  }
}

Symbol.for(key)

Symbol.for(key)通過key(一個(gè)字符串氓润,作為 symbol 注冊表中與某 symbol關(guān)聯(lián)的鍵赂乐,同時(shí)也會作為該 symbol 的描述)來判斷其唯一性,key必須是字符串或者可以被轉(zhuǎn)換成字符串(因此Symbol類型不能作為key旺芽,不過很難想象它有toString方法卻不能被動轉(zhuǎn)換成字符串)沪猴,不是字符串的,調(diào)用toString()轉(zhuǎn)換為字符串采章,如果無法轉(zhuǎn)換成字符串的运嗜,會報(bào)錯(cuò)。undefinednull 沒有toString(),但是不會報(bào)錯(cuò)悯舟,當(dāng)做字符串'undefined''null'處理担租,默認(rèn)值即為undefined。返回由給定的 key 找到的 symbol抵怎,否則就是返回新創(chuàng)建的symbol奋救。
判斷Symbol.for(key)的返回值是否相等其實(shí)就是在判斷兩個(gè)keytoString()返回結(jié)果是否相等.

Symbol.for([1,2,3]) === Symbol.for('1,2,3'); // true
Symbol.for() === Symbol.for(undefined); // true
Symbol.for() === Symbol.for('undefined'); // true
Symbol.for(null) === Symbol.for('null'); // true
Symbol.for({}) === Symbol.for({a: 123}); // true
Symbol.for([]) === Symbol.for(""); // true
Symbol.for(Infinity) === Symbol.for("Infinity"); // true
Symbol.for(NaN) === Symbol.for("NaN"); // true

Symbol.iterator

Symbol.iterator是一個(gè)內(nèi)置值如果對象有Symbol.iterator, 即obj[Symbol.iterator] !== undefined那么這個(gè)對象就可以被for...of遍歷

for (let i of [1,2,3] ) {
  console.log(i); // 1 2 3
}

for (let i of {num1: 1, num2: 2} ) {
  console.log(i); // Uncaught TypeError: {(intermediate value)(intermediate value)} is not iterable
}

因此如何讓一個(gè)對象可以被for...of:

  1. 給對象添加一個(gè)keySymbol.iterator的屬性方法
  2. 這個(gè)方法必須返回一個(gè)迭代器對象,它的結(jié)構(gòu)必須如下:
{
    next: function() {
        return {
            value: any, //每次迭代的結(jié)果
            done: boolean //迭代結(jié)束標(biāo)識
        }
    }
}

舉個(gè)例子:

obj={names: ["Tom", "Jane", "Tim"];
obj[Symbol.iterator] = function () {
  let i = 0
  const _this = this
  return {
    next: () => {
      return { 
        value: _this.names[i++], 
        done: i === _this.names.length 
      }
    },
  }
}
for(let i of obj) {
    console.log(i); // Tom Jane Tim
}

獲得屬性名稱

const MY_KEY = Symbol()
let obj2 = {
  [MY_KEY]: 123,
  enum: 2,
  nonEnum: 3,
}
console.log(Object.getOwnPropertyNames(obj2)) // ['enum', 'nonEnum']
console.log(Object.getOwnPropertySymbols(obj2)) // [Symbol()]
console.log(Reflect.ownKeys(obj2)) // ['enum', 'nonEnum', Symbol()]

Set

類似數(shù)組反惕,但成員值都是唯一的尝艘,可以方便的去重,求并集姿染、交集背亥、差集。

Map

Promise

有三種狀態(tài)pending fulfilled rejected

創(chuàng)建實(shí)例

new Promise(function(resolve, reject) {...})
創(chuàng)建Promise實(shí)例時(shí),需要往構(gòu)造方法中傳入一個(gè)函數(shù)作為參數(shù)狡汉,這個(gè)函數(shù)可以通過調(diào)用傳入的resolvereject方法來改變promise實(shí)例的狀態(tài)娄徊,調(diào)用resolvepending轉(zhuǎn)變?yōu)?code>fulfilled,調(diào)用rejectpending轉(zhuǎn)變?yōu)?code>rejected

實(shí)例方法

  1. then 實(shí)例狀態(tài)發(fā)生變化時(shí)盾戴,觸發(fā)的回調(diào)函數(shù)寄锐,第一個(gè)參數(shù)是 resolved狀態(tài)的回調(diào)函數(shù),第二個(gè)參數(shù)是 rejected 的回調(diào)函數(shù)(一般使用 catch 方法來替代第二個(gè)參數(shù))
  2. catch 用于指定發(fā)生錯(cuò)誤的回調(diào)函數(shù)
  3. finally 用于指定 不管 Promise對象最后狀態(tài)如何尖啡,都會執(zhí)行的操作

靜態(tài)方法

  1. Promise.all 將多個(gè) Promise 實(shí)例包裝成一個(gè)新的 Promise 實(shí)例
    const p = Promise.all([p1, p2, p3]);
    只有 p1,p2,p3 狀態(tài)全為 fulfilled橄仆,p 的狀態(tài)才會變成fulfilled。此時(shí)可婶,p1,p2,p3 的返回值組成一個(gè)數(shù)組沿癞,傳遞給 p 的回調(diào)函數(shù)。
    只要 p1,p2,p3 有一個(gè)狀態(tài)為 rejected 矛渴,那么 p 的狀態(tài)就變成 rejected。此時(shí)第一個(gè)被reject的實(shí)例的返回值惫搏,會傳遞給p的回調(diào)函數(shù)具温。

  2. Promise.race 將多個(gè) Promise實(shí)例包裝成一個(gè)新的 Promise 實(shí)例
    const p = Promise.race([p1, p2, p3]);
    三者誰先改變狀態(tài), p 也就會跟著改變狀態(tài)筐赔。率先改變的會將返回值傳遞給 p 的回調(diào)函數(shù)铣猩。

await async

async 是加在函數(shù)前的修飾符,被async定義的函數(shù)會默認(rèn)返回一個(gè)Promise對象的實(shí)例茴丰,因此被async標(biāo)記的函數(shù)可以直接then达皿。
await也是一個(gè)修飾符,只能使用于被標(biāo)記為async的方法內(nèi)贿肩,取到值時(shí)才會往下執(zhí)行峦椰。

淺聊 promise setTimeout aysnc await

  • 首先,這些不是同步任務(wù)汰规。
  • JS是單線程語言(注意區(qū)分線程和進(jìn)程汤功,而且僅JS是單線程,瀏覽器渲染等占用的是其他線程)溜哮,在這個(gè)單線程上滔金,會有同步任務(wù)和異步任務(wù),異步任務(wù)又包括宏觀任務(wù)和微觀任務(wù)茂嗓。
  • 宏觀任務(wù)包括(宿主發(fā)起):script(整體代碼)setTimeout setInterval餐茵、I/O UI交互事件 postMessage MessageChannel setImmediate
  • 微觀任務(wù)包括(JS引擎發(fā)起):promise.then MutationObserver process.nextTick await/async(實(shí)際上是promise + generator 語法糖)
  • 執(zhí)行順序 所有的微任務(wù)都存在于某個(gè)宏任務(wù)中,所以一定是由宏任務(wù)開始執(zhí)行述吸。首先我們分析有多少個(gè)宏任務(wù)忿族,在每個(gè)宏任務(wù)中,分析有多少個(gè)微任務(wù),根據(jù)調(diào)用次序肠阱,確定宏任務(wù)中的微任務(wù)執(zhí)行次序票唆,根據(jù)宏任務(wù)的觸發(fā)規(guī)則和調(diào)用次序,確定宏任務(wù)的執(zhí)行次序屹徘,最后確定整個(gè)順序走趋。
console.log('start')
setTimeout(() => {
    console.log('setTimeout complete')
})
setTimeout(() => {
    new Promise((resolve, reject) => {
        for(let i =0;i<5;i++) {
        }
        console.log('promise3 internal function complete')
        resolve()
    }).then(() => {
        console.log('promise3 complete')
    });new Promise((resolve, reject) => {
        for(let i =0;i<5;i++) {
        }
        console.log('promise4 internal function complete')
        resolve()
    }).then(() => {
        console.log('promise4 complete')
    });
})
new Promise((resolve, reject) => {
    for(let i =0;i<5;i++) {
    }
    console.log('promise internal function complete')
    resolve()
}).then(() => {
    console.log('promise complete')
});new Promise((resolve, reject) => {
    for(let i =0;i<5;i++) {
    }
    console.log('promise2 internal function complete')
    resolve()
}).then(() => {
    console.log('promise2 complete')
});
/**
console.log('end')
start
promise internal function complete
promise2 internal function complete
end
promise complete
promise2 complete
setTimeout complete
promise3 internal function complete
promise4 internal function complete
promise3 complete
promise4 complete
**/

以上代碼的順序大致可以描述為:

  1. script宏觀任務(wù)
  2. 同步任務(wù):console setTimeout Promise等初始化
  3. 所有微任務(wù) promise1.then promise2.then
  4. 下一個(gè)宏任務(wù) setTimeout1
  5. 同步任務(wù): console
  6. 無微觀任務(wù),因此直接開始下一個(gè)宏觀任務(wù) setTimeout2
  7. 同步任務(wù) Promise初始化
  8. 所有微任務(wù) promise3.then promise4.then

深拷貝 淺拷貝

深拷貝后的所有數(shù)據(jù)均不受被拷貝的數(shù)據(jù)的影響噪伊,至于為什么有可能被影響不做贅述簿煌。
淺拷貝基本上是拷貝第一層的基本數(shù)據(jù)類型值,以及第一層的引用類型地址鉴吹。

淺拷貝 Object.assign

Object.assign將一個(gè)或多個(gè)源對象的可枚舉屬性的值復(fù)制到目標(biāo)對象姨伟,并返回目標(biāo)對象。

const obj1 = {
    name: 'Sue',
    age: 18,
    getAge: () => this.age,
    key: Symbol('key'),
    mom: {
        name: 'Jane',
        age: 45,
        key: Symbol('key')
    }
}
const obj2 = {}
Object.assign(obj2, obj1)
// {name: 'Sue', age: 18, key: Symbol(key), mom: {…}, getAge: ?}
obj2.mom.age = 50
obj1.mom.age
// 50

以上例子可以證明使用Object.assign實(shí)現(xiàn)的是淺拷貝豆励,且可以拷貝Symbol數(shù)據(jù)類型夺荒。

淺拷貝 數(shù)組

concat

let arr = [1, 2, 3];
let arr2 = arr.concat()

slice

let arr = [1, 2, 3];
let arr2 = arr.slice()

深拷貝 JSON.parse + JSON.stringify

let arr = [1, 3, { username: ' kobe' },function(){}];
let arr2 = JSON.parse(JSON.stringify(arr));
arr2[2].username = 'duncan'; 
console.log(arr[2].username): //kobe

這種方式不能拷貝函數(shù)

let arr = [1, 3, { username: ' kobe' },function(){}];
let arr2 = JSON.parse(JSON.stringify(arr));
arr2[2].username = 'duncan'; 
console.log(arr2[3]); // undefined

深拷貝 遞歸遍歷

function checkType(value) {
  return Object.prototype.toString.call(value).slice(8, -1)
}

function deepClone(value) {
  const type = checkType(value);
  let result;
  if(type === 'Object') {
    result = {}
  } else if (type === 'Array') {
    result = []
  } else {
    return value
  }
  for(let i in value) {
    const _v = value[i];
    const _vt = checkType(_v);
    if (_vt === 'Array' || _vt === 'Object') {
      result[i] = deepClone(_v)
    } else {
      result[i] = _v
    }
  }
  return result
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市良蒸,隨后出現(xiàn)的幾起案子技扼,更是在濱河造成了極大的恐慌,老刑警劉巖嫩痰,帶你破解...
    沈念sama閱讀 222,729評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件剿吻,死亡現(xiàn)場離奇詭異,居然都是意外死亡串纺,警方通過查閱死者的電腦和手機(jī)丽旅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纺棺,“玉大人榄笙,你說我怎么就攤上這事∥辶桑” “怎么了办斑?”我有些...
    開封第一講書人閱讀 169,461評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長杆逗。 經(jīng)常有香客問我乡翅,道長,這世上最難降的妖魔是什么罪郊? 我笑而不...
    開封第一講書人閱讀 60,135評論 1 300
  • 正文 為了忘掉前任蠕蚜,我火速辦了婚禮,結(jié)果婚禮上悔橄,老公的妹妹穿的比我還像新娘靶累。我一直安慰自己腺毫,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評論 6 398
  • 文/花漫 我一把揭開白布挣柬。 她就那樣靜靜地躺著潮酒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪邪蛔。 梳的紋絲不亂的頭發(fā)上急黎,一...
    開封第一講書人閱讀 52,736評論 1 312
  • 那天,我揣著相機(jī)與錄音侧到,去河邊找鬼勃教。 笑死,一個(gè)胖子當(dāng)著我的面吹牛匠抗,可吹牛的內(nèi)容都是我干的故源。 我是一名探鬼主播,決...
    沈念sama閱讀 41,179評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼汞贸,長吁一口氣:“原來是場噩夢啊……” “哼绳军!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起矢腻,我...
    開封第一講書人閱讀 40,124評論 0 277
  • 序言:老撾萬榮一對情侶失蹤删铃,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后踏堡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,657評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡咒劲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評論 3 342
  • 正文 我和宋清朗相戀三年顷蟆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片腐魂。...
    茶點(diǎn)故事閱讀 40,872評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡帐偎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蛔屹,到底是詐尸還是另有隱情削樊,我是刑警寧澤,帶...
    沈念sama閱讀 36,533評論 5 351
  • 正文 年R本政府宣布兔毒,位于F島的核電站漫贞,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏育叁。R本人自食惡果不足惜迅脐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望豪嗽。 院中可真熱鬧谴蔑,春花似錦豌骏、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至钦睡,卻和暖如春蒂窒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背赎婚。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評論 1 274
  • 我被黑心中介騙來泰國打工刘绣, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人挣输。 一個(gè)月前我還...
    沈念sama閱讀 49,304評論 3 379
  • 正文 我出身青樓纬凤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親撩嚼。 傳聞我的和親對象是個(gè)殘疾皇子停士,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評論 2 361

推薦閱讀更多精彩內(nèi)容

  • ES6 新特性 ES6 新特性 一ES6簡介 二塊級作用域綁定1 let聲明2 const聲明Constant D...
    _無為_閱讀 847評論 0 3
  • 總結(jié): var let const的區(qū)別 數(shù)組新增拓展 對象新增拓展 函數(shù)新增拓展 Set 和 Map Promi...
    Porsche_Apo閱讀 727評論 0 0
  • ES6、ES7完丽、ES8特性一鍋燉(ES6恋技、ES7、ES8學(xué)習(xí)指南) 概述 ES全稱ECMAScript逻族,ECMAS...
    李振亞_cb74閱讀 314評論 0 0
  • ES6語法 Tags: javascript [TOC] const 與 let 變量 使用var帶來的麻煩: 運(yùn)...
    Showdy閱讀 179,168評論 6 114
  • ES6改動很大蜻底,可以簡單分為四類1、解決原有語法的缺陷和不足例如:let聘鳞,const2薄辅、對原有語法進(jìn)行增強(qiáng)解構(gòu)、擴(kuò)...
    少_游閱讀 8,288評論 0 12