ES6彙總(附加面試考點,冷知識點)————es6原對象方法的擴展(共3200+字)

前言

文章爲個人原創手寫,內容參考部分書籍(《深入理解ES6》)與博客(阮一峯),個人的彙總與總結。
如有不對,希望指出。

話題 鏈接
es6嚴謹性 https://juejin.im/post/5eea3020f265da02ab172265
es6簡潔性 https://juejin.im/post/5ef0116df265da02ba14e261
es6原對象方法的擴展 https://juejin.im/editor/drafts/5ef0d2626fb9a058ad35cfb8
es6新概念的引入 正在更新中

本文重點___es6原對象方法的擴展

對於剛步入ES6時代的前端們,是否日益發行很多API,從來沒見過?
我們有Object對象,但是貌似以前沒見過Object還有is()方法。
而es6的時代,我們逐步發現很多已經存在的東西,但是卻有着更好的支持,以及更好的擴展性。
本文重點描述原對象方法的擴展。(類似promise,proxy等新的知識點,會下一章節彙總,本章節只針對原es5已有的擴展。)

編碼(Unicode)的擴展

在 ES6 之前, JS 的字符串以 16 位字符編碼( UCS-2 )爲基礎。每個 16 位序列都是一個
碼元( code unit ),用於表示一個字符。字符串所有的屬性與方法(像是 length 屬性與
charAt() 方法)都是基於 16 位的碼元。

當然, 16 位曾經足以容納任何字符,然而由於Unicode引入了擴展字符集,這就不再夠用了。

這意味着
字符串內的任意單個字符都可以用一個碼元(共 16 位)或兩個碼元(共 32 位)來表示,前
者對應基本平面字符,而後者對應擴展平面字符。

看到這裏官方的解釋是否明白?
不明白的話,看一下我的個人解釋。就是es6引入了擴展字符集,新引入的編碼,如果不在原來的Unicode編碼範圍內的話,就將在擴展字符中,將由兩個元碼組成。

舉個簡單的栗子,這裏我們以"𠮷"爲例子,因爲"𠮷"就是我上述說的,擴展字符。

var text = "𠮷";
console.log(text.length); 

你會看到字符串長度爲2,是不是很神奇?我們要明白這是es6的編碼擴展。

冷知識點

  1. charCodeAt是獲取編碼字符的方法,但是在新引入的es6擴展字符中無法獲取到。
    所以引入了codePointAt。在非擴展字符中 charCodeAt = codePointAt;

  2. 引入了大括號表示法與四字節的 UTF-16 編碼是等價的。

     '\z' === 'z'  // true
     '\172' === 'z' // true
     '\x7A' === 'z' // true
     '\u007A' === 'z' // true
     '\u{7A}' === 'z' // true
    
  3. 怎麼判斷一個字符是不是es6擴展字符?我們可以利用他的編碼是否超過0xFFFF來判斷。

     function is32Bit(c) {
         return c.codePointAt(0) > 0xFFFF;
     }
    

面試考點

var text = "𠮷";
console.log(/^.$/.test(text)); // 
console.log(/^.$/u.test(text)); // 

參考答案:false true。爲什麼呢?我們都知道/^.$/ 匹配任意字符串,爲什麼不能兩個都爲true呢?

因爲當不使用 u 標誌時,該正則
表達式只匹配碼元,所以不能匹配由兩個碼元表示的這個日文字符。啓用 u 標誌後,正則表
達式就會比較字符而不是碼元,所以這個日文字符就會被匹配到。


字符串的擴展

關於字符串,es6也引入了一些擴展方法。

includes: 在給定文本存在於字符串中的任意位置時會返回 true ,否則返回false;

startsWith:在給定文本出現在字符串起始處時返回 true ,否則返回 false ;

endsWith: 在給定文本出現在字符串結尾處時返回 true ,否則返回 false 。

repeat: 它接受一個參數作爲字符串的重複次數,返回一個將初始字符串重複指定次數的新字符串。

面試考點:

爲什麼有了indexOf,es6還要引入includes?他們的區別是什麼?

參考答案:

1.indexOf返回的是數值類型,而includes返回的是布爾類型。所以,他們可以不同的場景選擇不同的方法。如果想查找某個元素在數組中的索引位置,就用indexOf。如果單純想查找某個元素在數組中是否存在,就用includes

2.數組中的indexOf不能判斷數組中是否有NaN而includes可以,案例如下:

var ary = [NaN];
console.log(ary.indexOf(NaN))//-1
console.log(ary.includes(NaN))//true

數組的擴展

該章節分爲兩部分,分別爲類數組,跟原數組擴展

類數組

已經有數組了,爲什麼還要類數組?煩不煩?

存在即合理,我們看一下類數組的發展史。

類型化數組的起源可以追溯到 WebGL,設計用於配合網頁上的 元素。而對於 WebGL 的需求來說, JS 原生的數學運算實在太慢,因爲它使用 64 位浮點數格式來存
儲數值,並在必要時將其轉換爲 32 位整數。。引入類型化數組突破了格式限制並帶來了更好的
數學運算性能,其設計概念是:單個數值可以被視爲由“位”構成的數組,並且可以對其使用與
JS 數組現有方法類似的方法。

這是首次有了類數組的概念,而ES6爲了完成前端優化,從數值數據類型以及數組緩衝區的角度出發,所以引入類數組的概念。

類型化數組並不是嚴格的數組,它們並沒有繼承 Array 對象,但它們的外觀和行爲都與數組
有許多相似點。類型化數組包含的數據類型是八種數值數據類型之一,基於數組緩衝區對象
建立,用於表示按位存儲的一個數值或一系列數值。類型化數組能夠明顯提升按位運算的性
能,因爲它不像 JS 的常規數值類型那樣需要頻繁進行格式轉換。

類數組不能改變類數組長度!
類數組不能改變類數組長度!
類數組不能改變類數組長度!

類數組還支持的函數:copyWithin(),entries(),fill(),filter(),find(),findIndex(),forEach(),indexOf(),join(),keys(),lastIndexOf(),map(),reduce(),reduceRight(),reverse(),slice(),some(),sort(),values(),

類數組不支持函數數組:concat(),pop(),push(),shift(),splice(),unshift()

面試要點:
類數組的對象有哪些?

參考答案:

NodeList 
arguments 
還有各種ArrayBuffer創建的東西

類數組怎麼轉換成數組?

參考答案:

  Array.prototype.slice.call() 
 Array.from()

原數組擴展

新增數組,引入了Array.of() 與 Array.from() 方法。

Array.of

傳統的new Array(2);第一個參數,可能爲數組長度,也可能是第一個參數值。設計上沒有問題,,但是程序中容易出現疏忽造成bug。

Array.of只能是參數值,這相對更嚴謹了一些。

Array.form

form,看到這個詞,我就想到轉換。沒錯,Array.form就是在已有的”數組“(如上述類數組)的環境下,將轉換爲真正的數組時,採用的方法。

Array.from() 方法不僅可用於類數組對象,也可用於可迭代對象,這意味着該方法可以將任

意包含 Symbol.iterator 屬性的對象轉換爲數組。

find/findIndex

在沒有引入該函數之前,數組的相關操作方法已經相對完善,但是檢索數組是件麻煩事,因爲沒有對應的原生方法可用。都需要自己手動實操。find/findIndex正是解決這類問題,法均會在回調函數第一次返回 true 時停止查找。他們兩者的區別是find找到匹配的值,而findIndex找到匹配的索引。

fill

fill() 方法能使用特定值填充數組中的一個或多個元素。當只使用一個參數的時候,該方法
會用該參數的值填充整個數組。

let numbers = [1, 2, 3, 4];
numbers.fill(1, 2);
console.log(numbers.toString()); // 1,2,1,1
numbers.fill(0, 1, 3);
console.log(numbers.toString()); // 1,0,0,1

第一個參數爲填充的值,第二個爲start,第三個爲end。

copyWithin

copyWithin() 方法與 fill() 類似,可以一次性修改數組的多個元素。不過,與 fill() 使
用單個值來填充數組不同, copyWithin() 方法允許你在數組內部複製自身元素。爲此你需要
傳遞兩個參數給 copyWithin() 方法:從什麼位置開始進行填充,以及被用來複制的數據的起
始位置索引。

let numbers = [1, 2, 3, 4];
// 從索引 2 的位置開始粘貼
// 從數組索引 0 的位置開始複製數據
// 在遇到索引 1 時停止複製
numbers.copyWithin(2, 0, 1);
console.log(numbers.toString()); // 1,2,1,4

函數的擴展

函數的擴展主要分三個部分,rest 參數(本章節提及),箭頭函數(上一篇簡介性已經聲明,本文不做介紹),還有方法參數優化(本章節重點)。

本文針對ES6的擴展作出文章,但是關於函數的擴展,我們不得不提起ES5引入的arguments。

