JavaScript- 解決多次實體化物件會造成物件無法正常使用

因為JavaScript的物件導向與一般大家所認識的物件導向有所不同

因此上一篇文章當中我們有提到,在js的OOP當中,如果一開始在建構元的時候就先將物件內的this儲存起來

那麼之後就可以針對這個物件的this來去做進一步的使用

但是如果今天我這個物件需要進行多次的實體化,這時候就會發現你先前的物件會無法正常的使用

怎麼說呢?讓我們看看以下的範例就可以了解!

在我們JavaScript的物件導向中我們需要使用變數來將目前的this儲存起來

目的在於運用這樣的方式:

可以確保自己存取的是目前物件內的變數(因為以目前這樣的寫法如果用了整排的this會比較難看懂

因此這時候你的Code大概會長這個樣子:

    var js; //先準備好變數要將物件JavaScript儲存起來
    function JavaScript()
    {  
        js = this; //儲存當前狀態
        js.num = 100;
		   
    }

    JavaScript.prototype.count = function ()
    {
        js.num += 100;
       
    }

    var js1 = new JavaScript();
    js1.count();
    console.log(js1.num); //200

但是這樣就會出現一個缺點:

「假設今天你的這個物件,他是一個元件,需要被重複的使用,那麼當在new第二個物件時就會發現先前的物件完全起不了作用。」

什麼意思呢?

我們用下面的範例Code來為大家做個解說。

 var js;
    function JavaScript()
    { 
       
        js.num = 100;
		   
    }

    JavaScript.prototype.count = function ()
    {
        js.num += 100;
       
    }

    var js1 = new JavaScript(); //建立JavaScript的物件js1
    
    var js2 = new JavaScript(); //建立JavaScript的物件js2
    js1.count(); //將物件js1的值+100

    console.log(js1.num); // 100
    console.log(js2.num); // 200

這時候各位有沒有發現到一個問題? 

當我建立了第二個物件的時候,由於我的js是全域變數,因此我的this永遠都會是最新的物件狀態

也就是儘管我不論怎麼去針對第一個物件去呼叫函數進行更改,都會更改到第二個物件。

而這個問題,可能大家會覺得,那我就在第二個物件生成前先去針對第一個物件進行操作就好拉!

但是,假設如果今天我的這個物件,是一個行道樹的物件

我每new一個物件,就是產生出一棵樹出來,那麼當我把樹都new完之後

卻發現我只能針對最後一顆樹進行操作,這樣的邏輯挺不合理的,對吧?

因此從這個地方我們了解到,我們不僅要將程式給物件化,還需要讓程式能夠具備重複使用的功能才行

因此,我們將Code重新進行改寫,將JavaScript改為封閉式寫法

如下所示:

 var JavaScript = (function () { //建立一個名為JavaScript的類別

        function JavaScript() { //建構元初始化num變數
           
            this.num = 100; 
        }
        JavaScript.prototype.Count = function () { //新增函數Count,並執行累加一百的方法
            
            this.num += 100;
        };
        return JavaScript;  //返回當前的JavaScript類別
    }());// () 代表立即執行

    var js = new JavaScript();
    var js1 = new JavaScript();
    js.Count();
    console.log(js.num);  // 100
    console.log(js1.num); // 200

從上方的範例程式碼中我們可以發現到改動的地方在於整個JavaScript

我們將JavaScript進行了封閉化,可以看到程式碼當中最後我們 return JavaScript

並且在最後面多加了()

而為什麼要這樣做呢?

因為這樣的寫法,變成是有點類似其他語言物件導向的概念

JavaScript這個類別要先實體化,就像使用JQuery一樣
讀進來的時候會需要先建立這個物件,你才能使用裡面的東西

就好像是我們封裝完之後,需要實體化他才能做使用
()就是執行你的JavaScript,並得到return JavaScript這個物件
這樣你在外面才能使用new JavaScript.JavaScript

而這樣的寫法還有一個好處,因為類似於我們往常所使用的類別,因此在裡面即使使用this來去對物件進行存取

也比較不容易迷失方向,因為只要在裡面,this代表的就是當前的這個物件。

 

另外,如果這樣的寫法你沒辦法接受,或是覺得這樣的方式很難看懂,筆者建議你可以學習TypeScript

TypeScript是由一位國外專門寫C#的人開發出來的,最後被M$收購走了

如果用TypeScript來呈現剛剛的Code 大概會長這個樣子:

class JavaScript {  //類別
    num: number;
    constructor() { //建構子
        this.num = 100
    }
    Count() {
        this.num += 100;
    }
}

var js =  new JavaScript();
var js1 = new JavaScript();
js.Count();
console.log(js.num);
console.log(js1.num);

有沒有瞬間覺得格外親切許多呀?

如果不喜歡js,那麼也許你可以考慮ts,都是不錯的選擇唷!

 

以上文章敘述如有錯誤及觀念不正確,請不吝嗇指教:)

有任何家教、案子 或技術相關問題 請都歡迎聯繫我

http://www.zhenghui.idv.tw/