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

news2025/2/27 2:04:33

一、前言

通过 "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);
        };
        
        //返回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");

四、插件的几种写法

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

  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

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/618692.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

(9)基于发射器的调优

文章目录 前言 1 概述 2 调优值 3 用任务规划器设置 前言 你可以在飞行中使用你的遥控发射器进行广泛的参数调优。这是为那些无法使用自动调优功能的高级用户准备的&#xff0c;或者希望通过对每个参数的完全手动调优控制来进行微调。 1 概述 基于发射机的调优允许你在飞行…

scala内建控制结构

一、条件表达式 &#xff08;一&#xff09;语法格式 - if (条件) 值1 else 值2&#xff08;二&#xff09;执行情况 条件为真&#xff0c;结果是值1&#xff1b;条件为假&#xff0c;结果是值2。如果if和else的返回结果同为某种类型&#xff0c;那么条件表达式结果也是那种类…

Vue.js 中的 props 和 $emit 方法有什么关系?

Vue.js 中的 props 和 $emit 方法有什么关系&#xff1f; 在 Vue.js 中&#xff0c;props 和 $emit 方法是两个常用的概念。它们可以帮助开发者更方便地实现组件之间的通信。但是这两个概念有什么关系呢&#xff1f;本文将会详细介绍 Vue.js 中的 props 和 $emit 方法&#xf…

【LeetCode每日一题】——1475.商品折扣后的最终价格

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时间频度】九【代码实现】十【提交结果】 一【题目类别】 栈 二【题目难度】 简单 三【题目编号】 1475.商品折扣后的最终价格 四【题目描述】 给你一…

【区块链 | EVM】深入理解学习EVM - 深入了解 Solidity:堆栈

探讨 EVM 堆栈机器,以及如何在堆栈中推入和弹出数据 原文链接: https://betterprogramming.pub/solidity-tutorial-all-about-stack-c1ec6070fe60探讨 EVM 堆栈机器,以及如何在堆栈中推入和弹出数据 图片来源:Iva Rajović on Unsplash 这是"深入Solidity数据存储位置…

A股月份效应 | Python量化A股市场魔咒,5穷6绝7翻身准确吗?| 邢不行

A股有很多广为流传的谚语&#xff0c;它们大多源于投资者对交易经验的总结和共识。 比如我们之前验证过的散户反买别墅靠海、跳空必回补等谚语。 今天我们要验证的&#xff0c;是五穷六绝七翻身这句谚语。 它的意思是A股在5月、6月可能会跌的很惨&#xff0c;到7月会开始反弹回…

浅谈倾斜摄影三维模型数据裁剪的应用场景

浅谈倾斜摄影三维模型数据裁剪的应用场景 倾斜摄影三维模型数据裁剪是将倾斜摄影三维模型数据中不需要的部分删除或隐藏的过程&#xff0c;可以提高数据处理效率和准确性。倾斜摄影三维模型数据裁剪广泛应用于建筑、城市规划、地质勘探、环境监测等领域。本文将介绍倾斜摄影三维…

基于Springboot+Vue的计算机房管理系统

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 计算机房管理系统在现…

读取所在点的像素值

由于项目需求&#xff0c;需要用到开源的软件开发&#xff0c;就开始研究GDAL&#xff0c;这个开源库&#xff0c;目前来说&#xff0c;调用GDAL库&#xff0c;最方便的语言还是python &#xff0c;简单记录下&#xff0c;用python语言做GDAL开发的一些东西吧。一个在开发中经常…

​浅谈Vue3响应式原理与源码解读

一. 了解几个概念 什么是响应式 在开始响应式原理与源码解析之前&#xff0c;需要先了解一下什么是响应式&#xff1f;首先明确一个概念&#xff1a;响应式是一个过程&#xff0c;它有两个参与方&#xff1a; 触发方&#xff1a;数据响应方&#xff1a;引用数据的函数 当数据发…

