如何開發(fā)原生的 JavaScript 插件(知識點+寫法)

一、前言

通過 "WWW" 原則我們來了解 JavaScript 插件這個東西

第一個 W "What" -- 是什么?什么是插件,我就不照搬書本上的抽象概念了,我個人簡單理解就是,能方便實現(xiàn)某個功能的擴(kuò)展工具.(下面我會通過簡單的例子來幫助讀者理解)

第二個 W "Why" -- 為什么? 為什么要有插件這種東西,首先結(jié)合第一個 W 來理解就是,使用插件的目的是方便我們實現(xiàn)某一個功能. 也就是說在編程過程中我們只需要找輪子,或者改輪子而不需要重新造輪子.節(jié)省開發(fā)時間,并且各司其職會更加專業(yè)(做得更好)扒磁。其次就是方便維護(hù)惦界,因為每個功能模塊可以分得更清楚魄咕,所謂的松耦合咪辱。

第三個 W "How" -- 如何做?我們?nèi)绾伍_發(fā) JavaScript 插件?這是我們這片文章要談?wù)摰闹攸c.

二教届、準(zhǔn)備知識

在討論如何做之前我們不妨先通過反向思維來看看插件的特點署驻。我們從如何使用 Javascript 插件開始。

假設(shè)我們現(xiàn)在要使用插件 js-plugin.js

第一步:引入插件耕餐,注意依賴項凡傅,例如有些插件是基于 jquery 編寫的,先引入 jquery

第二步:通過插件提供的 API 實現(xiàn)我們所要的業(yè)務(wù)

以經(jīng)典的 jquery 使用方法為例

<script src="http://cdn.bootcss.com/jquery/3.1.0/jquery.min.js"></script>
<script>
    $(function(){
        $("#Id").html('hello world!');
    })
</script>

順便說一句肠缔,能使用CDN的盡量使用CDN,這將使你的資源加載得更快.并節(jié)省你主機(jī)的帶寬開銷
傳送門: BootCDN

上述兩點其實也就是說我們的插件要做到夏跷,引入相關(guān)文件就可以方便地進(jìn)行使用。換句話說插件必須滿足下面的特點:

首先明未,我覺得插件最重要的一點 -- 復(fù)用性槽华。就是說你這個插件在這個項目中是能用的,搬到另一個項目中它也是能用的(廢話)趟妥,并且原則上依賴項越少越好

其次猫态,我覺得這是插件的宗旨 -- 易用性。開發(fā)一個插件,如果使用繁瑣懂鸵,倒不如重新造輪子偏螺,那就失去了插件的意義。

除此之外匆光,當(dāng)然還有高效性套像,考慮執(zhí)行的效率還有內(nèi)存的優(yōu)化。

三终息、Module 模式

插件開發(fā)不得不提的是 Modlule 模式夺巩,Module -- 模塊,模塊化開發(fā)周崭,是在編程中十分通用的模式柳譬。說白了就是把業(yè)務(wù)需求分模塊。每一個模塊負(fù)責(zé)一個功能的實現(xiàn)续镇。有點像其他面向?qū)ο缶幊陶Z言中的類美澳。例如 JsonHelper 專門負(fù)責(zé) json 解析,F(xiàn)ilesUpload,專門用來做文件上傳的摸航,等等這些制跟。

插件就是用這樣一種模塊化思想來進(jìn)行開發(fā)的,下面我們通過代碼來簡單解釋下 Module 模式酱虎。

var Helloword = function(objId){
    var _get_dom = function(Id){
        return document.getElementById(Id);
    }
    var _aim_obj = _get_dom(objId);
    var _say_hello = function(str){
        _aim_obj.innerHTML = str;    HelloWorld.sayHello('hello','hello text');
    }
    return{
        sayHello:_say_hello
    }
}

由上述代碼可見雨膨,我們將某些功能,如 “sayHello” 給歸到 Helloword (模塊)中了读串。當(dāng)然我們可以繼續(xù)在下面添加其他功能聊记,但都?xì)w于模塊 Helloword 來管理。這就是 Module 的體現(xiàn)恢暖。

使用方法(注意這里使用了 new )

var Hei = new Helloword('hello');
Hei.sayHello('Hello Word');

var Hei2 = new Helloword('hi');
Hei2.sayHello('hi');

更直觀點排监,我們來看下完整的代碼

<!DOCTYPE html>
<html>
<head>
    <title>Module</title>
</head>
<body>
    <div Id="hello"></div>
    <div Id="hi"></div>
    <script type="text/javascript">
        var Helloword = function(objId){
            var _get_dom = function(Id){
                return document.getElementById(Id);
            }
            var _aim_obj = _get_dom(objId);
            var _say_hello = function(str){
                _aim_obj.innerHTML = str;
            }
            return{
                sayHello:_say_hello
            }
        }
        var Hei = new Helloword('hello');
        Hei.sayHello('Hello Word');
        
        var Hei = new Helloword('hi');
        Hei.sayHello('hi');        
    </script>
</body>
</html>

運行結(jié)果如下

運行結(jié)果

