Javascript模擬繼承(贈送.net吐槽一段)


首先吐槽一句,今年的就業形勢很不樂觀啊,特別是搞.net的(相對java),特特別是還沒出校門沒有正式工作經驗的,找個實習很難,前些天接了個面試電話,上來就質疑我“你一個在校大學生怎么可能做了那么多項目呢,你的簡歷是真實的嗎?這些項目你做的是核心工作嗎?”,語氣中充滿了質疑,我只能生硬的回答着“嗯啊”,這個時候去解釋或許太蒼白了,我深知年輕人很難受到別人信任。當然了冷靜下來想想,現在這個社會留給年輕人的機會本來就不多,就算你在大學里學了不少東西,做了不少東西,相對於前輩來講還是有大差距的,經歷點挫折是應該的嘛,不怨天不尤人,繼續堅持下去吧。

蛋疼的日子總要做點事的,最近想把自己寫的一些js常用功能封裝成自己的一個庫,於是乎學習了一下jquery框架的整體架構,收獲頗多,接着又看了看百度編輯器的核心js庫,發現其中一段javascript模擬繼承的代碼,用的地方還挺多,閑得無聊分析一下吧。

引起我注意的來自百度編輯器js庫中的一段注釋

  /**
     * 模擬繼承機制,subClass繼承superClass
     * @name inherits
     * @grammar UE.utils.inherits(subClass,superClass) => subClass
     * @example
     * function SuperClass(){
     *     this.name = "小李";
     * }
     * SuperClass.prototype = {
     *     hello:function(str){
     *         console.log(this.name + str);
     *     }
     * }
     * function SubClass(){
     *     this.name = "小張";
     * }
     * UE.utils.inherits(SubClass,SuperClass);
     * var sub = new SubClass();
     * sub.hello("早上好!"); ==> "小張早上好!"
     */

要說大廠就是大廠,注釋寫的非常規范,可以讓新人很快參與到項目中來。(順便吐槽一句,.net開發者想進百度很難啊,內部有些辦公系統也不招聘實習生,想進電商實現也很難啊,因為基本上沒有.net平台了...)。