arguments引入的對象,使我們方法的擴展性更加強烈。在沒有引入arguments對象之前,我們的參數默認值,只能通過參數判斷,來判斷用戶是否傳遞。而ES5帶來了arguments,ES6更加的人性化,直接支持給於默認值。

ES5之前:
function test(url, timeout) {
    timeout = (typeof timeout !== "undefined") ? timeout : 2000;
}


ES5:
function test(url) {
    var timeout = 2000;
    if( arguments.length >  1){
        timeout = arguments[1]
    }
}

ES6:
function test(url, timeout = 2000) {
 
}

看發展史,是否更加簡潔方便呢?

看到這裏,arguments很方便了。但是實際用起來的時候,你會發現arguments因爲沒有具體函數名,而產生歧義。看代碼時,一下子看不出所以然來。

這時候ES6引入了”剩餘參數“,也稱呼rest。

function test(url, timeout_0 = 2000, timeout_1 = 2000, timeout_2 = 2000) {
     
}

如果此時寫成:
function test(url, ...timeout){
    
}
我們是否可以快速的獲取對象?

冷知識點

剩餘參數受到兩點限制。一是函數只能有一個剩餘參數,並且它必須被放在最後。

面試考點

考點1:arguments在嚴格跟非嚴格模式下,有什麼區別?

參考答案:

function mixArgs(first, second) {
    console.log(first === arguments[0]);
    console.log(second === arguments[1]);
    first = "c";
    second = "d";
    console.log(first === arguments[0]);
    console.log(second === arguments[1]);
}
mixArgs("a", "b");

輸出true,true,true,true

function mixArgs(first, second) {
    "use strict";
    console.log(first === arguments[0]);
    console.log(second === arguments[1]);
    first = "c";
    second = "d";
    console.log(first === arguments[0]);
    console.log(second === arguments[1]);
}

 輸出true,true,false,false
 
 看到這裏,我們不難看出,
 嚴格模式下arguments 對象不會反映出具名參數的變化,
 而非嚴格模式下反之

對象的擴展

本章節兩個重點 Object.is以及object.assign

Object.is:

 當在 JS 中要比較兩個值時,你可能會使用相等運算符( == )或嚴格相等運算符( ===
)。爲了避免在比較時發生強制類型轉換,許多開發者更傾向於使用後者。但嚴格相等運算
符也並不完全準確,例如,它認爲 +0 與 -0 相等,即使這兩者在 JS 引擎中有不同的表
示;另外 NaN === NaN 會返回 false ,因此有必要使用 isNaN() 函數來正確檢測 NaN 。

Object.assign:

淺複製,當屬性值爲對象時,僅複製其引用。併合併爲同一個對象。

面試考點

什麼爲深拷貝,什麼爲淺拷貝?分別有哪一些呢?

參考答案:

深拷貝,是指完整的新建一個對象。淺拷貝,只是把對象,或者對象首層的屬性,指向複製對象中。

所以,深拷貝的對象,值無論怎麼變,都隻影響隻身。而淺拷貝,還會影響以前拷貝的對象。

我們日常見到的拷貝方法,基本都爲淺拷貝,比如Object.assign,concat,slice 等。
最簡單的深拷貝方法,SON.parse(JSON.stringify(object))。
但是他有弊端,例如:會忽略 undefined,會忽略symbol,
不能序列化函數,不能解決循環引用的對象

當然簡單的深拷貝,我們可以直接寫一份。
(鏈接:https://github.com/zhuangweizhan/codeShare)。
但是也會有上述的問題。

如果要完成真正意義上的深拷貝,建議loash庫。

Object.is跟===有什麼區別呢?

參考答案:

 Object.is() 方法對任何值都會執行嚴格相等比較,
 當在處理特殊的 JS 值時,它有效成爲了 === 的一個更安全的替代品。
首先他可以準確判斷出NaN。
+0不等於-0。

嚴格模式下,與非嚴格模式下,對象重命名有會出現什麼情況呢?

參考答案:

非嚴格模式,值會覆蓋。嚴格模式,程序會報錯。

es6嚴謹性 : https://juejin.im/post/5eea3020f265da02ab172265

es6簡潔性 : https://juejin.im/post/5ef0116df265da02ba14e261

es6原對象方法的擴展: https://juejin.im/post/5ef0116df265da02ba14e261

es6新概念的引入: 正在更新中

友情提示

該文章已結束,下一篇文章,將談一下es6新概念的引入,包括Set與Map的引入,promise,poxy,迭代器生成器等知識點。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章