微信小程序原生开发功能合集十八:系统主题及自定义主题功能实现

本章实现系统主题监听及相应处理,包括暗黑色、亮色等。并实现自定义主题控制相关功能,可通过菜单进行主题的切换。   另外还提供小程序开发基础知识讲解课程,包括小程序开发基础知识、组件封装、常用接口组件使用及常用功能实现等内容,具体如下:    1. CSDN课程: ht…

VUE 实现滑块验证 ①

作者 : SYFStrive 博客首页 : HomePage &#x1f4dc;&#xff1a; 微信小程序 &#x1f4cc;&#xff1a;个人社区&#xff08;欢迎大佬们加入&#xff09; &#x1f449;&#xff1a;社区链接&#x1f517; &#x1f4cc;&#xff1a;觉得文章不错可以点点关注 &#x1f4…

2023年6月DAMA-CDGP数据治理专家认证,来这里

DAMA认证为数据管理专业人士提供职业目标晋升规划&#xff0c;彰显了职业发展里程碑及发展阶梯定义&#xff0c;帮助数据管理从业人士获得企业数字化转型战略下的必备职业能力&#xff0c;促进开展工作实践应用及实际问题解决&#xff0c;形成企业所需的新数字经济下的核心职业…

Windows批处理文件倒计时且循环执行文件/程序

Windows批处理文件倒计时且循环执行文件/程序&#xff1a; 最近想循环测试下语音唤醒设备&#xff0c;所以需要用bat文件在Windows上一直循环播放指定的mp3文件&#xff0c;且设置了间隔时间&#xff0c;也就是倒计时时间&#xff0c;最后网上查了一堆之后整理了一个bat&#x…

微信小程序开发中遇到的坑

目录 1、clearInterval不起作用 2、设置background: linear-gradient(180deg, #FCF8F5 0%, #FCF8F5 99.9%, transparent 100%);解决元素底部有黑线的问题。但是在ios中不起作用。 3、wx.createAnimation&#xff0c;设置的动画只能执行一次 4、swiper在苹果手机上显示不全&…

C#,码海拾贝(33)——约化“一般实矩阵”为“赫申伯格矩阵”的“初等相似变换法”之C#源代码

using System; namespace Zhou.CSharp.Algorithm { /// <summary> /// 矩阵类 /// 作者&#xff1a;周长发 /// 改进&#xff1a;深度混淆 /// https://blog.csdn.net/beijinghorn /// </summary> public partial class Matrix {…

【React】脚手架,组件化开发,类组件/函数式组件,声明周期,组件的嵌套,子父传递,插槽,Context,事件总线,setState原理

❤️ Author&#xff1a; 老九 ☕️ 个人博客&#xff1a;老九的CSDN博客 &#x1f64f; 个人名言&#xff1a;不可控之事 乐观面对 &#x1f60d; 系列专栏&#xff1a; 文章目录 脚手架目录结构组件化开发类组件函数式组件 声明周期组件的嵌套组件之间的通信插槽 Context事件…

vscode实现代码片段快捷输入设置

1.编写想要的代码片段 <template> <div>AppContent</div> </template> <script> export default { } </script> <style scoped> </style> 2.打开网站:snippet generator 如下图添加描述,快捷键和代码片段.右边会有生成内容 …

93.构建样品餐部分第一节

之前我们实现得页面是这个样子的 现在让我们来完成剩下的样品餐部分吧&#xff01; ● 大致实现的页面是这样的 ● 让我们先简单的生成这些框架 <section class"section-meals"><div class"container"><span class"subheading&qu…

SpringCloud Alibaba Seata配置到Nacos

SpringCloud Alibaba Seata 1 Seata 简介 单体应用被拆分成微服务应用&#xff0c;原来的三个模块被拆分成三个独立的应用&#xff0c;分别使用 三个独立的数据源业务操作需要调用三个服务来完成。此时每个服务内部的数据一致性由本地事务来保 证但是全局的数据—致性问题没法…