如何开发原生的 JavaScript 插件(知识点+写法)

1、前言

经过 "WWW" 原则咱们来了解 JavaScript 插件这个东西javascript

第一个 W "What" -- 是什么?什么是插件,我就不照搬书本上的抽象概念了,我我的简单理解就是,能方便实现某个功能的扩展工具.(下面我会经过简单的例子来帮助读者理解)css

第二个 W "Why" -- 为何? 为何要有插件这种东西,首先结合第一个 W 来理解就是,使用插件的目的是方便咱们实现某一个功能. 也就是说在编程过程当中咱们只须要找轮子,或者改轮子而不须要从新造轮子.节省开发时间,而且各司其职会更加专业(作得更好)。其次就是方便维护,由于每一个功能模块能够分得更清楚,所谓的松耦合。html

第三个 W "How" -- 如何作?咱们如何开发 JavaScript 插件?这是咱们这片文章要谈论的重点.java

2、准备知识

在讨论如何作以前咱们不妨先经过反向思惟来看看插件的特色。咱们从如何使用 Javascript 插件开始。jquery

假设咱们如今要使用插件 js-plugin.jsgit

第一步:引入插件,注意依赖项,例若有些插件是基于 jquery 编写的,先引入 jquerygithub

第二步:经过插件提供的 API 实现咱们所要的业务web

以经典的 jquery 使用方法为例编程

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

顺便说一句,能使用CDN的尽可能使用CDN,这将使你的资源加载得更快.并节省你主机的带宽开销 传送门: BootCDNjson

上述两点其实也就是说咱们的插件要作到,引入相关文件就能够方便地进行使用。换句话说插件必须知足下面的特色:

首先,我以为插件最重要的一点 -- 复用性。就是说你这个插件在这个项目中是能用的,搬到另外一个项目中它也是能用的(废话),而且原则上依赖项越少越好

其次,我以为这是插件的宗旨 -- 易用性。开发一个插件,若是使用繁琐,倒不如从新造轮子,那就失去了插件的意义。

除此以外,固然还有高效性,考虑执行的效率还有内存的优化。

3、Module 模式

插件开发不得不提的是 Modlule 模式,Module -- 模块,模块化开发,是在编程中十分通用的模式。说白了就是把业务需求分模块。每个模块负责一个功能的实现。有点像其余面向对象编程语言中的类。例如 JsonHelper 专门负责 json 解析,FilesUpload,专门用来作文件上传的,等等这些。

插件就是用这样一种模块化思想来进行开发的,下面咱们经过代码来简单解释下 Module 模式。

var HelloWorld = 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
    }
}

由上述代码可见,咱们将某些功能,如 “sayHello” 给归到 HelloWorld (模块)中了。固然咱们能够继续在下面添加其余功能,但都归于模块 HelloWorld 来管理。这就是 Module 的体现。

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

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

