【開源我寫的富文本】打造全網最勁富文本技術選型之經典OOP還是魅力硬核。

套路--先貼圖html

demo :  http://www.vvui.net/editor/index.html前端

gitee : https://gitee.com/kevin-huang/Bui-Editor-publicjava

前提jquery

下面的內容忽略ES6。ES6多了一些特性,語法糖,硬核仍是內在的經典,本文只講經典。git

 

吐槽JavaScript  的非主流特性es6

  JavaScript的非主流特色讓許多習慣了JAVA、c#等這些現代面向對象風格語言的碼農們甚是煩惱。這種怪異的特色,加上天馬行空的做用域特性,讓人有種愛不起的感受。不得不吐槽幾點:c#

  1. function 是一個雙面人: 當普通調用時候它是一個函數,當new建立對象時候它是一個構造函數。api

  2. JavaScript沒有顯式的class定義,更沒有像java、c#那樣的繼承設計。數組

  3. JavaScript的做用域很奇怪,沒有塊級做用域的實現,不能像java、c#那樣定義一個class,你要時刻記得你的操做是否會存在變量污染的問題。app

 

論JavaScript的 OOP實現

  吐槽了JavaScript非主流的特性,咱們回到OOP這個經典問題上:封裝、繼承、多態。下面就三個特性的問題論論Javascript如何經過拐彎抹角的方式實現OOP的。

  

  問題一、沒有class,JavaScript是怎麼作封裝的?

    咱們都知道java或者c#裏面,咱們一般利用class來作封裝,將一組屬性、函數封裝在一類裏面,類的成員能夠定義爲私有、公有。

    而然,JavaScript壓根沒有class這個設計,那怎麼作封裝呢?怎麼定義類成員?對於這個問題,function這個一等公民的身份特性就派上用場了。

    1)function是JavaScript裏的一等公民,它的權利比較大,在它裏面定義的變量(var 聲明),僅限fuction內使用。嘿嘿,利用這個特性,funciton能夠模擬class,知足局部做用域的要求。

    2)function不只解決了局部做用域的問題,它還能夠在new的時候,搖身一變轉爲構造函數。不要問我爲何,它天生如此。

    3)function解決了class裏面的構造函數,局部做用域問題,那成員變量怎麼定義解決呢?

    4)關於成員變量,一是能夠定義在function的prototype屬性對象上,二能夠定義在function運行時的this上下文對象上。

    5)關於私有,公有。嚴格來講,JavaScript的function封裝,無法實現私有、公有。不管是定義在prototype的成員,或者this上下文上的成員,外部都可以訪問。

    6)一般定義在prototype上的成員稱爲公有(即全部實列都共享這些成員),定義在this對象上的成員稱爲私有,這個私有表示每個實例都有一個副本,不是共享的。   

    總結:

      JavaScript利用functon這個一等公民來實現類的封裝。

 

  問題二、沒有extend,JavaScript是怎麼作繼承的?

    * 問題1中提到的「function」是JavaScript世界裏面的一等公民。權利很大。這不!Javascript的繼承還得靠這個一等公民。那這個一等公民有啥特性能夠模擬java的extend繼承呢?

    * 大凡想拿JavaScript裝裝B的人,常常會拿「原型繼承鏈」這個高深詞嚇唬嚇唬小白。看上去這玩兒好像就是JavaScript繼承的機制。通俗地說:「繼承啊,還得看function這個一等公民」。

    * 繼承看「function」,準確來講是看function的prototype(原型)。這個prototype是function隱含的一個屬性,這個屬性是一個對象,你能夠理解爲 function.prototype = {} 。

    * function裏的prototype能夠實現繼承?那要看看這個prototype裏面都有什麼了。prototype裏面有兩個很重要的屬性:constructor 、_proto_。其中_proto_是繼承的關鍵,它會指向父類的prototype。

    * 在貼出更復雜的關係圖前,先看看function、prototype、_proto_三者簡單的關係圖:

      關係解析:funciton裏面有一個prototype,prototype指向一個對象,該對象裏有兩個屬性:constructor,_prop_。constructor回指function,_prop_指向父類的prototype。

         

                * 閱讀至此,你應該明白了,繼承的關鍵是 function裏的prototype及prototype裏面的_prop_,_prop_是通向父親大人的路徑。

     * 懂得了關鍵還不行,要理解一下當你訪問對象的一個成員時候,JavaScript是怎麼找到這個成員給你的(暫時稱之爲 繼承鏈查詢機制)。

      好比你訪問了 myIns.name(myIns是new funciton產生的實例),js會這樣查詢你要訪問的成員。

      (1)js會先找this裏面是否有name屬性,有則直接返回。

      (2)this裏面沒有name,則找myIns._proto_(這個_proto_實際上指向了function.prototype)裏面是否有該屬性,有則直接返回。

      (3)function.prototype裏面也沒有找到name屬性,則找 function.prototype._proto_指向的父類裏面是否存在這個name。

    總結:

      JavaScript的繼承是利用function的prototype(原型)、prototype._proto_(原型裏面的父類指引) 實現的。

      繼承還依賴JavaScript成員訪問的鏈式查詢機制:先查本身有沒有,沒有則查原型prototype裏的,prototype裏也沒有則進一步查_proto_指向的父類。 

      繼承鏈查詢機制:我稱之爲「就近原則」!  

    最後:貼個稍稍複雜的繼承鏈圖解

                                  

 

  問題三、沒有override,JavaScript是怎麼作多態重寫?

  多態,嚴格來講,JavaScript沒有明確的多態重寫實現,可是能夠藉助JavaScript動態語言特性,繼承鏈成員查詢機制,達到模擬多態重寫的實現。

  1)重寫實現:利用JavaScript的繼承鏈查詢機制(就近原則),在this、prototype上定義同名的成員,能夠達到相似於java裏的重寫機制。

  2)重載實現:重載即同一個函數名,多種參數組合。對於這個問題能夠利用function內部arguments,在函數內部經過對argumnets數量,類型的判斷達到重載目的。

  3)JavaScript具備靈活的動態成員功能,即你能夠在運行時刪除,新增一個成員。利用這個特性,能夠實現java相似於java的反射動態成員的功能。 

 

