W3Cschool
恭喜您成為首批注冊用戶
獲得88經驗值獎勵
為什么會用這樣一個題目呢,這是要說封裝的什么問題,本文并不講高深的封裝理論,只是解決一個小問題。
今天在百度知道上閑逛,遇到一個網友的問題,問題如下,問題的地址見這里:
下面先不看看其他網友給的答案:
網友大部分回答不能一起定義,那么我們來分析下為什么這樣做是錯的,然后給出相應的解決辦法。
先來說說為什么調用出錯,我在自己的瀏覽器里重現(xiàn)了問題,處于實驗并未全部復原代碼,并且用到了全局變量哦:
function Dialog(){
Dialog.prototype = {
init:function(){
console.log("ok");
}
}
}
var a = new Dialog();
a.init();
下面是火狐提示的錯誤:
init不是一個方法,這是為什么呢,我們將調用代碼修改下,出于演示,并未遵循JsLint代碼規(guī)范:
var a = new Dialog();
typeof a.init;
結果顯示為undefined,也就是init沒有被定義,或者說在求值過程中未找到init標識符的值,這是因為在調用函數時函數里面的內容才會被解析執(zhí)行,所以在調用new Dialog(),時其內部的代碼尚未執(zhí)行,所以設置Dialog的原型的語句尚未執(zhí)行,通過這個例子可以看出綁定this的prototype的過程是在執(zhí)行構造函數內部代碼之前,可以用下面的代碼來解釋下:
function Dialog(){
var that = Object.create(Object.getPrototypeOf(this));
Dialog.prototype = {}
}
很明顯獲取原型時尚未設置原型,但當我們再次調用new 時情況將發(fā)生改變:
var a = new Dialog();
var b = new Dialog();
typeof b.init;
在此調用時奇跡發(fā)生了,我們看到第二次調用時成功獲取了值,只有第一次時值是未獲去,那我們是不是可以改造下我們的dialog函數呢:
function Dialog(){
Dialog.prototype = {
init:function(){
console.log("ok");
}
}
}
new Dialog();
var a = new Dialog();
typeof a.init;
我們只需先調用下構造函數便解決了問題,如果你覺得上面的代碼還是有悖于封裝我們可以再做改變:
var Dialog = (function(){
function Dialog(){
Dialog.prototype = {
init:function(){
console.log("ok");
}
}
}
new Dialog();
return Dialog;
}());
上面真的解決問題了嗎,你難道沒有疑問呢,如果你已經看出問題所在在了,那你也一定能想出解決辦法,而且你應該是一個高手,那么讓我們看看這樣巧妙的解決辦法有什么問題,為此我們來構造下面的代碼:
var a = new Dialog();
typeof a instanceof Dialog;
也許你會問為什么會這樣寫,也許下面的結果更讓你吃驚:
結果為false,為什么我的a不是Dialog的實例呢,我的a明明是Dialog創(chuàng)建的,要想搞清這個問題我們先得說清楚 instanceof關鍵字的工作原理,當我們調用類似a instanceof Dialog 這樣的語句時,解釋器是怎么判斷a是Dialog創(chuàng)建的對象的呢,原來解釋器是判斷a的原型是否為Dialog的prototype屬性所指向的對象也就是說如果a的原型和Dialog的prorotype屬性指向同一個對象就認為a是Dialog的對象,當然在判斷時并不是至判斷a的的原型,而是判斷原型鏈中的每個對象,例如:
var a = [];
a instanceof Array;
a instanceof Object;
上面的兩條語句都會返回true,因為a的原型鏈中包含這兩個對象。
而上面我們的代碼為什么結果為false呢,那是因為當我們每次調用Dialog構造函數時都會在內部重寫Dialog的原型,而已經創(chuàng)建的對象的原型會指向原來的原型對象,解釋器在判斷兩個對象是否相等時,要判斷兩個對象是否引用同一塊地址,而不是兩個對象是否有相同的屬性和方法,所以上面出現(xiàn)false的原因就很清楚了,所以上面的解決辦法就出現(xiàn)問題了,而且是很大的問題。顯然這種方法行不通。
那我們有沒有辦法解決問題呢,讓我們先來看看作者想要實現(xiàn)什么,作者想要實現(xiàn)的封裝,也就是構造函數和構造函數的原型分開寫的問題,作者想把他們寫到一起,作者認為這才是封裝,那么我們先來看下封裝是什么,作者對封裝的理解是否有誤:
封裝,1、在程序上,隱藏對象的屬性和實現(xiàn)細節(jié),僅對外公開接口,控制在程序中屬性的讀和修改的訪問級別;將抽象得到的數據和行為(或功能)相結合,形成一個有機的整體,也就是將數據與操作數據的源代碼進行有機的結合,形成“類”,其中數據和函數都是類的成員。
上面是對封裝的解釋,可以看出這跟作者描述的封裝并不是一個意思,作者此處所想表達的實際上是更好的代碼結構。
既然清楚了作者的意思,來看下解決辦法,如何將構造函數的定義和原型的定義寫到一起呢,看下我給出的解決辦法:
var Dialog = (function(){
function Dialog(){
}
Dialog.prototype = {
init:function(){
console.log("ok");
}
}
return Dialog;
}());
var a = new Dialog();
a instanceof Dialog;
好了問題解決了,結果正確了,而且我們也得到了比較清晰的代碼結構。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: