let和const命令
let命令
- 循環體的let變量只對花括號做用域可見,花括號外不可見
- 循環體的語句部分是一個父做用域,而循環體內部是一個單獨的子做用域
- let聲明的變量不存在變量提高,未聲明的使用會報錯
- 只要塊級做用域內存在let聲明,它所聲明的變量就綁定了這個區域,再也不受外部的影響
- let不容許在相同的做用域重複聲明同一個變量,子父級做用域能夠同名變量聲明
const命令
- const常量的值一旦聲明就不得改變
- const一旦聲明變量,就必須當即初始化,不能留到之後賦值
- const的做用域與let命令相同,只在聲明所在的塊級做用域內有效
- const命令一樣存在暫時性死區,只能在聲明的位置後面使用
- const聲明的常量,也與let同樣不可重複聲明
- 對於複合類型的變量,變量名不指向數據,而是指向數據所在的地址,因此const命令只是保證變量名指向的地址不變,並不保證該地址的數據不變
——let和const命令的聲明再也不自動歸入global對象(window)javascript
塊級做用域與函數聲明
- ES6的瀏覽器下,塊級做用域內聲明的函數會被提高至全局做用域或函數做用域頂部,做爲
var fn = undefined
- 其餘的遊覽器下,仍是將塊級做用域的函數聲明看成let處理
- 應該避免在塊級做用域內聲明函數,若是確實須要也應該使用函數表達式而不是函數聲明
- ES6的塊級做用域容許聲明函數,但只在使用大括號的狀況下成立,若是沒有使用大括號就會報錯
變量的解構賦值
數組的解構賦值
- 只要某種數據結構具備Iterator接口,均可以採用數組形式的解構賦值
- 解構賦值容許指定默認值,可是若是一個數組成員不嚴格等於undefined,默認值不會生效
- 若是默認值是一個表達式,那麼這個表達式是惰性求值的,即只有在用到的時候纔會求值
- 默認值能夠引用解構賦值的其餘變量,但該變量必須已經聲明
- 可使用嵌套進行解構賦值
let [foo, [[bar], baz]] = [1, [[2], 3]];
對象的解構賦值
- 變量必須與屬性同名,才能取到正確的值
let { foo, bar } = { foo: "aaa", bar: "bbb" };
- 若是變量名與屬性名不一致,必須寫成
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
- 聲明後再進行的賦值必須加圓括號
let foo;——({foo} = {foo: 1});
- 對象的解構也能夠指定默認值,同數組同樣成員對應必須嚴格等於undefined,默認值纔會生效
字符串的解構賦值
- 字符串進行解構賦值時,會被轉換成一個相似數組的對象
const
- 相似數組的對象都有一個length屬性,所以還能夠對這個屬性解構賦值
let { length : len } = 'hello'
數值和布爾值的解構賦值
- 解構賦值的規則是,只要等號右邊的值不是對象或數組,就先將其轉爲對象
let {toString: s} = 123; s === Number.prototype.toString
- 因爲undefined和null沒法轉爲對象,因此對它們進行解構賦值,都會報錯
let { prop: x } = undefined;
函數參數的解構賦值
- 函數參數的解構賦值遵循基本解構類型的特色
圓括號問題
- 不能使用圓括號的狀況:
- a.變量聲明語句中,不能帶有圓括號
- b.函數參數中,模式不能帶有圓括號
- c.賦值語句中,不能將整個模式,或嵌套模式中的一層,放在圓括號之中
- 能使用圓括號的狀況:
解構賦值的用途
- 交換變量的值
- 從函數返回多個值
- 函數參數的定義
- 提取JSON數據
- 函數參數的默認值
- 遍歷Map結構
- 輸入模塊的指定方法
字符串的擴展
- codePointAt()——處理4個字節儲存的字符,返回一個字符的碼點(默認十進制,十六進制可使用toString方法轉換)
- String.fromCodePoint()——能夠識別大於0xFFFF的字符,彌補了String.fromCharCode方法的不足
- ES6爲字符串添加了遍歷器接口for...of,除了遍歷字符串,這個遍歷器最大的優勢是能夠識別大於0xFFFF的碼點
- at()提案——識別Unicode編號大於0xFFFF的字符,返回正確的字符
- normalize()——將字符的不一樣表示方法統一爲一樣的形式,這稱爲Unicode正規化
- 索引字符是否存在——接受二個參數,第一個表示索引字符,第二個表示起始位置
- includes()——返回布爾值,表示是否找到了參數字符串
- startsWith()——返回布爾值,表示參數字符串是否在源字符串的頭部
- endsWith()——返回布爾值,表示參數字符串是否在源字符串的尾部
- repeat()——將原字符串重複n次,返回一個新字符串
- a.參數若是是小數,會被取整
- b.參數是負數或Infinity,會報錯
- c.參數是0到-1之間的小數,則等同於0(這是由於會先進行取整運算)
- d.參數是字符串,則會先轉換成數字
- 字符串補全長度——接受兩個參數(第一個表示字符串補全的最小長度,第二個表示要參與補全的字符串)
- padStart()——用於頭部補全
- padEnd()——用於尾部補全
- a.若是原字符串的長度,等於或大於指定的最小長度,則返回原字符串
- b.若是用來補全的字符串與原字符串,二者的長度之和超過了指定的最小長度,則會截去超出位數的補全字符串
- c.若是省略第二個參數,默認使用空格補全長度
- 用途:
- a.爲數值補全指定位數
'1'.padStart(10, '0')
- b.日期字符串格式化
'12'.padStart(10, 'YYYY-MM-DD')
- 模板字符串
- a.模板字符串是加強版的字符串,用反引號()標識
- b.能夠看成普通字符串使用,也能夠用來定義多行字符串,或者在字符串中嵌入變量
- c.空格,縮進和換行的狀態都會被保持,除非使用.trim()去除
- d.模板字符串中嵌入變量,須要將變量名寫在${}之中,{}至關於js執行域,能夠放置變量,表達式和函數(可調用)等
- e.若是大括號中的值不是字符串,將按照通常的規則轉爲字符串;若是內部是一個字符串,將原樣輸出
- 標籤模版
- a.模版字符串前跟函數名,該函數將會被調用來處理該模版字符串,這被稱爲"標籤模版"功能
- b.函數處理模版字符串的時候,會將沒有變量${}的部分拼合成數組參數,變量${}部分的結果做爲後續參數
- c.函數處理模版字符串時,參數形式被轉換爲(數組,參數1,參數2..),其中的數組項有一個raw屬性,與參數數組的項幾乎相同,惟一的區別是字符串裏面的斜槓都被轉義了
- String.raw模版字符串
- a.用於處理模版字符串,返回一個斜槓都被轉義的字符串(若是原字符串斜槓已經轉義,String.raw不會作任何處理)
- b.也能夠做爲正常的函數使用,第一個參數應該是一個具備raw屬性的對象,且raw屬性的值應該是一個數組
- 模版字符串的限制
- a.默認會將字符串轉義,所以致使了沒法嵌入其餘語言
- b.解決提案——遇到不合法的字符串轉義,就返回undefined,而不是報錯,而且從raw屬性上面能夠獲得原始字符串
正則的擴展
數值的擴展
二進制和八進制表示法
- 二進制——0b(或0B)
- 八進制——0o(或0O)
新增api
- Number.isInteger()——是否爲整數
- Number.EPSILON——極小常量,能夠接受的偏差範圍
- Number.MAX_SAFE_INTEGER
- Number.MIN_SAFE_INTEGER——安全整數
- Number.isSafeInteger()——整數是否落在安全範圍(超出精度的結果會被自動設爲界點值,因此驗證運算結果是否落在安全整數的範圍內,不要只驗證運算結果,而要同時驗證參與運算的每一個值)
function trusty (left, right, result) { if (Number.isSafeInteger(left) && Number.isSafeInteger(right) && Number.isSafeInteger(result)) { return result; } throw new RangeError('Operation cannot be trusted!'); }
Math對象的拓展
- Math.trunc()——去除一個數的小數部分
- Math.sign()——判斷一個數是正數,負數,仍是零
- Math.cbrt()——計算一個數的立方根
- Math.clz32()——一個數的32位無符號整數形式有多少個前導0
- Math.imul()——返回兩個數以32位帶符號整數形式相乘的結果(解決相乘數超過js精度的問題)
- Math.fround()——返回一個數的單精度浮點數形式(主要用於那些沒法用64個二進制位精確表示的小數)
- Math.hypot()——返回全部參數的平方和的平方根
指數運算符
函數的擴展
函數參數的默認值
- 參數變量是默認聲明的,不能用let或const再次聲明(可用var,二者獨立)
- 使用參數默認值時,不能有同名參數
- 參數默認值是惰性求值的——若是參數默認值是變量,那麼參數實際值只有運行時才能肯定
- 參數默認值可爲解構賦值形式
function({a}={}){}
函數的length屬性
- 函數的length屬性,不包括rest參數和參數默認值
函數默認值做用域
- 一旦設置了參數默認值,函數進行聲明初始化時,參數會造成一個單獨的做用域
- 參數默認值造成的做用域與函數體內部的做用域不屬於同一個做用域,後者優先級大於前者
rest參數
- 獲取函數的多餘參數,在參數中展示爲數組
- rest只能做爲最後一個,它以後不能再有其餘參數
擴展運算符
- 將一個數組轉爲用逗號分隔的參數序列——可用於僞數組(arguments,nodelist)
- 若是將擴展運算符用於數組的解構賦值,只能放在參數的最後一位,不然會報錯
- 任何實現了Iterator接口的對象,均可以用擴展運算符轉爲真正的數組——### ...僞數組
- 擴展運算符在處理字符串(Iterator接口)時,除能將其轉換爲數組還能識別32位的Unicode字符
嚴格模式
- 函數參數使用了默認值、解構賦值、或者擴展運算符,那麼函數內部就不能顯式設定爲嚴格模式,不然會報錯
- 解決辦法——在函數體外設置嚴格模式
name屬性
- 函數表達式下,es5的name取值爲空字符串,es6爲變量名
- Function構造函數返回的函數實例,name屬性的值爲anonymous
- bind返回的函數,name屬性值會加上bound前綴+函數名
- 用一個Symbol值的變量去定義方法,name屬性返回Symbol值的描述
箭頭函數
- 函數體內的this對象,就是定義生效時所在的對象,而不是使用時所在的對象
- 不能夠看成構造函數的new命令,由於箭頭函數內部沒有this,只能獲取到外層this
- 不可使用arguments對象,該對象在函數體內不存在,可用rest參數代替
- 不可使用yield命令,所以箭頭函數不能用做Generator函數
- super、new.target在箭頭函數中一樣不存在,由於不存在內部this,因此用call()、apply()、bind()去改變函數this指向的操做無效
綁定this
- call、apply、bind的替代品——對象::函數,返回原對象
- 該運算符會自動將左邊的對象,做爲上下文環境(即this對象),綁定到右邊的函數上面
尾調用優化
- 當尾調用函數內部不依賴於外層變量做用域的時候,函數執行時調用幀就只有一項,這將大大節省內存
- ES6的尾調用優化只在嚴格模式下開啓,正常模式是無效的
尾遞歸優化
- 對於尾遞歸來講,因爲只存在一個調用幀,因此永遠不會發生「棧溢出」錯誤
- 尾遞歸的單次調用幀下降了算法複雜度,減輕了運算壓力
- 尾遞歸應該是單項的,對於多項尾遞歸同時進行一樣會增長調用幀,形成「棧溢出」
- 解決尾遞歸調用棧太多的辦法是採用"循環"換掉"遞歸",在循環中每一步返回另外一個函數並執行
函數參數的尾逗號
- 函數參數定義和調用時的參數書寫均可以在參數尾部添加多於的逗號
數組的擴展
靜態方法
- Array.from——用於將相似數組的對象和可遍歷的對象(帶iterable句柄)轉換爲真正的數組
- a.接受3個參數——Array.from(對象,過濾函數,上下文)
- b.任何有length屬性的對象,均可以經過Array.from方法轉爲數組,擴展運算符沒法轉作到
- c.能正確處理各類Unicode字符,能夠避免JavaScript將大於\uFFFF的Unicode字符,算做兩個字符的bug
- Array.of——用於將一組值,轉換爲數組
- a.彌補用數組構造函數生成數組的差別性
- b.Array(3) ### '','',''與Array(3, 11, 8) ### 3, 11, 8
實例方法
- copyWithin()
在當前數組內部,將指定位置的成員複製到其餘位置(覆蓋該位置),返回當前數組(開始替換的位置,開始複製的位置,結束複製的位置)
- fill()
填充和替換(值,起始位置,結束爲止)
- includes(值,位置)
是否包含給定值(不像indexOf方法同樣採用全等於進行比較)
- find(條件函數)
查找符合條件的值並返回
- findIndex(條件函數)
查找符合條件的值並返回位置
- entries()
鍵值對遍歷器(iterator)
- keys()
鍵名遍歷器(iterator)
- values()
鍵值遍歷器(iterator)
數組的空位
- Array(2)——['','']
- es6的數組遍歷方法都會跳過空位,map也會跳過,可是會保留空位
- join()和toString()會將空位視爲undefined,而undefined和null會被處理成空字符串
- es6新增方法會默認將空位轉換爲undefined,for...of循環則會遍歷空位
對象的拓展
屬性的簡潔表示法
- 容許在對象中直接寫入變量,變量名做爲鍵,變量值做爲值
- 容許對象定義中的方法簡寫(省卻:和function)
屬性名錶達式
- 容許在對象字面量定義中,[表達式]做爲鍵的寫法
- 若是屬性名錶達式的鍵是一個對象變量,那它會自動轉換爲"[object Object]"名
新增api
- Object.is(值1,值2)
是否嚴格相等
- Object.assign(target,source1,source2..)
對象淺拷貝
- a.若是target傳遞undefind和null會報錯
- b.除引用類型外,source只接受字符串,其他忽略
- c.屬性名爲Symbol值的屬性也會被Object.assign拷貝
- d.對於嵌套形式的對象形式,source會覆蓋整個鍵名對應的對象
- f.處理數組時會把數組視爲對象,經過對應數組下標進行屬性拷貝和覆蓋
- e.沒法正確拷貝get屬性和set屬性(undefined)
- Object.setPrototypeOf(obj,prototype)
爲對象設置原型
- Object.getPrototypeOf(obj)
返回對象的原型
- Object.getOwnPropertySymbols()
返回Symbol屬性鍵數組
- Object.keys()
返回鍵數組(可枚舉)
- Object.values()
返回值數組(可枚舉)
- Object.entries()
返回鍵值對數組
- Object.getOwnPropertyDescriptors()
返回指定對象全部自身屬性的描述對象
對象的擴展運算符
- 在解構賦值下,"...obj"等於剩餘對象集
- 在解構賦值下,"...obj"必須處於最後一位
- 在對象使用中,"...obj"將對象拆散成單個鍵值對放入{}(可用於淺拷貝和對象合併)
- 在對象使用中,若是出現同名鍵值對,後面會覆蓋前面的(適用於對象的擴展運算符)
- 在對象使用中,若是擴展運算符表明的對象鍵值對中有get取值函數,這個函數會執行
Null傳導運算符·提案
- 經過符號"?."簡化邏輯與,簡化對象判斷
const firstName = (message&&message.body&&message.body.user&&message.body.user.firstName) || 'default'
const firstName = message?.body?.user?.firstName || 'default'
Symbol
使用注意
- 一種新的原始數據類型,表示獨一無二的值
- 能夠接受一個字符串參數,用於Symbol值的描述區分
Symbol("xjh")
- 不能用new操做符,也不能參與運算,相似於字符串
- 對象操做必須用中括號表示,用點運算符賦值無效——用Symbol值直接定義或賦值會轉換爲字符串鍵
- 若是Symbol()的參數是一個對象,就會調用該對象的toString方法將其轉爲字符串,而後才生成一個Symbol值
- Symbol值能夠強制類型轉換爲字符串,布爾值,數組和對象,可是不能轉換爲數
相關api
- Symbol.for("name")
- a.若是存在登記爲name的symbol值就取到,不然就建立
- b.若是存在登記爲name的symbol值,重複的調用只會獲得同一個symbol值
- c.Symbol.for建立的symbol值是全局的,iframe生成的能夠在主頁獲取到
- Symbol.keyFor("name")
- a.返回已登記的Symbol類型值的key
- b.Symbol("name")建立的不屬於登記返回,沒法返回key
內置Symbol
- Symbol.hasInstance
- a.等同於instancsof,判斷是否爲該對象的實例時,會調用這個方法
- b.foo instanceof Foo在語言內部,實際調用的是Foo[Symbol.hasInstance(foo)]
- Symbol.isConcatSpreadable
- a.等於一個布爾值,表示該對象使用Array.prototype.concat()時,是否能夠展開
- b.數組的默認行爲是能夠展開的,Symbol.isConcatSpreadable屬性等於true或undefined,都有這個效果
- c.相似數組的對象也能夠展開,但它的Symbol.isConcatSpreadable屬性默認爲false,必須手動打開
- Symbol.species
- a.指向當前對象的構造函數,創造實例時,默認會調用這個方法
- b.定義Symbol.species屬性要採用get讀取器,默認讀取this
- Symbol.match
- a.返回一個執行正則的match函數
- b.當執行str.match(obj)時,若是obj中存在該屬性,則在會調用它
- Symbol.replace
- a.返回一個執行替換的replace函數
- b.當執行str.replace(obj,"World")時,若是obj中存在該屬性,則在會調用它
- Symbol.search
- a.返回一個執行查找的search函數
- b.當執行str.search(obj)時,若是obj中存在該屬性,則在會調用它
- Symbol.split
- a.返回一個執行查找的search函數
- b.當執行str.split(obj)時,若是obj中存在該屬性,則在會調用它
- Symbol.iterator
- a.指向當前對象默認的遍歷器方法
- b.對象進行for...of循環時,會調用Symbol.iterator方法
- Symbol.toPrimitive
- a.返回將對象轉爲原始類型值的方法
- b.Symbol.toPrimitive被調用時,會接受一個字符串參數,表示當前運算的模式
- Number:該場合須要轉成數值
- tring:該場合須要轉成字符串
- Default:該場合能夠轉成數值,也能夠轉成字符串
- Symbol.toStringTag
- a.返回一個類型字符串表示的函數
- b.當執行Object.prototype.toString時,若是obj中存在該屬性,則在會調用它
- Symbol.unscopables
- a.指向一個對象,指定了使用with關鍵字時,哪些屬性會被with環境排除
- b.被它指定的屬性和方法將在with做用域中被忽略
Set和Map數據結構
Set
- 一種相似於數組的新數據結構,成員的值都是惟一的,不存在重複
- Set的構造函數接受數組(或具備iterable接口的其餘數據結構)做爲參數
- Set的值是跟內存地址綁定的,只要內存地址不同,就視爲兩個值
- Set的實例默承認遍歷,它的默認遍歷器生成函數就是values方法
- Set的遍歷順序就是插入順序,keys方法和values方法的行爲徹底一致
- 實例屬性和方法
- size 返回成員個數
- add() 添加某個值(返回Set實例)
- delete() 刪除某個值(返回布爾值)
- has() 返回布爾值
- clear() 清除全部成員(沒有返回值)
- keys() 返回鍵名遍歷器
- values() 返回鍵值遍歷器
- entries() 返回鍵值對遍歷器
- forEach() 帶回調函數的遍歷方法
WeakSet
- WeakSet結構與Set相似,也是不重複的值的集合,沒有size和length屬性
- 構造函數的參數也只能接受數組或相似數組,但其成員必須爲對象
- WeakSet中的對象都是弱引用,其指向的對象不計入垃圾回收機制
- WeakSet用於存儲DOM節點時,若是節點從文檔移除,會自動進行垃圾回收
- 實例屬性和方法
- add() 添加對象(返回實例)
- delete() 刪除某個值(返回布爾值)
- has() 返回布爾值
Map
- 一種相似於對象的新數據結構,可是鍵的範圍不限於字符串,各類類型的值均可以看成鍵
- 構造函數接受數組(或具備iterable接口的其餘數據結構)做爲參數,數組項爲表明鍵值項的數組(### "a",1)
- Map的鍵上是跟內存地址綁定的,只要內存地址不同,就視爲兩個鍵
- 實例屬性和方法
- size 返回成員個數
- set 添加鍵值對(返回Set實例)
- get 返回值(無則undefined)
- has() 返回布爾值
- delete() 刪除某個值(返回布爾值)
- clear() 清除全部成員(沒有返回值)
- keys() 返回鍵名的遍歷器
- values() 返回鍵值的遍歷器
- entries() 返回全部成員的遍歷器
- forEach() 遍歷Map的全部成員
WeakMap
- WeakMap結構與Map結構相似,也是用於生成鍵值對的集合,沒有size和length屬性
- WeakMap只接受對象做爲鍵名(null除外),不接受其餘類型的值做爲鍵名
- WeakMap的鍵名都是弱引用,鍵名所指向的對象不計入垃圾回收機制
- WeakMap用於儲存dom節點的臨時數據時,若是節點從文檔移除,會自動進行垃圾回收
- 實例屬性和方法
- get() 獲得對象
- set() 添加對象(返回實例)
- delete() 刪除某個值(返回布爾值)
- has() 返回布爾值
Proxy
概述
- Proxy用於修改某些操做的默認行爲,等同於在語言層面作出修改,屬於一種「元編程」
- new Proxy(target, handler)接收2個參數,target表明目標對象,handler表明參數對象,用於定製行爲
- 若是handler沒有設置任何攔截,那就等同於直接指向原對象
- 若是一個屬性不可配置和不可寫,則該屬性不能被代理,經過Proxy對象操做該屬性會報錯
實例方法
- get()
- set()
- apply()
- has()——對象是否具備某個屬性
- construct()——針對new命令
- deleteProperty()——delete操做
- a.方法返回false,屬性就沒法被delete刪除
- defineProperty()
- getOwnPropertyDescriptor()
- getPrototypeOf()
- a.getPrototypeOf方法的返回值必須是對象或者null,不然會報錯
- isExtensible()——是否鎖定[不可拓展屬性]
- a.該方法只能返回布爾值,不然返回值會被自動轉爲布爾值
- b.proxy(攔截函數返回值)與target的Object.isExtensible()結果必須一致,不然報錯
- ownKeys()——對象自身屬性的讀取操做
- a.主要攔截Object.keys(),Object.getOwnPropertyNames()和Object.getOwnPropertySymbols()函數
- b.ownKeys方法返回的數組成員,只能是字符串,不然會報錯
- c.攔截Object.keys時,有三類屬性會被ownKeys方法自動過濾——不存在的屬性,不可遍歷的屬性和Symbol值屬性
- d.若是目標對象是不可擴展的,ownKeys返回的數組之中必須包含原對象的全部屬性,且不能包含多餘的屬性,不然報錯
- preventExtensions()——鎖定操做
- a.該方法只能返回布爾值,不然返回值會被自動轉爲布爾值
- b.只有目標對象不可擴展時,返回值才能爲true,不然會報錯
- setPrototypeOf()——設置原型屬性
- a.該方法只能返回布爾值,不然返回值會被自動轉爲布爾值
- b.若是目標對象不可擴展,則setPrototypeOf方法不得改變目標對象的原型
靜態方法
- 在Proxy代理的狀況下,目標對象內部的this關鍵字會指向proxy實例
- 有些原生對象的內部屬性,只有經過正確的this才能拿到,因此Proxy也沒法代理這些原生對象的屬性
Reflect
概述
- 將Object對象的一些明顯屬於語言內部的方法放到Reflect對象上
- 現階段,某些方法同時在Object和Reflect對象上部署,將來的新方法將只部署在Reflect對象上
- 修改某些Object方法的返回結果,讓其變得更合理
- Object.defineProperty在沒法定義屬性時,會拋出一個錯誤,而Reflect.defineProperty則會返回false
- 讓以前是命令式的Object操做行爲變成函數行爲
"a" in obj,delet obj['a']
變成Reflect.has(obj, name),Reflect.deleteProperty(obj, name)
-
Reflect對象的方法與Proxy對象的方法一一對應,只要是Proxy對象的方法,就能在Reflect對象上找到對應的方法java
靜態方法
- get()
- set()
- a.若是Proxy對象和Reflect對象聯合使用,經過proxy對Reflect傳入context會觸發proxy的defineProperty攔截
- has()
- deleteProperty()
- a.若是刪除成功或者被刪除的屬性不存在,返回true;刪除失敗,返回false
- construct()
- a.等同於new target(...args),提供了一種不使用new,來調用構造函數的方法
- getPrototypeOf()
- a.若是參數不是對象,Object.getPrototypeOf會將這個參數轉爲對象,而後再運行,而Reflect.getPrototypeOf會報錯
- setPrototypeOf()
- a.用於設置對象的__proto__屬性,返回第一個參數對象
- b.若是第一個參數不是對象,Object.setPrototypeOf會返回這個參數,而Reflect.setPrototypeOf會報錯
- **apply()
- defineProperty()
- getOwnPropertyDescriptor()
- a.若是第一個參數不是對象,Object.getOwnPropertyDescriptor會返回undefined,而Reflect.getOwnPropertyDescriptor會拋出錯誤
- isExtensible()
- a.對象是否能夠拓展
- b.若是參數不是對象,Object.isExtensible會返回false,由於非對象原本就是不可擴展的,而Reflect.isExtensible會報錯
- preventExtensions()
- a.設置對象爲不可拓展
- b.若是參數不是對象,Object.preventExtensions在es5環境報錯,在es6環境返回傳入的參數,而Reflect.preventExtensions會報錯
- ownKeys()
- a.返回對象的全部屬性(可枚舉和不可枚舉,可讀和不可讀)
Promise對象
Promise含義
- Promise是一個能夠獲取異步操做消息的對象,它提供了統一的API,使得各類異步操做均可以用一樣的方法進行處理
- Promise有三種狀態Pending,Resolved和Rejected,只有異步操做的結果,能夠決定當前是哪種狀態
- Promise對象的狀態不受外界影響,一旦狀態改變,就不會再變,任什麼時候候獲得的都是這個結果
- Promise實例之間進行傳遞的時候,被傳遞實例會等待傳遞實例的狀態改變後才進行回調狀態操做
- 優勢:
- a.能夠將異步操做以同步操做的流程表達出來,避免了層層嵌套的回調函數
- b.統一的接口使得控制異步操做更加容易
- 缺點:
- a.沒法取消Promise,一旦新建它就會當即執行,沒法中途取消
- b.若是不設置回調函數,Promise內部拋出的錯誤不會反應到外部
- c.當處於Pending狀態時,沒法得知目前進展到哪個階段(剛剛開始仍是即將完成)
基本用法
var promise = new Promise(function(resolve, reject) { if (true){ resolve(value); } else { reject(error); } }); promise.then(function(value) {
Promise.prototype.then
- then方法會默認返回一個新Promise實例,所以能夠進行鏈式操做
- then方法主動return的值會做爲下一個then方法的參數
- then方法主動return的new Promise實例會被加入異步堆棧,只有其狀態改變纔會執行其鏈式的then回調
Promise.prototype.catch
- Promise.prototype.catch方法是.then(null,Rejected)的別名,用於指定發生錯誤時的回調函數
- 若是異步操做拋出錯誤,狀態就會變爲Rejected,就會調用catch方法指定的回調函數
- then方法指定的回調函數,若是運行中拋出錯誤,也會被catch方法捕獲
- 在Promise構造函數回調中直接調用Rejected方法會觸發catch方法
- catch方法返回的仍是一個Promise對象,所以後面還能夠接着調用then方法
- catch方法之中,還能再拋出錯誤,當還存在下一個catch的時候就會捕獲並執行
Promise.all
- 用於將多個Promise實例,包裝成一個新的Promise實例
- Promise.all方法接受一個數組做爲參數
- a.若是數組由Promise實例組成,則會等待其中的Promise都完成時纔會觸發Promise.all實例的狀態變化
- b.若是數組不禁Promise實例組成,就會直接調用Promise.resolve方法,將參數轉爲Promise實例,再進一步處理
- 只有p一、p二、p3的狀態都完成,組合p的狀態纔會完成
- 只要p一、p二、p3之中有一個被rejected,組合p的狀態就變成rejected(此時第一個被reject的實例返回值會傳遞給p的回調函數)
Promise.race
- 同上
- 只要有一個Promise參數實例完成,就會調用Promise.race實例的狀態變化,將率先完成的子Promise參數傳遞給Promise.race回調
Promise.resolve
- 將現有對象轉爲Promise對象
- a.當參數爲Promise對象時,會原封不動返回該對象
- b.當參數爲帶"then"鍵名方法的對象時,會將這個對象轉爲Promise對象,而後就當即執行該對象的then方法
- c.當參數爲非帶"then"鍵名方法的對象時,Promise.resolve方法返回一個新的Promise對象,狀態爲Resolved
- d.不帶參數時,Promise.resolve方法直接返回一個新的Promise對象,狀態爲Resolved
Promise.reject
- 返回一個新的Promise實例,狀態爲rejected,參數爲錯誤信息
- Promise.reject()方法的參數,會原封不動地做爲reject或catch的回調參數
Promise.try提案
- 對於那種多是同步多是異步的返回操做提供統一的處理方式,動態執行對應的同步/異步狀態
- database.users.get({id: userId})有可能報同步錯誤,有可能報異步錯誤
Promise.try(database.users.get({id: userId})).then(...).catch(...)
Iterator和for...of循環
Iterator的做用
- 爲各類數據結構,提供一個統一的、簡便的訪問接口(for...of)
- 使得數據結構的成員可以按某種次序排列
- 當使用for...of循環遍歷某種數據結構時,該循環會自動去尋找Iterator接口
默認Iterator接口
- 部署了Symbol.iterator屬性的數據結構,就稱爲部署了遍歷器接口
- 原生具有Iterator接口的數據結構有:Array,Map,Set,String,TypedArray和函數的arguments對象
調用場合
- 解構賦值,擴展運算符,yield*,for..of
遍歷器對象的return和throw方法
- return方法
- 調用場景——若是for...of循環提早退出(一般是由於出錯,或者有break語句或continue語句)
- 部署場景——若是一個對象在完成遍歷前,須要清理或釋放資源,就能夠部署return方法
- throw方法
- 主要是配合Generator函數使用,通常的遍歷器對象用不到這個方法
for...of循環
- 一個數據結構只要部署了Symbol.iterator屬性,就被視爲具備iterator接口,就能夠用for...of循環遍歷它的成員
- for...of循環內部調用的就是數據結構的Symbol.iterator方法
- 擁有iterator接口的數據結構——字符串,數組,類數組(arguments和DOM NodeList),Generator對象
- for...of更經常使用於數組循環,for...in更經常使用於對象循環
Generator函數的語法
基本概念
- 語法上,function關鍵字與函數名之間有一個星號*,函數體內部使用yield表達式
- Generator屬於普通函數,調用不會當即執行,而是返回一個遍歷器對象,須要調用next()才能執行yield狀態
- Generator函數就是遍歷器生成函數,所以能夠把Generator賦值給對象的Symbol.iterator屬性,從而使得該對象具備Iterator接口,能夠被for...of循環和擴展運算符轉換
yield表達式
- yield表達式若是用在一個表達式中,必須放在圓括號裏面;若是用做函數參數或放在賦值表達式右邊,能夠不加括號
- yield表達式自己沒有返回值,老是返回undefined;
- next方法能夠帶一個參數,該參數就會被看成上一個yield表達式的返回值
- 因爲next方法的參數表示上一個yield表達式的返回值,因此在第一次使用next方法時,傳遞參數是無效的
Generator.prototype.throw()
- Generator函數返回的遍歷器對象,都有一個throw方法,能夠在函數體外拋出錯誤,而後在Generator函數體內捕獲
- throw方法能夠接受一個參數,該參數會被catch語句接收,建議拋出Error對象的實例
- 一旦Generator執行過程當中拋出錯誤,且沒有被內部捕獲,就不會再執行下去了,Generator函數默認結束
Generator.prototype.return()
- 調用return方法後會終結Generator函數,返回值的value屬性就是return方法的參數,沒有即爲undefined
- 若是Generator函數內部有try...finally代碼塊,那麼return方法會推遲到finally代碼塊執行完再執行
yield* 表達式
- yield* obj,若是obj是遍歷器對象,將會遍歷該對象的yield,增長步長
- 任何數據結構只要有Iterator接口,就能夠被yield*遍歷
Generator函數的異步應用
- Generator函數將異步操做表示得很簡潔,可是流程管理卻不方便
- 解決方案
- Thunk函數
- a.js版本的Thunk函數方案是將多參數函數轉換爲單參數函數版本
- b.可引入node模塊,也能夠本身書寫,用於管理Generator函數流程
- co模塊
- a.js版本的co函數方案是對promise的包裝
async函數
- Generator函數的語法糖
- 改進特色
- a.內置執行器 ——自動執行完,無需寫thunk和co自執行方案
- b.更好的語義
- c.更廣的適用性 ——異步等待執行,同步直接執行
- d.返回promise ——可用then方法指定下一步操做
- 基本語法
- a.async函數返回一個Promise對象,可使用then方法添加回調函數
- b.async函數的return值會成爲返回的Promise對象的值,then方法的參數
- c.遇到await就會等待異步/同步操做完成,而後接着執行函數體
- d.await命令後是一個Promise對象,若是不是則會被轉成一個當即resolve的Promise對象
- 錯誤處理
- a.async函數內拋出錯誤,會致使返回的promise對象變爲reject狀態
- b.只要一個await語句後面的Promise變爲reject,那麼整個async函數都會中斷執行,錯誤信息會傳入catch方法
- c.若是異步操做失敗,卻不但願中斷後續異步操做,方法有:
- 1).使用try...catch語句,將await放入try,catch捕捉後會繼續執行後續代碼
- 2).對await後的promise對象增添catch方法進行錯誤捕捉,而後程序會繼續執行後續代碼
- 異步遍歷器(提案)
- a.異步遍歷器的最大的語法特色就是,用遍歷器的next方法,能返回一個Promise對象
- b.對象的異步遍歷器接口,部署在Symbol.asyncIterator屬性上面
- c.next方法能夠連續調用,沒必要等到上一步Promise對象resolve之後再調用;next方法會累積起來,自動按照每一步的順序運行下去
- for await...of(提案)
- a.for await...of循環的一個用途,是部署了asyncIterable操做的異步接口,能夠直接放入這個循環
- b.for...of自動調用遍歷器的next方法,獲得一個Promise對象;await用來處理這個Promise對象,一旦resolve,就把獲得的值傳入循環體
- c.for await...of循環也能夠用於同步遍歷器
- 異步Generator函數(提案)
- a.async函數與Generator函數的結合,await後面的操做會返回Promise對象
- b.普通的async函數返回的是一個Promise對象,而異步Generator函數返回的是一個異步Iterator對象,經過調用next方法來返回可操做的Promise對象
- c.yield *後面一樣能夠繼續跟異步Generator函數
Class
Class基本語法
- 類的數據類型就是函數,類自己指向構造函數
- 類內部全部定義的方法都是不可枚舉的
- 類自己和內部的屬性方法能夠採用變量來聲明和表示
- 不使用new的類調用會報錯
- 當constructor未被顯示添加,空的constructor會被默認添加
- class聲明不存在變量提高
- 採用class表達式,能夠寫出當即執行的class
- 類和模塊的內部,默認就是嚴格模式
- class的get和set函數也定義在原型上
Class的靜態方法
- 父類的靜態方法,能夠被子類繼承——子類調用父類靜態方法
- 子類也能夠經過super,在靜態方法中調用父類的靜態方法
Class的靜態屬性和實例屬性
[es6用法]
class的私有屬性
- es7提案
- a.私有屬性用#表示,也用於表示私有方法,在類的外包沒法訪問
- b.私有屬性能夠指定初始值,在構造函數執行時進行初始化
class Foo {
new.target屬性
- 返回new命令做用的那個構造函數,若是是class內部調用則返回當前class
- new.target只適用於構造函數或class內部的constructor方法
- 若是構造函數不是經過new命令調用的,則new.target會返回undefined
- 能夠用來肯定構造函數是怎麼調用的,也能夠用其作不可實例化的抽象類
Class的繼承
Class繼承
- 基本用法
- 1.存在繼承關係後,constructor內必須執行super()操做,不然會報無this的錯誤
- 2.子類實例的構建是基於對父類實例加工,super()至關於對子類進行父類.call(this)
- 3.super返回父類實例後,植入子類原型屬性和constructor,而後再接入到子類原型上
- super關鍵字
- 1.super用做函數時,必須用在constructor以內,不然會報錯
- 2.super用做對象時,在普通方法中指向父類原型對象,在靜態方法中指向父類
- 3.經過super調用父類的方法時,至關於父級原型調用該方法,可是super會綁定子類的this
- 4.經過super對某個屬性賦值時,由於super綁定了子類的this,於是會賦值到子類屬性上,可是調用時依然會在父級原型查找
- 5.super並非動態綁定的,而是在聲明時「靜態」綁定的
- 原生構造函數的繼承
- 1.es5以前原生構造函數沒法用this去綁定,致使拿不到其內部實例屬性,沒法實現真正繼承
- 2.es6經過extends繼承能夠自定義原生數據結構,實現子類的真正繼承和拓展能力
3.super傳參對Object原生類型無效,es6規定Object構造函數會忽略參數
Decorator
基本語法
- 書寫上,置於要修改的類和方法之上
- 只能用於類和類的方法,不能用於函數,由於存在函數提高
- 無論是修飾類仍是修飾方法,都支持多個修飾器
- 修飾器對行爲的改變,發生在編譯器,而不是運行時,其本質是編譯時執行函數
類的修飾
- 當用於修飾類的時候,它的第一個參數表明所要修飾的目標類
方法的修飾
- 修飾器不只能夠修飾類,還能夠修飾類的方法
- 修飾方法的時候,接受三個參數(target, name, descriptor)
- 當多個修飾器一塊兒用時,遵循先從外到內進入,而後由內向外執行
Module的語法
export命令
- export命令規定的是對外的接口,所以必須與模塊內部的變量創建一一對應關係
export { 變量名 }
- export語句輸出的接口,與其對應的值是動態綁定關係,即經過該接口,能夠取到模塊內部實時的值一必定時器動態改變值的狀況
- export命令能夠出如今模塊的任何位置,只要處於模塊頂層就能夠,若是處於塊級做用域內就會報錯一一import命令一樣如此
import命令
- import命令具備提高效果,會提高到整個模塊的頭部首先執行,由於import命令是屬於編譯階段執行
- 因爲import是靜態執行,因此不能使用表達式和變量這些只有在運行時才能獲得結果的語法結構
- import語句會執行所加載的模塊,所以能夠有以下的寫法
import 'a'; import '1';
- 屢次重複執行同一句import語句,那麼只會執行一次,而不會執行屢次
import { foo } from 'my_module'; import { bar } from 'my_module';
模塊的總體加載
import * as 模塊名 from './文件名';
export default命令
- 爲模塊指定默認輸出時,import命令能夠爲模塊指定任意名字,且不須要用{}括號包起來
- 模塊內部的聲明函數在外部是無效的,加載的時候視同爲匿名函數進行加載
- 一個模塊只能有一個默認輸出
- export default本質上就是一個叫作default的變量或方法,所以能夠用as語句進行更名
var a = 1; export default a;
——將變量a的值賦給變量default,所以export default 1
也是能夠的
- 同時輸入默認方法和其餘變量
import abc,{ each } from 'lodash'
export與import的複合寫法
若是在一個模塊之中,先輸入後輸出同一個模塊,import語句能夠與export語句寫在一塊兒node
export { foo, bar } from 'my_module';
export * from 'my_module'; ——會忽略my_module模塊的default
export { default } from 'foo';
export { foo as myFoo } from 'my_module';
export { es6 as default } from './someModule';
export { default as es6 } from './someModule';
import()提案
- 屬於運行時執行的動態加載,區別於import的靜態加載
- import()函數能夠用在任何地方,不只僅是模塊,非模塊的腳本也可使用
- import()函數與所加載的模塊沒有靜態鏈接關係,這點也是與import語句不相同
- import()相似於Node的require方法,區別主要是前者是異步加載,後者是同步加載
- import()返回一個Promise對象,並容許模塊路徑動態生成——import(f()).then(...)
Module的加載實現
遊覽器加載
- script標籤中defer和async的區別——defer是渲染完再執行,async是下載完就執行——即不能保證執行順序
- 瀏覽器加載ES6模塊也使用
<script>
標籤,但要加入type="module"屬性,效果等同於defer
- a.代碼運行在模塊做用域,頂層變量對外不可見
- b.默認採用嚴格模式,無論有無"use strict"
- c.模塊之中,import和export指令對應模塊時,.js後綴不能省略
- d.模塊頂層this爲undefined
es6模塊與commonjs模塊的差別
- commonjs模塊輸出的是一個值的拷貝,es6模塊輸出的是值的引用
- commonjs模塊是運行時加載,es6模塊是編譯時輸出接口
- commonjs頂層this指向當前模塊,es6頂層this指向undefined
- es6模塊是動態引用,不會緩存值,模塊裏面的變量綁定其所在的模塊,意味着能夠獲取模塊的動態變化
- es6輸入的模塊變量,只是一個「符號鏈接」,屬於只讀的,對它進行從新賦值會報錯
- export經過接口輸出的是同一個值,所以不一樣的腳本加載這個接口,獲得的都是一樣的實例
node加載
- node中採用兩套方案進行加載,es6模塊和commonjs採用各自的加載方案
- 若是不輸出任何接口,但但願被node認爲是es6模塊,能夠在腳本中寫"export {}"
import加載commonjs模塊
- import加載commonjs模塊,node會自動將module.exports屬性看成模塊的默認輸出,即等同於export default
- import加載commonjs模塊時,commonjs模塊的輸出緩存機制依然有效,被引入模塊內部的變化不會更新到引入模塊
- import {readfile} from 'fs'報錯
緣由——fs是commonjs格式,只有在運行時才能肯定readfile接口,而import命令要求編譯時就肯定這個接口
解決辦法——改成總體輸入
require加載es6模塊
- 採用require命令加載es6模塊時,es6模塊的全部輸出接口會成爲輸入對象的屬性
- require加載es6模塊依然存在緩存機制,被引入模塊內部的變化不會更新到引入模塊
循環加載·commonjs
- commonjs的重要特性就是加載時執行,即腳本代碼在require的時候就會執行,而後在內存生成一個對象
- commonjs模塊不管加載多少次,都只會在第一次加載時運行一次,之後再執行加載,都只會到緩存中取值,返回第一次運行結果
循環加載·es6
- es6模塊是動態引用,若是使用import從一個模塊加載變量(即import foo from 'foo'),那些變量不會被緩存,而是成爲一個指向被加載模塊的引用,意味着能夠取到值得變化