OOP與Jquery雙劍合璧讓經典永駐

   前面說了一大堆JavaScript如何實現OOP。脫離了Dom談JavaScript就猶如紙上談兵。將OOP結合Dom一塊兒實現前端組件的開發纔是實戰,這也是Bui、Bui-editor、Bui-flow具體的OOP組件思路。

   特別地,我認爲利用JavaScript經典OOP(也能夠用es6的oop)配上jquery操做dom,是開發前端UI組件的經典大殺器,清晰的封裝,面向對象的特性,大大提升代碼的質量,組件的擴展度。

   下面以一個簡單的按鈕組件例子展現Bui、Bui-editor、Bui-flow的OOP組件思路。

   一、定義按鈕組件的容器Div

        <div id="toolbar"></div>   

   二、定義JavaScript的Button對象             

<script>
    /**定義button類的構造函數**/
    function Button(jq,opts){
        this.opts = opts;
        this.jqObj = jq;
        this.button = $("<button>按鈕</button>").appendTo(this.jqObj);
        this._bindEvents();
    }
    /**
     * 定義Button的成員
     * ***/
    Button.prototype = {
     constructor:Button,
/**定義一個點擊事件**/ click:function(){ this.button.trigger("click"); }, /**綁定button的事件**/ _bindEvents:function(){ var _this = this; this.button.on({ click:function(){ if(_this.opts.onClick){ _this.opts.onClick.call(this); } alert("click"); } }); } }; </script>

 

  三、使用組件    

    /**
     * 建立一個Button實例
     * **/
    var btn = new Button($("#toolbar"),{
        onClick:function(){
            alert("按鈕被觸發");
        }
    });
    /**調用實例api**/
    btn.click();

 

 

最後:

貼一個我正在開發的流程設計器,你能夠關注的我 gitee  https://gitee.com/kevin-huang

相關文章
相關標籤/搜索