我們這里需要注意的是,每使用 new 創(chuàng)建出來的新對象都將開辟新的內(nèi)存空間(新的一份copy)胀茵,只要引用沒有釋放社露,那么該對象的占用的內(nèi)存空間將不會被回收挟阻。那么如何避免過多浪費內(nèi)存呢琼娘?一句話“釋放引用”,只需要釋放對該對象的所有引用附鸽,垃圾回收機(jī)制就會將該對象占用的內(nèi)存空間回收脱拼。

var Hei = new Helloword('hello');
Hei.sayHello('Hello Word');

Hei = null;//解除引用。

這樣還要“手動”內(nèi)存管理坷备,麻煩熄浓。如何讓該模塊在內(nèi)存中只保留一份(copy)呢?請看下面一段代碼

var HelloWorld = (function(){
    var _getDom = function(Id){
        return document.getElementById(Id)                    
    }
    var _sayHello = function(Id,str){
        _getDom(Id).innerHTML = str;
    }
    return {
        getDom:_getDom,
        sayHello:_sayHello
    }
}())

使用方法

HelloWorld.sayHello('hello','hello text');

是的,正如你所見到的,不需要 new 了。使用時不再需要創(chuàng)建新對象赌蔑,也就是說我們只保持了該對象在內(nèi)存中的一份引用俯在,也就是HelloWorld 對它的引用。當(dāng) HelloWorld 對其引用解除時其所占用的內(nèi)存將得到釋放娃惯。上述代碼實質(zhì)上是一個匿名閉包跷乐。如果對閉包不是很理解的朋友可以看看我寫的上一篇文章《淺析 JavaScript 中的閉包(Closures)》

四、插件基礎(chǔ)代碼

了解了上面的種種之后我們要開始直切主題了趾浅。

首先我們創(chuàng)建一個 js 文件 取名為 first-js-plugin.js(啥名字都行)愕提,鍵入以下代碼

;
var plugin =(function(){
    function _firstFunc(str){
        console.log(str);
    };
    return{
        firstFunc: _firstFunc,
    };
})();

再創(chuàng)建一個 HTML頁面 取名為 pluginTest.html (啥名字都行)

完整代碼如下

<!DOCTYPE html>
<html>    
<head>
    <title></title>
    <script type="text/javascript" src="./first-js-plugin.js"></script>
    <script type="text/javascript">
        plugin.firstFunc("Hello ! I am firstFunc");
    </script>
</head>
<body>

</body>
</html>

運行結(jié)果:

運行結(jié)果

通過這個簡單的插件,我們來分析一下里面的代碼.

在分析代碼之前我們先來了解另一個東西,自調(diào)用匿名函數(shù)(防止插件用戶定義函數(shù)與插件沖突)

(function(){
    //code
})();

可能有些童鞋會覺得有點陌生,那看下下面的代碼

var func = function(){
    //code
}
func();

其實這兩段代碼是等價的,當(dāng)然有點差別,第一個是匿名函數(shù).作用都是定義一個函數(shù)并立即執(zhí)行.

(function(){
    //code
})();

代碼分析:

  1. 最后面的小括號 () 表示執(zhí)行該函數(shù)

  2. (匿名函數(shù)) 小括號(分組表達(dá)式)包起來匿名函數(shù)的聲明,作用相當(dāng)是將函數(shù)聲明轉(zhuǎn)為表達(dá)式,這樣才能執(zhí)行,僅此而已

    如果采取以下寫法

     function(){
         //code
     }();
    

    編譯器報錯,問題是函數(shù)聲明無法執(zhí)行,表達(dá)式才能執(zhí)行

搞清楚這些之后我們回頭給下面的代碼加上分析,如下

;//JavaScript 弱語法的特點,如果前面剛好有個函數(shù)沒有以";"結(jié)尾,那么可能會有語法錯誤

/*
 plugin.api_funcs 給對象設(shè)置屬性,屬性值為 自調(diào)用匿名函數(shù)
 這里涉及到j(luò)s作用域鏈以及閉包的知識點
*/    
var plugin =(function(){
    function _firstFunc(str){
        alert(str);
    };
    
    //返回API
    return{
        firstFunc: _firstFunc
    };
})();

我們將代碼抽取一下(只為幫助理解皿哨,已經(jīng)理解的朋友請忽略)

//01.定義變量
var plugin = 某對象;

