js的this和面向對象編程


    很奇怪的是很多書或資料沒有把這個事情講清楚。

    關鍵就是在於沒有一個整體的思維技術模式,問題被隔離了所以反而不容易理解。

    我們先看this,這是js的關鍵字,指示函數的上下文對象。

    這里問題就來了,比如:

            var obj = {};

            obj.name = 'test';

            obj.output = function () {

                console.log(this.name);

            };

            obj.output();

  this指定了上下文對象,當然如果沒有指定就會指定到全局變量,window,這就是問題的根源所在。所以最好的解決方案,就是使用'use strict'嚴格模式,一但出錯,比較容易定位問題。

      在不用嚴格模式下,我們看看問題出現在哪里?

      重命名變量時:

      比如上面,console.log(obj.name),不用this的話,那么在其它代碼里obj被另外變量定義,明顯要出錯。但用了this,代碼環境一變就出問題。

     比如我們把這個對象重構成構造函數:

     function Obj(name) {

....

    都要使用this關鍵字。

    但是構造函數也是個函數,稍不注意就會當成普通函數調用。不加new,變成這樣。

   Obj('test')...

    這時構造函數被錯誤運行,而它竟爭不會出錯,為什么呢?在非嚴格模式下,構造函數的this指向了全局的window,這就是JS最大的缺陷。不僅不能得到正確的運行結果,還污染了全局。在大量的JS里,誤調用一個構造函數就是災難性的結果。

    為什么面向對象的程序比如C#,Java不會有這個問題?因為它們使用class關鍵字,class在定義階段無法使用(除非明確定義的static屬性和方法)

    

    可見,JS的這個嚴重的this,不僅是全局變量的問題,還影響了整個構造函數的面向對方方式編程,所以安全的方式寫構造函數是必須的,就是不用new,也能構造。

    當然'use strict'只是治標。治本就是要讓new 和不new都得到一致的結果。

    JS的構造函數,如果直接運行,那么返回結果就是對象,this定義的對象被拋棄,很特別的一點。所以干脆就不用定義this用new,直接使用返回對象。

            function pClass() {
                this.Name = 'test';
                this.output = function () {
                    console.log(this.Name);
                }
                return new pClass();
            }

            var p1 = pClass();
            var p2 = new pClass();
            p1.output();
            p2.output();

  不用new,倒是對了,第一個問題得到解決,但如果再new就會變成嵌套調用。出錯。很明顯,出錯是因為this,所以我們在內部,直接定義對象返回,做成真正的“構造函數”

    

            function pClass() {

                return {
                    Name: 'test',
                    output: function () {
                        console.log(this.Name);
                    }
                }
            }

            var p1 = pClass();
            var p2 = new pClass();
            p1.output();
            p2.output();

  這問題又來了,直接返回對象避免了this的問題,但明顯重復,比如p1,p2使用了兩個實例的output方法,這是不可以容忍的。

     所以這就導致了JS在處理對象的創建方面無法提供有效的機制,this和new不匹配,徹底的解決方案就是ES6,引入class關鍵字,否則的話,不管怎么創建都沒有完美的解決方案,而且代碼啰嗦。

    在ES5上,次好的解決方案是:

    1.引入'use strict',防止錯誤的構造函數及this

    2.構造函數首字母大寫,其它的一律駝峰,通過命名來區分

    3.創建對象一律使用new,並使用簡單的prototype模式

    4.非new形式盡量使用module模式

    5.最關鍵的地方,JS對象就不是長項,面向對象編程也並非最佳方式,應該優先考慮組合模式,把對象和方法體分開,這從根源上解決JS的對象弱點。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM