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

news/2024/12/30 0:47:15/

一、前言

通过 "WWW" 原则我们来了解 JavaScript 插件这个东西

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

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

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

二、准备知识

在讨论如何做之前我们不妨先通过反向思维来看看插件的特点。我们从如何使用 Javascript 插件开始。

假设我们现在要使用插件 js-plugin.js

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

第二步:通过插件提供的 API 实现我们所要的业务

以经典的 jquery 使用方法为例

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

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

上述两点其实也就是说我们的插件要做到,引入相关文件就可以方便地进行使用。换句话说插件必须满足下面的特点:

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

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

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

三、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 对其引用解除时其所占用的内存将得到释放。上述代码实质上是一个匿名闭包。如果对闭包不是很理解的朋友可以看看我写的

四、插件基础代码

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

首先我们创建一个 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);};//返回APIreturn{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");

四、插件的几种写法

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

  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"                }//定义一些apivar _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

 


http://www.ppmy.cn/news/258662.html

相关文章

JUC基础-0531

3 线程间通信 线程间通信的模型有两种:共享内存和消息传递&#xff0c;以下方式都是基本这两种模型来实现的。我们来基本一道面试常见的题目来分析 多线程编程步骤&#xff1a; 第一步&#xff1a;创建资源类&#xff0c;在资源类创建属性和操作方法第二步&#xff1a;在资源…

Qt6之Qt生成dll及vc调用

Qt可以调用vc生成的dll&#xff0c;反之qt也可以提供生成的dll给其它语言来调用&#xff0c;比如VC、rust等。 一、qt生成dll 在Qt creator加持下已经很容易的生成DLL&#xff0c;如下&#xff1a; 1、新建&#xff0c;库&#xff0c;C Library&#xff1b; 2、类型&#xff…

机器学习方法在生态经济学领域中的应用

查看原文>>>基于R语言机器学习方法在生态经济学领域中的实践技术 近年来&#xff0c;人工智能领域已经取得突破性进展&#xff0c;对经济社会各个领域都产生了重大影响&#xff0c;结合了统计学、数据科学和计算机科学的机器学习是人工智能的主流方向之一&#xff0c…

哨兵2号(Sentinel-2)卫星数据批量处理

李国春 2021 10 11 哨兵2号&#xff08;Sentinel-2&#xff09;数据广受欢迎&#xff0c;数据质量好&#xff0c;还免费。人家欧空局有自己的处理软件&#xff0c;也有控制台命令行的批量处理。RSD也来凑凑热闹沾个光&#xff0c;指不定有人喜欢不同的操作风格&#xff0c;愿意…

运用自动化测试脚本,测试下CSDN的登录功能模块

目录 前言 python程序目录 账号密码登录模块 测试用例执行模块 运行结果示例 前言 自动化测试的重要性越来越受到人们的重视&#xff0c;因为它可以提高测试效率、降低测试成本并减少人为错误的出现。为了满足这个需求&#xff0c;越来越多的公司开始采用自动化测试来保证…

Java样题

除了List、Set、Map、Queue这四个接口外&#xff0c;其他的都是实现类。例如&#xff0c;ArrayList、LinkedList、HashSet、LinkedHashSet、HashMap、LinkedHashMap、TreeMap等都是实现类&#xff0c;而不是接口。 . 子类构造方法调用父类构造方法要使用 super ( 实参 )&#…

电磁炉的使用知识

厨用电电磁炉的使用知识 发布时间&#xff1a;2004年10月4日 19时59分 电磁炉是一种新型家用电器。其基本工作原理是&#xff1a;利用可控的高频电磁场直接作用在具有导磁及导电性的厨具上而产生涡流发热来完成工作的。所使用厨具的材质应具有良好的导磁及导电特性&#xf…

【2023】华为OD机试真题Java CC++ Python JS Go-题目0243-模拟商场优惠打折

题目0243-模拟商场优惠打折 题目描述 模拟商场优惠打折,有三种优惠券可以用,满减券、打折券和无门槛券。 满减券:满100减10,满200减20,满300减30,满400减40,以此类推不限制使用; 打折券:固定折扣92折,且打折之后向下取整,每次购物只能用1次; 无门槛券:一张券…