很奇怪的是不少書或資料沒有把這個事情講清楚。javascript
關鍵就是在於沒有一個總體的思惟技術模式,問題被隔離了因此反而不容易理解。java
咱們先看this,這是js的關鍵字,指示函數的上下文對象。編程
這裏問題就來了,好比:安全
var obj = {}; obj.name = 'test'; obj.output = function () { console.log(this.name); }; obj.output();
this指定了上下文對象,固然若是沒有指定就會指定到全局變量,window,這就是問題的根源所在。因此最好的解決方案,就是使用'use strict'嚴格模式,一但出錯,比較容易定位問題。函數
在不用嚴格模式下,咱們看看問題出如今哪裏?this
重命名變量時:prototype
好比上面,console.log(obj.name),不用this的話,那麼在其它代碼裏obj被另外變量定義,明顯要出錯。但用了this,代碼環境一變就出問題。對象
好比咱們把這個對象重構成構造函數:blog
function Obj(name) {ip
....
都要使用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的對象弱點。