![](/img/trans.png)
[英]JavaScript - why Array.prototype.fill actually fills a "pointer" of object when filling anything like 'new Object()'
[英]Array.prototype.fill() with object passes reference and not new instance
我有點玩弄並試圖實例化一個長度為x
的新數組,其中該數組的所有元素都被初始化為值y
:
var arr = new Array(x).fill(y);
如果y
的值不是object ,這會很有效。 這意味着如果y
是 object,則以下內容為真:
var arr = new Array(2).fill({});
arr[0] === arr[1]; //is true;
arr[0].test = 'string';
arr[1].test === 'string'; //is also true;
state 有什么方法可以在使用填充函數時為每個元素創建一個新的 object 嗎? 或者我應該把它轉換成一個循環?
您可以先用任何值(例如undefined
) fill
數組,然后您就可以使用map
:
var arr = new Array(2).fill().map(u => ({}));
var arr = new Array(2).fill().map(Object);
公認的答案很好,並且適用於 90% 的情況。
但是,如果您正在制作高性能的 JS 應用程序,並且如果您使用大/巨大的數組,則 Array.map(..)會在內存和處理器使用中產生很大的過載,因為它會創建數組的副本。
我建議使用經典的 for循環:
a = new Array(ARRAY_SIZE);
for (var i = 0; i < ARRAY_SIZE; i++) {
a[i] = [];
}
// or it's one line alternative
for (var i = 0, a = []; i < ARRAY_SIZE; a[i++] = []);
我測試了六種替代方案並得到了這個:
Array.map() ,如上所述( 11 倍!!!更慢):
a = new Array(ARRAY_SIZE).fill().map(u => { return []; });
for 循環,最好的一個(最快的):
// Standard multi-line way a = new Array(ARRAY_SIZE); for (var i = 0; i < ARRAY_SIZE; i++) { a[i] = []; } // One line syntax for (var i = 0, a = []; i < ARRAY_SIZE; a[i++] = []);
forEach (慢6 倍):
a = new Array(ARRAY_SIZE).fill(); a.forEach((val, i) => { a[i] = []; })
[更新 2020-08-27] 下面由 Ilias Karim 提出的另一種方法
Array.from ( 30 倍!!!慢) - 盡管語法最好,但性能顯然更差:(
a = Array.from({ length: ARRAY_SIZE }, () => []);
[..Array(..)] ( 5x 倍!!!慢)
a = [...Array(ARRAY_SIZE)].map(_=>([]))
Array.push(..) ,在性能方面排名第二( 2x 倍!!!更慢)
let a = [], total = ARRAY_SIZE; while(total--) a.push([]);
PS。 我用這個小提琴進行測試。
一種高效的解決方案: Array.from({ length: 5 }, () => new Object())
最短可能:
let node = [...Array(2)].map(_=>({})) console.log(node)
Ilias Karim 的回答非常出色。 我剛剛做了以下事情:
a = Array.from({length:l}, () => new Array(c).fill(prefix));
創建一個預先填充的指定大小的二維數組,l x c,用前綴填充。 現在我的代碼可以填充二維矩陣中需要非前綴值的槽。
您也可以通過以下解決方法解決此問題。
var arr = new Array(2).fill({});
arr = JSON.parse(JSON.stringify(arr));
我寫了一篇關於這個的博客文章:http: //www.samhenderson.xyz/posts/12
但是 TLDR 是,如果您想避免鏈接多個函數,例如fill
, map
。 並且想避免編寫循環,那么您可以使用:
const array = Array.from({ length: 2 },()=>({}))
對於數組數組:
const array = Array.from({ length: 2 },()=>([]))
要添加解釋別名問題以及如何解決它的答案,這里有一個方便的 function 可用於創建 arrays 並為調用者提供更清晰的語法:
const array = (length, fill) => [...Array(length)].map((_, i) => typeof fill === "function"? fill(i): fill ); // usage: const a = array(3, i => array(3, j => [i, j])); a[0][0][0] = -42; console.log(a);
請注意,對於非原始值,您仍然需要使用回調 function。 這實際上是一個功能,因為它公開了索引並允許您提供任意邏輯來填充元素。 如果您擔心不小心將非原始、非函數 object 作為填充值傳遞,則可能會引發錯誤。
如果您真的希望能夠直接傳遞 object 並將其復制到底層,這里有一個幾乎可以禁止混疊的調整:
const array = (length, fill) => [...Array(length)].map((x, i) => typeof fill === "function"? fill(i): typeof fill === "object"? _.cloneDeep(fill): fill ); // usage: const a = array(2, array(2, {foo: 3})); a[0][0].foo = 42; console.log(a);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
一般來說,我建議避免.fill()
幾乎完全支持擴展語法[...Array()]
因為它很容易忘記別名行為並最終導致令人沮喪的錯誤。
如果速度很重要,請使用傳統for
循環:
const array = (length, fill) => { const a = []; for (let i = 0; i < length; i++) { a[i] = typeof fill === "function"? fill(i): fill; } return a; }; // usage: const a = array(2, () => array(2, Object)); a[0][0].foo = 42; console.log(a);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.