var Hei2 = new HelloWorld('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 HelloWorld = 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 HelloWorld('hello');
            Hei.sayHello('Hello World');
            
            var Hei = new HelloWorld('hi');
            Hei.sayHello('hi');        
        </script>
    </body>
    </html>

运行结果以下

咱们这里须要注意的是,每使用 new 建立出来的新对象都将开辟新的内存空间(新的一份copy),只要引用没有释放,那么该对象的占用的内存空间将不会被回收。那么如何避免过多浪费内存呢?一句话“释放引用”,只须要释放对该对象的全部引用,垃圾回收机制就会将该对象占用的内存空间回收。

var Hei = new HelloWorld('hello');
Hei.sayHello('Hello World');
    
Hei = null;//解除引用

这样还要“手动”内存管理,麻烦。如何让该模块在内存中只保留一份(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 了。使用时再也不须要建立新对象,也就是说咱们只保持了该对象在内存中的一份引用,也就是HelloWorld 对它的引用。当 HelloWorld 对其引用解除时其所占用的内存将获得释放。上述代码实质上是一个匿名闭包。若是对闭包不是很理解的朋友能够看看我写的上一篇文章《浅析 JavaScript 中的闭包(Closures)》

4、插件基础代码

了解了上面的种种以后咱们要开始直切主题了。

首先咱们建立一个 js 文件 取名为 first-js-plugin.js(啥名字都行),键入如下代码

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

再建立一个 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>

运行结果以下图显示

经过这个简单的插件,咱们来分析一下里面的代码.

在分析代码以前咱们先来了解另外一个东西,自调用匿名函数(防止插件用户定义函数与插件冲突)

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

可能有些童鞋会以为有点陌生,那看下下面的代码

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

其实这两段代码是等价的,固然有点差异,第一个是匿名函数.做用都是定义一个函数并当即执行.

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

代码分析:

  1. 最后面的小括号 () 表示执行该函数
  2. (匿名函数) 小括号(分组表达式)包起来匿名函数的声明,做用至关是将函数声明转为表达式,这样才能执行,仅此而已

    若是采起如下写法

    function(){ //code }();

    编译器报错,问题是函数声明没法执行,表达式才能执行

搞清楚这些以后咱们回头给下面的代码加上分析,以下

;//JavaScript 弱语法的特色,若是前面恰好有个函数没有以";"结尾,那么可能会有语法错误

    /*
     plugin.api_funcs 给对象设置属性,属性值为 自调用匿名函数
     这里涉及到js做用域链以及闭包的知识点
    */    
    var plugin =(function(){
        function _firstFunc(str){
            alert(str);
        };
        
        //返回API
        return{
            firstFunc: _firstFunc
        };
    })();

咱们将代码抽取一下(只为帮助理解,已经理解的朋友请忽略)

//01.定义变量
var plugin = 某对象;

//02.建立对象并返回
(function(){//code;return ...})();//匿名执行函数 return 某对象

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

//说白了就是,经过某个key将一个函数存储起来.使用时经过key访问到这个函数
var plugin = {key:function(){//code}}

//因此最终的体现以下
var plugin = {firstFunc: “具体的函数引用”}

因此咱们最后才能经过,插件名.属性 来使用插件,正如:

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

4、插件的几种写法

这里我就不墨迹了,直接上代码,关键处会给注释

  1. 面向对象思想 类方式

    //自定义类    
    function plugin(){}
    
    //提供默认参数
    plugin.prototype.str = "default param";
    
    //提供方法(若是不传参,则使用默认参数)
    plugin.prototype.firstFunc = function(str = this.str){
        alert(str);
    }
    
    //建立"对象"
    var p = new plugin();
    //调用方法
    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(){
        //定义一些默认参数
        var _options={
            default_word:"default hello"                
        }
    
        //定义一些api
        var _plugin_api = {
            firstFunc:function(str = _options.default_word){
                alert(str);
                return this;//返回当前方法
            },
            secondFunc:function(){
                alert("secondFunc");
                return this;//返回当前方法
            }
        }
        //这里肯定了插件的名称
        this.CJPlugin = _plugin_api;
    })();
    
    CJPlugin.firstFunc("hello");//hello
    CJPlugin.firstFunc();//default hello
    CJPlugin.secondFunc();//secondFunc
结语

JavaScript 插件的相关知识今天暂时聊到这了.下篇文章笔者将经过实例来介绍如何开发一款属于本身的省市区三级联动插件.若是有朋友正在学习插件开发.那么下篇文章可能咱们有更多能够探讨的话题。

 

限于笔者技术,文章观点不免有不当之处,但愿发现问题的朋友帮忙指正,笔者将会及时更新。也请转载的朋友注明文章出处并附上原文连接,以便读者能及时获取到文章更新后的内容,以避免误导读者。笔者力求避免写些晦涩难懂的文章(虽然也有人说这样显得高逼格,专业),尽可能使用简单的用词和例子来帮助理解。若是表达上有好的建议的话也但愿朋友们在评论处指出。

本文为做者原创,转载请注明出处! Cboyce

相关文章
相关标签/搜索