摘要:從這句話我們可以知道,當我們構造一個指定長度的時,由于有長度,所以會開辟相應下標的空間,但是因為該下標并沒有元素,所以就會返回,任何原因構造數組元素失敗時,都會返回一個。
JS中的Array作者:陳大魚頭
github: KRISACHAN
ecma-262中的定義:Array()Array對象是一種特殊對象,它會對數組索引屬性鍵進行特殊處理。
每個Array對象都有一個不可配置的length屬性,其最大值是232 - 1。
當且僅當不帶參數調用Array構造函數時,此描述才適用。
執行過程:
定義 numberOfArgs 傳遞給此函數的調用的實參數量;
斷言: numberOfArgs 為 0;
如果 NewTarget 為 undefined ,就設置 newTarget 為 活動函數對象(active-function-object,正在運行的執行上下文的函數組件) ,并且讓 newTarget 成為 NewTarget ;
原型 proto 怎么辦?通過原生方法GetPrototypeFromConstructor(newTarget, "%ArrayPrototype%")來構造;
返回原生方法ArrayCreate(0, proto)。
魚頭注:NewTarget是啥?NewTarget是原生Class FunctionCallbackInfo(函數調用的callback上下文的信息)內的一個不變量,用來定義構造調用時的返回值(new.target)。
Array(len)當且僅當使用一個參數調用Array構造函數時,此描述才適用。
執行過程:
定義 numberOfArgs 為傳遞給此函數的調用的實參數量;
斷言: numberOfArgs 為1;
如果 NewTarget 為 undefined ,就設置 newTarget 為 活動函數對象 ,并且讓 newTarget 成為 NewTarget ;
原型 proto 怎么辦?通過原生方法GetPrototypeFromConstructor(newTarget, "%ArrayPrototype%")來構造;
然后定義array 為ArrayCreate(0, proto);
如果 len 的類型不是個Number,則:
定義 defineStatus 為CreateDataProperty(array, "0", len);
斷言:defineStatus為真;
讓 intLen(初始化長度) 為1。
或者:
定義intLen為ToUint32(len)(原生方法,將len轉換成0到232-1之間的整數值);
如果intLen不等于len,拋出RangeError異常。
執行Set(array, "length", intLen, true)(原生方法,給對象的屬性賦值);
返回array。
Array(...items)當且僅當使用至少兩個參數調用Array構造函數時,此描述才適用。
執行過程:
定義 numberOfArgs 為傳遞給此函數的調用的實參數量;
斷言: numberOfArgs 大于等于2;
如果 NewTarget 為 undefined ,就設置 newTarget 為 活動函數對象 ,并且讓 newTarget 成為 NewTarget ;
原型 proto 怎么辦?通過原生方法GetPrototypeFromConstructor(newTarget, "%ArrayPrototype%")來構造;
然后定義array 為ArrayCreate(numberOfArgs, proto);
定義 k 為0;
定義 items為 正序傳入參數的 零源(zero-origined) 列表;
重復,當 k 小于 numberOfArgs
定義 Pk 為 ToSting(k);
定義 itemK 為 item[k];
定義 defineStatus 為CreateDataProperty(array, Pk, itemK);
斷言:defineStatus為真;
k 加1。
斷言: array的 length 值為 numberOfArgs;
返回 array。
empty上面的三種情況以上便是構造Array()時不同情況的具體實現。但是我們從上面的斷言可以知道,構造結果有可能為真,有可能為假。還有是定義指定長度數組時會出現什么事呢?
在V8源碼 3.28.71(node0.12.18)中 Array 有個CloneElementAt的方法。定義如下:
在指定索引處克隆元素時,如果克隆失敗,則返回一個空句柄(任何原因)。
從這句話我們可以知道,當我們構造一個指定長度的 Array 時,由于有長度,所以會開辟相應下標的空間,但是因為該下標并沒有元素,所以就會返回empty,任何原因構造數組元素失敗時,都會返回一個empty。
示例如下:
var arr = new Array(10); arr // [empty × 10]以上總結
上面是 ECMA 上的定義以及 V8 源碼的容錯處理,其實簡單來說就是:
調用 Array(args) 時:
用原生方法 GetPrototypeFromConstructor 生成原型 proto ;
判斷 args 的類型;
如果為 undefined,則直接返回創建數組的原生方法 ArrayCreate;
如果為 number,則用原生方法 Set 創建 args 長度的數組,并通過原生方法 CloneElementAt 來創建 args 個 empty 作為數組元素,如果args 大于 232 - 1 的話,會報錯;
如果為其他類型,則把 args 變成數組元素,并用 原生方法 CreateDataProperty 創建參數,然后返回創建數組的原生方法 ArrayCreate。
類型轉換類型轉換是一個經常出現在一些網上常見面試題或者奇技淫巧中的內容。那么關于數組的類型轉換,又是怎樣的呢?
首先我們要知道,在 JS 中類型轉換只有三種情況,分別是:
轉換為布爾值
轉換為數字
轉換為字符串
轉換為原始類型對象在轉換類型的時候,會執行原生方法ToPrimitive。
其算法如下:
如果已經是 原始類型,則返回當前值;
如果需要轉 字符串 則先調用toSting方法,如果此時是 原始類型 則直接返回,否則再調用valueOf方法并返回結果;
如果不是 字符串,則先調用valueOf方法,如果此時是 原始類型 則直接返回,否則再調用toString方法并返回結果;
如果都沒有 原始類型 返回,則拋出 TypeError類型錯誤。
當然,我們可以通過重寫Symbol.toPrimitive來制定轉換規則,此方法在轉原始類型時調用優先級最高。
// 下面例子來自YCK的小冊 const data = { valueOf () { return 1; }, toString () { return "1"; }, [Symbol.toPrimitive]() { return 2; } }; data + 1 // 3轉換為布爾值
對象轉換為布爾值的規則如下表:
參數類型 | 結果 |
---|---|
Undefined | 返回 false。 |
Null | 返回 false。 |
Boolean | 返回 當前參數。 |
Number | 如果參數為+0、-0或NaN,則返回 false;其他情況則返回 true。 |
String | 如果參數為空字符串,則返回 false;否則返回 true。 |
Symbol | 返回 true。 |
Object | 返回 true。 |
對象轉換為數字的規則如下表:
參數類型 | 結果 |
---|---|
Undefined | 返回 NaN。 |
Null | Return +0. |
Boolean | 如果參數為 true,則返回 1;false則返回 +0。 |
Number | 返回當前參數。 |
String | 先調用 ToPrimitive,再調用 ToNumber,然后返回結果。 |
Symbol | 拋出 TypeError錯誤。 |
Object | 先調用 ToPrimitive,再調用 ToNumber,然后返回結果。 |
對象轉換為字符串的規則如下表:
參數類型 | 結果 |
---|---|
Undefined | 返回 "undefined"。 |
Null | 返回 "null"。 |
Boolean | 如果參數為 true ,則返回 "true";否則返回 "false"。 |
Number | 調用 NumberToString,然后返回結果。 |
String | 返回 當前參數。 |
Symbol | 拋出 TypeError錯誤。 |
Object | 先調用 ToPrimitive,再調用 ToString,然后返回結果。 |
所以通過上面的轉換規則,我們是否能夠輕松地看懂以下的隱式轉換呢?
[1,2,3] + {a: 1, b: 2} // "1,2,3[object Object]" [1,2,3] + 1 // "1,2,31" [1,2,3] + true // "1,2,3true" [1,2,3] + undefined // "1,2,3undefined" [1,2,3] + null // "1,2,3null" [1,2,3] + "123" // "1,2,3123" [1,2,3] + Symbol("biu") // "Uncaught TypeError"
所以各位是否理解上述隱式轉換的答案呢?
關于API使用的一些經驗與思考JS數組自帶了很多的方法,在現代工程化數據驅動的理念下,這些方法都是非常重要的。loops
forEach是 Array 方法中比較基本的一個,作用也很簡單,與for,就是遍歷,循環。不同的是,forEach可以選擇自定義上下文環境。例子如下:
var arr1 = [1, 2, 3]; var arr2 = [5, 6, 7]; arr1.forEach(function (e, i, a) { console.log(e, this); // this為arr2 }, arr2);
但是如果forEach的回調函數是用箭頭函數定義的,那么就無法改變它原本指向的上下文環境。例子如下:
var arr1 = [1, 2, 3]; var arr2 = [5, 6, 7]; arr1.forEach((e, i, a) => { console.log(e, this); // this為window對象 }, arr2);
所以如果我們要實現以下這個功能:
在ES6以前的環境中,如果直接用for循環,會出現只能獲取到最后一個元素的問題,但是用forEach則沒有這個問題。
reduceArray ES5 API reduce跟reduceRight,可以輕松實現并歸元素的功能,例子如下:
如果我們需要實現一個這樣的對象:
{ a: 1, b: 2, c: 3 ... };
那么用reduce就會變得很簡單:
var newArr = "a,b,c,d,e,f".split(",").reduce((acc, cur, idx) => { let o = {}; if (Object.prototype.toString.call(acc) !== "[object Object]") { o[cur] = idx; } else { let newO = {}; newO[cur] = idx; o = { ...acc, ...newO, }; }; return o; }, "a");性能
上面演示了通過JS數組API實現的一些功能,所以與for循環比性能如何呢?
var arr = new Array(100); arr.forEach(data => { console.log(data); }); for (var i = 0; i < arr.length; ++i) { console.log(arr[i]); };
所以哪個更耗時間呢?
在公布結果之前,其實網上一直流傳著for循環性能比forEach性能好,考慮性能少用forEach的言論,其實以前的瀏覽器也是這種情況。
詳情可以看知乎的這篇評論:https://www.zhihu.com/question/54637225/answer/140362071
性能對比如下:
以下代碼測試環境為:Chrome 55.0.2883 / Windows 7 0.0.0
所以在9012年的如今,結果又會是如何呢?
以下代碼測試環境為:Chrome 73.0.3683 / Windows 10 0.0.0
通過上面的對比,結果已經很明顯了,我們要知道,現代的瀏覽器性能優化已經做得比以前好很多了,再加上電子設備本身的硬件也越來越好,所以代碼塊的性能不是我們首要的考慮因素。
在跟同行溝通的過程中,經常會看到有人為了扣那么一個兩個表達式的性能而煩惱,其實是這是沒有任何必要,原因也如上,我們應該優化的是我們表達式是否清晰明了,是否適合后期維護或拓展。
如果你也喜歡探討技術,或者對本文,本系列有任何的意見或建議,你可以掃描下方二維碼,關注微信公眾號“ 魚頭的Web海洋 ”,隨時與魚頭互動。歡迎!衷心希望可以遇見你。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/105872.html
摘要:當且僅當使用至少兩個參數調用構造函數時,此描述才適用。斷言的值為返回。還有是定義指定長度數組時會出現什么事呢在源碼中有個的方法。轉換為數字對象轉換為數字的規則如下表參數類型結果返回。不同的是,可以選擇自定義上下文環境。 作者:陳大魚頭 github: KRISACHAN JS中的Array ecma-262中的定義: Array對象是一種特殊對象,它會對數組索引屬性鍵進行特殊處理。 ...
摘要:簡單就意味著更快的開發速度,更小的維護成本,同時往往具有更好的體驗下面我介紹哪些或許你不知道小技巧。默認為,此時陰影與元素同樣大。如果沒有指定,則由瀏覽器決定通常是的值,不過目前取透明。首先,我們要明白這里的最小寬度值是什么意思。 暑假實習的時候帶我的師傅,告訴我要注重基礎,底層實現原理。才能在日新月異的技術行業站住腳跟,以不變應萬變,萬丈高樓平地起,所以我們應該不斷的去學習,去交流。...
摘要:簡單就意味著更快的開發速度,更小的維護成本,同時往往具有更好的體驗下面我介紹哪些或許你不知道小技巧。默認為,此時陰影與元素同樣大。如果沒有指定,則由瀏覽器決定通常是的值,不過目前取透明。首先,我們要明白這里的最小寬度值是什么意思。 暑假實習的時候帶我的師傅,告訴我要注重基礎,底層實現原理。才能在日新月異的技術行業站住腳跟,以不變應萬變,萬丈高樓平地起,所以我們應該不斷的去學習,去交流。...
摘要:簡單就意味著更快的開發速度,更小的維護成本,同時往往具有更好的體驗下面我介紹哪些或許你不知道小技巧。默認為,此時陰影與元素同樣大。如果沒有指定,則由瀏覽器決定通常是的值,不過目前取透明。首先,我們要明白這里的最小寬度值是什么意思。 暑假實習的時候帶我的師傅,告訴我要注重基礎,底層實現原理。才能在日新月異的技術行業站住腳跟,以不變應萬變,萬丈高樓平地起,所以我們應該不斷的去學習,去交流。...
閱讀 3240·2023-04-25 20:35
閱讀 3605·2019-08-30 15:54
閱讀 1982·2019-08-30 15:43
閱讀 2169·2019-08-29 15:14
閱讀 1879·2019-08-29 11:17
閱讀 3372·2019-08-26 13:36
閱讀 685·2019-08-26 10:15
閱讀 2815·2019-08-23 15:41