//02.創(chuàng)建對象并返回
(function(){//code;return ...})();//匿名執(zhí)行函數(shù) return 某對象

//然后看核心的返回
return{firstFunc: _firstFunc};

//說白了就是,通過某個key將一個函數(shù)存儲起來.使用時通過key訪問到這個函數(shù)
var plugin = {key:function(){//code}}

//所以最終的體現(xiàn)如下
var plugin = {firstFunc: “具體的函數(shù)引用”}

所以我們最后才能通過浅侨,插件名.屬性 來使用插件,正如:

plugin.firstFunc("Hello ! I am firstFunc");

四证膨、插件的幾種寫法

這里我就不墨跡了,直接上代碼,關(guān)鍵處會給注釋

  1. 面向?qū)ο笏枷?類方式

     //自定義類    
     function plugin(){}
    
     //提供默認(rèn)參數(shù)
     plugin.prototype.str = "default param";
    
     //提供方法(如果不傳參,則使用默認(rèn)參數(shù))
     plugin.prototype.firstFunc = function(str = this.str){
         alert(str);
     }
    
     //創(chuàng)建"對象"
     var p = new plugin();
     //調(diào)用方法
     p.firstFunc("Hello ! I am firstFunc");//Hello ! I am firstFunc
     p.firstFunc();//default param
    
  2. 閉包方式

    閉包方式就是我們剛剛一直在介紹

     var plugin =(function(){
         function _firstFunc(str){
             alert(str);
         };
         return{
             firstFunc: _firstFunc,
         };
     })();
    
  3. 第二種方式上的一些變化

     (function(){
         //定義一些默認(rèn)參數(shù)
         var _options={
             default_word:"default hello"                
         }
    
         //定義一些api
         var _plugin_api = {
             firstFunc:function(str = _options.default_word){
                 alert(str);
                 return this;//返回當(dāng)前方法
             },
             secondFunc:function(){
                 alert("secondFunc");
                 return this;//返回當(dāng)前方法
             }
         }
         //這里確定了插件的名稱
         this.CJPlugin = _plugin_api;
     })();
    
     CJPlugin.firstFunc("hello");//hello
     CJPlugin.firstFunc();//default hello
     CJPlugin.secondFunc();//secondFunc
    
結(jié)束語

JavaScript 插件的相關(guān)知識今天暫時聊到這了.下篇文章筆者將通過實例來介紹如何開發(fā)一款屬于自己的省市區(qū)三級聯(lián)動插件.如果有朋友正在學(xué)習(xí)插件開發(fā).那么下篇文章可能我們有更多可以探討的話題如输。

限于筆者技術(shù),文章觀點難免有不當(dāng)之處央勒,希望發(fā)現(xiàn)問題的朋友幫忙指正挨决,筆者將會及時更新。也請轉(zhuǎn)載的朋友注明文章出處并附上原文鏈接订歪,以便讀者能及時獲取到文章更新后的內(nèi)容脖祈,以免誤導(dǎo)讀者。筆者力求避免寫些晦澀難懂的文章(雖然也有人說這樣顯得高逼格刷晋,專業(yè))盖高,盡量使用簡單的用詞和例子來幫助理解。如果表達(dá)上有好的建議的話也希望朋友們在評論處指出眼虱。
本文為作者原創(chuàng),轉(zhuǎn)載請注明出處! 《如何開發(fā)原生的 JavaScript 插件(知識點+寫法)》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末喻奥,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子捏悬,更是在濱河造成了極大的恐慌撞蚕,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件过牙,死亡現(xiàn)場離奇詭異甥厦,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)寇钉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進(jìn)店門刀疙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人扫倡,你說我怎么就攤上這事谦秧。” “怎么了?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵疚鲤,是天一觀的道長锥累。 經(jīng)常有香客問我,道長集歇,這世上最難降的妖魔是什么揩悄? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮鬼悠,結(jié)果婚禮上删性,老公的妹妹穿的比我還像新娘。我一直安慰自己焕窝,他們只是感情好蹬挺,可當(dāng)我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著它掂,像睡著了一般巴帮。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上虐秋,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天榕茧,我揣著相機(jī)與錄音,去河邊找鬼客给。 笑死用押,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的靶剑。 我是一名探鬼主播蜻拨,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼桩引!你這毒婦竟也來了缎讼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤坑匠,失蹤者是張志新(化名)和其女友劉穎血崭,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體厘灼,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡夹纫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了手幢。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片捷凄。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖围来,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤监透,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布桶错,位于F島的核電站,受9級特大地震影響胀蛮,放射性物質(zhì)發(fā)生泄漏院刁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一粪狼、第九天 我趴在偏房一處隱蔽的房頂上張望退腥。 院中可真熱鬧,春花似錦再榄、人聲如沸狡刘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽嗅蔬。三九已至,卻和暖如春疾就,著一層夾襖步出監(jiān)牢的瞬間澜术,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工猬腰, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留鸟废,地道東北人。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓姑荷,卻偏偏與公主長得像侮攀,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子厢拭,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,689評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理兰英,服務(wù)發(fā)現(xiàn),斷路器供鸠,智...
    卡卡羅2017閱讀 134,654評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,097評論 25 707
  • 工廠模式類似于現(xiàn)實生活中的工廠可以產(chǎn)生大量相似的商品畦贸,去做同樣的事情,實現(xiàn)同樣的效果;這時候需要使用工廠模式楞捂。簡單...
    舟漁行舟閱讀 7,752評論 2 17
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法薄坏,類相關(guān)的語法,內(nèi)部類的語法寨闹,繼承相關(guān)的語法胶坠,異常的語法,線程的語...
    子非魚_t_閱讀 31,625評論 18 399
  • 經(jīng)朋友不斷推薦繁堡,讀了《殺死一只知更鳥》沈善,盡管我沒有預(yù)設(shè)任何的期待乡数,還是覺得閱讀體驗很棒。沿著作者給予的思路闻牡,我找到...
    孤單相許閱讀 195評論 0 0