建議先看一下prototype的用法(參考http://blog.sina.com.cn/s/blog_7045cb9e0100rtoh.html

首先我們來看一個列子

//定義一個父類
function SuperClass() { this.name = "小李"; this.age = "15"; } //父類通過prototype給自己增加了一個hello方法 SuperClass.prototype = { hello: function (str) { console.log("hello:"+this.name + str); } }
//父類通過prototype給自己增加了一個sex屬性 SuperClass.prototype.sex
= "男";
//父類通過prototype給自己增加了一個指向一個對象(數組對象)的屬性arr,這里強調一下,這里指向的是一個對象,待會測試有用。 SuperClass.prototype.arr
= new Array("a", "b");
//定義一個子類
function SubClass() { this.name = "小張"; this.address = "北京"; }
//將父類的方法屬性克隆過來
SubClass.prototype = new SuperClass();
//創建一個子類對象
var son = new SubClass();
//這樣我們的son遍具有了hello方法
son.hello("你好");
//我們生成另一個子類實例,改變name和arr
var son2 = new SubClass();
son2.name="小紅"; son2.arr.push(
"cc"); console.log(son.name);//值未變
console.log(son.arr);//輸出a,b,cc也就是說父類中的屬性如果指向的是對象,則子類的實例將會共享這個對象。

上面的列子中 SubClass.prototype = new SuperClass();   這句起到了關鍵的作用,它把父類的方法屬性克隆給了子類。但是會帶來一個問題,那就是假如子類的定義中使用了js框架中流行的構造函數/原型方式,如下:

   function SubClass() {
            this.name = "小張";
            this.address = "北京";
        }
  SubClass.prototype.add = function () {
            console.log("add:"+this.name);
        }

這就是傳說中的聯合創建類的方法,就是用構造函數/原型方式就可以像其他程序設計語言一樣創建對象,用構造函數定義對象的非函數屬性,用原型方式定義對象的方法。 很多js框架中都在用這種方法,這種方法效率較高,節約內存。

然而當在子類定義之后寫上 SubClass.prototype = new SuperClass();以后,會覆蓋掉自己定義的add方法,這樣子類的這句定義

 SubClass.prototype.add = function () {

            console.log("add:"+this.name);

}

就必須寫到SubClass.prototype = new SuperClass(); 之后了。這樣顯然給我們使用帶來了麻煩,每次定義子類這種用法的時候還得考慮一個順序問題,實在不方便。我們看看百度編輯器的js核心庫是怎么解決的

為了分析方便,我把它的js模擬繼承的代碼抽離出來,原來一些以json方式組織的函數單獨放到一個新的html頁面里做測試。以下是我抽離出來的和模擬繼承有關的代碼:

 //定義一個父類
        function SuperClass() {
            this.name = "小李";
            this.showMsg = function () {
                alert("baseClass::showMsg");
            }
          
        }      
      
        SuperClass.prototype = {
            hello: function (str) {
                console.log(this.name + str);
            }
           
        }
        SuperClass.prototype.sex = "男";
        SuperClass.prototype.arr = new Array("a", "b"); 
        //定義子類
        function SubClass() {
            this.name = "小張";

        }
        //子類通過聯合創建方式增加了add方法
        SubClass.prototype.ddd = function () { console.log(this.name); }   
        //可以在定義完成之后,在需要繼承的時候寫上一下語句來開始繼承操作 
        inherits(SubClass, SuperClass);
        //生成一個子類實例
        var sub = new SubClass();
        sub.hello("早上好!");//父類的hello可以使用
        sub.ddd(); //子類的ddd方法可以使用了     
        sub.arr.push("cc");
        var sub1 = new SubClass();      
        console.log(sub1.arr);//sub1和sub共享了arr,需注意。

相應的extend,inherits和makeInstance方法

        //將原型s中的屬性復制給一個對象t
        function extend(t, s, b) {
            if (s) {
//                console.log(s);
                for (var k in s) {                   
//下面用到了hasOwnProperty,用來判斷一個對象是否有你給出的屬性或對象
if (!b || !t.hasOwnProperty(k)) { t[k] = s[k]; } } } return t; } function inherits(subClass, superClass) { var oldP = subClass.prototype, newP = makeInstance(superClass.prototype); //返回父類由原型方法生成實例對象,這里並沒有返回整個父類對象實例,而是根據父類原型生成了一個對象,這樣父類構造函數中的成員屏蔽掉了,子類無法繼承。 console.log(newP); extend(newP, oldP, true); //通過這一步,子類在原型中定義的屬性賦給了父類原型生成的對象 subClass.prototype = newP;//通過這一步,子類原型被重新構造,包括了自己原來的屬性和父類原型中的屬性。 return (newP.constructor = subClass); } function makeInstance(obj) { var noop = new Function(); noop.prototype = obj; obj = new noop; noop.prototype = null; return obj; }
這里要說一句,這篇文章介紹的模擬繼承方法只能將父類原型中的屬性,比如上面的hello方法可以繼承給子類,或者父類原型再添加一個性別屬性比如SuperClass.prototype.sex = "男";這里的sex同樣可以傳遞給子類,但是父類構造函數中的成員無法繼承給子類,子類必須重新定義。也就是說父類構造函數中定義的屬性可以認為是“private”的,父類原型中定義的是”public“的,所以如果父類的屬性想讓子類繼承,最好定義到原型中。這時特別要注意如果父類原型中的成員指向一個對象時,比如 SuperClass.prototype.arr = new Array("a", "b"); 所有子類的實例將會共享這個arr屬性。

總結它的這個邏輯也就一句話,把子類原型中的成員給了父親原型的一個實例對象,這個實例對象得到了擴充,然后清空子類原型,最后把這個擴充的對象中的成員克隆給子類原型。

   好了,扯淡了半天把自己都扯暈了,我是有多無聊啊。趕緊來個單位把我這妖孽收了吧。

 

 

 

 

 


免責聲明!

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



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