iT邦幫忙

1

Javascript Array Push 問題

Han 2019-05-22 14:58:393561 瀏覽
  • 分享至 

  • xImage

不囉唆直接上程式碼

var objText = {
    type : 'text', 
    text : ''
}

var myArray = [] ;

for(var i=0; i < 5; i++)
{
    objText.text = i ;

    console.log(objText) ;

    myArray.push(objText);
}

console.log(myArray);
//首先我預想的結果應該是這樣
{ type: 'text', text: 0 }
{ type: 'text', text: 1 }
{ type: 'text', text: 2 }
{ type: 'text', text: 3 }
{ type: 'text', text: 4 }
[ { type: 'text', text: 0 },
  { type: 'text', text: 1 },
  { type: 'text', text: 2 },
  { type: 'text', text: 3 },
  { type: 'text', text: 4 } ]

//實際上是
{ type: 'text', text: 0 }
{ type: 'text', text: 1 }
{ type: 'text', text: 2 }
{ type: 'text', text: 3 }
{ type: 'text', text: 4 }
[ { type: 'text', text: 4 },
  { type: 'text', text: 4 },
  { type: 'text', text: 4 },
  { type: 'text', text: 4 },
  { type: 'text', text: 4 } ]

目前解決方法是在迴圈裡面進行宣告

for(var i=0; i < 5; i++)
{
    let objText = {
        type : 'text',
        text : ''
    }

    objText.text = i ;

    console.log(objText) ;

    myArray.push(objText);
}

但我實在不懂為何會這樣,想了解一下原理

是因為閉包問題嗎??
但我印出來的objText也有確實的每一個迴圈改變

還是因為他是同一個物件,所以我改變了之後,陣列裡所有物件也跟著改變
這樣的話我push進去的是給同一個物件,不是複製進去的意思嗎??

寫這個程式的目的是做Line的bot裡面的訊息格式都是使用json
因此蠻常需要做一個template不斷動態產生訊息,但不斷踩到這個雷
所以上來發問一下~還請各位大佬解答

看更多先前的討論...收起先前的討論...
pinglam iT邦新手 5 級 ‧ 2019-05-22 15:14:36 檢舉
我覺得這個網址可以回答到你的問題以及解決你的疑問:https://stackoverflow.com/questions/35940890/variable-value-changes-after-pushing-in-array
pinglam iT邦新手 5 級 ‧ 2019-05-22 15:19:21 檢舉
根據這個網址的回答,push 只會push其reference ,並不會push其value,所以你要每次loop開始都要開新object,而你的解決方法中的let 正是開新的object到暫存中,當然不會發生引用同一個ojbect的問題
Han iT邦研究生 1 級 ‧ 2019-05-22 15:20:28 檢舉
看來就是這樣呢!一直以為push進去就是一個新的物件!
感謝~本來也有不斷google這個問題,看來是我沒抓到問題的關鍵XD
ccutmis iT邦高手 2 級 ‧ 2019-05-22 15:34:15 檢舉
更簡單的解法提供您參考...
var myArray1 =[];
for(var i=0; i < 5; i++)
myArray1.push({type:'text',text:i});
console.log(myArray1);
小魚 iT邦大師 1 級 ‧ 2019-05-22 18:23:03 檢舉
這個其實很多程式語言都會遇到,
多遇到幾次就會了,
主要是你的觀念還不夠清楚造成的.
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 個回答

1
froce
iT邦大師 1 級 ‧ 2019-05-22 16:27:23
最佳解答

要說得精確一點:
JS跟python的變數很特別,他們兩個對於變數都有分:

  1. mutable:array(python:list)、object(python:dict)...
  2. immutable:string、integer、float...

然後這兩個語言遇到這兩類變數,在傳遞時會有不同的行為:
mutable:會用 call by reference
immutable:會用 call by value

像你這樣,在mutable(array)中推送,實際上array中記的值是推送reference,你4次都推同樣的物件,也就是你array裡面其實存的是

[objText的ref, objText的ref, objText的ref, objText的ref]

所以會是objText的最後值。

解法的話,ccutmis提供的是一個解,另外也可以用new,無分好壞,看你物件有沒有需要被重用:

function objText(text) {
  this.type = 'text'
  this.text = text
}

for(var i=0; i < 5; i++)
{
    let _obj = new objText(i)
    
    myArray.push(_obj);
}

然後這個在python被習慣稱做 call by assignment,JS則被稱為 call by sharing。

ccutmis iT邦高手 2 級 ‧ 2019-05-22 16:36:01 檢舉

/images/emoticon/emoticon12.gif

Han iT邦研究生 1 級 ‧ 2019-05-23 09:55:57 檢舉

謝謝 這個回應蠻清楚的!也修正了我一些觀念~

0
舜~
iT邦高手 1 級 ‧ 2019-05-22 15:41:39

因為每次push的都是相同的物件,所以輸出都是相同的 ...


後來發現已在討論解決了XD

ccutmis iT邦高手 2 級 ‧ 2019-05-22 15:49:15 檢舉

/images/emoticon/emoticon82.gif

我要發表回答

立即登入回答