簡體   English   中英

帶有 object 的 Array.prototype.fill() 傳遞引用而不是新實例

[英]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 嗎? 或者我應該把它轉換成一個循環?

您可以先用任何值(例如undefinedfill數組,然后您就可以使用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.from30 倍!!!慢) - 盡管語法最好,但性能顯然更差:(

     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 是,如果您想避免鏈接多個函數,例如fillmap 並且想避免編寫循環,那么您可以使用:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM