iT邦幫忙

4

用Javascript征服演算法 (2-Gray Code-Javascript番外篇)

  • 分享至 

  • xImage
  •  

今天來稍微講解javascript的物件參考使用上的一些心得,主要是針對Gray Code在進行修改時的過程紀錄,希望可以對大家有一些幫助~
用Javascript征服演算法 (2-Gray Code-Javascript<番外篇>)

此篇的產生,主要是因為在“用Javascript征服演算法 (2-Gray Code-Javascript實作)“小賴大大有回應我可以改進實作code,而後我確實也將程式碼做了修正,在這過程中有一些心得想與大家分享,也是希望能夠記錄下來:)

在“用Javascript征服演算法 (2-Gray Code-Javascript實作)“中,主要是針對產生bit數變化時的function的部分,能夠有更佳有效率的方式,以下是當初的function寫法

Gray.prototype.next = function() {  
    //奇數列i就表示為最後一位元(length - 1)  
    //偶數列就是最右往左邊數為1得數字的左邊那個(所以減1位數)  
    //-1則是在Gray code最後一組只有最左邊的數字為1其餘為0的狀況下,lastIndexOf(1)才會為0  
    var i = (this.isOdd ? this.code.length : this.code.lastIndexOf(1)) - 1;  
    console.log(this.code.lastIndexOf(1));  

    return new Gray(i === -1 ? [] :   
               this.code.slice(0, i)  
                        .concat([1 - this.code[i]])  
                        .concat(this.code.slice(  
                            i + 1, this.code.length)),   
           !this.isOdd);  
};  

而小賴是回應我,能夠將return中的新array產生方是稍作修改,就可以少做兩次concat的動作,而小賴大大提供的修改方式如下(順便特別圈出要修改的地方)

修改前

this.code.slice(0, i)  
    .concat([1 - this.code[i]])  
    .concat(this.code.slice(i + 1, this.code.length))

修改後

var newcode = this.code.slice(0);
newcode[i] = 1-newcode[i];

但我這個人就是皮在癢,很想精簡程式 (雖然也被糾正發現其實沒差XD),就改成了以下程式碼

this.code = this.code.slice(0);

this.code[i] = 1 - this.code[i];

為什麼我想用this.code? 而不想去產生一個var newcode? 而且直接使用this.code會造成什麼問題?

  1. 因為之前本身在寫其他語言時,就很習慣類似i = i+1這種寫法,就想避免使用新變數
    但其實,在這邊

    this.code = this.code.slice(0);

    var newcode = this.code.slice(0);

this.code跟直接宣告newcode的都是對原本this.code做所謂的 "深層複製"

何謂深層複製? 何謂淺層?

在這邊深層複製其實指的就是,產生並使用一塊新的記憶體並複製this.code在heap中參考所指向的那塊記憶體 (也就是真正的資料所在處)

而Slice這個函式就是提供對array作出深層複製(如下圖),所以其實都是做同樣的事情,只是多宣告一個var newcode但其實並沒有比較節省記憶體或多大差別QQ

此外使用this.code還會造成初始化的this.code陣列[0,0,0,0]被修改的問題
從上圖可以看見有一個紅色框框,那個其實是一開始this.code的參考記憶體位置,但因為我們做了this.code = this.code.slice(0),所以this.code指到另外一個記憶體位置了,而接下來我們又馬上將[0,0,0,0] 修改成 [0,0,0,1] 因此原本的[0,0,0,0]就徹底被蓋過去了orz

接下來,來講解淺層複製吧~

何謂淺層複製?
淺層層複製是僅複製了參考,也就是只將物件本身的參考位置複製到新的變數,也就是他們都指向同一塊記憶體,如下圖

如果我們當初沒有做slice這動作,而是做

var newcode = this.code;
//or省略this.code = this.cdoe.slice(0);

就會完美呈現上圖的囧境,因為沒有產生新的記憶體去複製參考,因此接下來怎麼修改bit(0->1 or 1->0)的過程都會被重複修改到上一次修改的值,因此最後alert出來的結果都會是最後一個結果[1,0,0,0] orz

以上就是整體修改得debug過程,使用javascript時要非常注意物件的行別,因為他會做自動轉換,如果沒有小心注意物件所傳遞的是參考or值,就很可能會發生上述悲劇QQ
希望本篇心得文,有幫助到各位對於記憶體的小小觀念,在此下台一鞠躬~


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
azole
iT邦新手 5 級 ‧ 2013-10-01 10:44:40

可以進一步思考一個問題,如果陣列裡頭存的是物件呢? 那用slice會怎麼樣呢? 要真的做到連裡頭存的object都複製的深深層複製,要怎麼做呢?

我要留言

立即登入留言