JavaScript模块化开发流程分步讲解

作者:dawn 时间:2024-06-05 09:11:18 

接触了Vue模块化开发才发现JavaScript组件化开发的演变一直在继续,以前也没有特别在意这一块内容,写着代码能调试运行不报错就可以了,主要编程语言标准就是ECMAScript5和ECMAScript6(2015年发布),使用ECMAScript6规范编写的程序需要转译器将代码编译为ECMAScript5才能为浏览器支持。作为前度开发者了解这些以及ECMAScript5和ECMAScript6的写法区别即可。

比如,ECMAScript5的写法:

var MyModuleName = {
 Property1: "",
 Property2: "",
 Config: {
   SetName1:"",
   SetName2:""
 },
 Method1: function() {},
 Method2: function() {}
};

对应的ECMAScript6的写法:

export const MyModuleName = {
 Property1: "",
 Property2: "",
 Config: {
   SetName1: "",
   SetName2: ""
 },
 myMethod1() {},
 myMethod2() {}
};

其实学习前端开发仅仅知道大概是不行的,现在把这一块的内容详细梳理一下。

1、使用传统的全局命名空间

这样情况下的缺点显而易见:

⑴全局变量无法控制是否冲突;

⑵成员函数之间看不出直接关系。

示例代码:

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>最原始的模式</title>
</head>
<body>
   <div id="view"></div>
   <script>
       var a=1,b=2;
       const viewId=document.getElementById('view');
       const contentId=document.createElement('div');
       contentId.innerHTML="a+b="+add(a,b);
       viewId.appendChild(contentId);
       function add(a,b){
           return a+b;
       }        
       function subtract(a,b){
           return a-b;
       }
   </script>
</body>
</html>

可以出正确结果,如果进行所谓的模块化开发,就是将代码不同文件化来进行。

主文件:

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>最原始的模式</title>
</head>
<body>
   <div id="view"></div>
   <script>
       var a=1,b=2;
   </script>
   <script src="module2.js"></script>
   <script src="module1.js"></script>
</body>
</html>

module1.js代码:

const viewId=document.getElementById('view');
const contentId=document.createElement('div');
contentId.innerHTML="a+b="+add(a,b);
viewId.appendChild(contentId);

module2.js代码:

var add=function(a,b){
   return a+b;
}        
var subtract=function(a,b){
   return a-b;
}

但是这导致可能因为文件引入顺序而出现运行错误,如果文件多了,依赖不容易检查,那么纠错就是一件让人头疼的事情了。

2、使用对象的写法

缺点:

⑴暴露所有模块成员;

⑵内部状态可以被外部改写;

⑶多文件化后依赖关系不好处理。

示例代码:

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>使用对象写法</title>
</head>
<body>
   <div id="view"></div>
   <script>
       var a=1,b=2;
       var MyUtils=new Object({
           Property1: "as",
           add:function(a,b){
               return a+b;
           },
           subtract:function(a,b){
               return a-b;
           }
       });
       const viewId=document.getElementById('view');
       const contentId=document.createElement('div');
       var result=MyUtils.add(a,b);
       contentId.innerHTML="a+b="+result;
       viewId.appendChild(contentId);
   </script>
</body>
</html>

3、使用命名空间的写法

前端开发者基本上都使用过JQuery.js来进行前端开发,JQuery.js主要使用率命名空间模式来组织代码,定义了一个全局变量 $ 或 jQuery,该变量是一个对象,包含了所有 jQuery 提供的功能。当使用 $或者jQuery 时,实际上就是访问这个全局变量。而 jQuery 库中所有的方法和属性都是在这个全局变量上定义的。

缺点:

⑴无法解决相互依赖问题特别是多文件化后;

⑵代码组织形式逐渐复杂化;

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>使用命名空间的写法</title>
</head>
<body>
   <div id="view"></div>
   <script>
       var a=1,b=2;

var MyApp = {
           UI: {
               //定义UI操作内容
           },
           Data: {
               //定义Data内容
           },
           Service: {
               //定义Service的内容
           },
           Utils: {
               //定义工具类内容
               add:function(a,b){
                   return a+b;
               },
               subtract:function(a,b){
                   return a-b;
               }                
           }
       };        
       const viewId=document.getElementById('view');
       const contentId=document.createElement('div');
       var result=MyApp.Utils.add(a,b);
       contentId.innerHTML="a+b="+result;
       viewId.appendChild(contentId);
   </script>
</body>
</html>

最开始常见的写法也可以是这样的:

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>使用IIFE(立即执行函数)写法</title>
</head>
<body>
   <div id="view"></div>
   <script>
       var a=1,b=2;
       //定义全局变量
       var MyUtils={};
       //定义子命名空间
       var MyUtils.UI={};
       var MyUtils.Data={};
       var MyUtils.Service={};
       var MyUtils.Utils={};
       //在子命名空间中定义内容
       var MyUtils.Utils.add=function(a,b){
               return a+b;
       };
       const viewId=document.getElementById('view');
       const contentId=document.createElement('div');
       var result=MyUtils.add(a,b);
       contentId.innerHTML="a+b="+result;
       viewId.appendChild(contentId);
   </script>
</body>
</html>

4、使用IIFE的写法

缺点:

⑴外部代码无法读取内部的变量;

⑵无法彻底解决模块间的相互依赖问题。

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>使用IIFE(立即执行函数)写法</title>
</head>
<body>
   <div id="view"></div>
   <script>
       var a=1,b=2;
       var MyUtils=(function(){
           Property1: "as";
           var add=function(a,b){
               return a+b;
           };
           var subtract=function(a,b){
               return a-b;
           }
           return {
               add:add,
               subtract:subtract
           }
       })();
       const viewId=document.getElementById('view');
       const contentId=document.createElement('div');
       var result=MyUtils.add(a,b);
       contentId.innerHTML="a+b="+result;
       viewId.appendChild(contentId);
       //外部代码无法读取内部的变量。
   </script>
</body>
</html>

要解决外部访问对象内部数据,可以对外暴露方法:

var a=1,b=2;
       var MyUtils=(function(){
           Property1: "as";
           var add=function(a,b){
               return a+b;
           };
           var subtract=function(a,b){
               return a-b;
           };
           var setProperty=function(str){
               this.Property1=str;
           };
           return {
               add:add,
               subtract:subtract,
               setProperty
           }
       })();
       const viewId=document.getElementById('view');
       const contentId=document.createElement('div');
       var result=MyUtils.add(a,b);
       contentId.innerHTML="a+b="+result;
       viewId.appendChild(contentId);
       MyUtils.setProperty("123");
       console.log(MyUtils.Property1);

上面的代码暴露了setProperty方法,可以操作对象的内部属性值。

遵循IIFE(立即执行函数)规范很好地使用了闭包的特点,可以进行多模块的开发:

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>使用IIFE(立即执行函数)写法</title>
</head>
<body>
   <div id="view"></div>
   <script>
       var a=1,b=2;
       var MyUtils1=(function(){
           Property1: "as";
           var add=function(a,b){
               return a+b;
           };
           var setProperty=function(str){
               this.Property1=str;
           };
           return {
               add:add,
               setProperty
           }
       })();
       var MyUtils2=(function(){
           Property1: "untils2";
           var add=function(a,b){
               return a+b;
           };
           var setProperty=function(str){
               this.Property1=str;
           };
           return {
               add:add,
               setProperty
           }
       })();
       //"继承"前面两个模块
       var MyUtils=(function(MyUtils1,MyUtils2){
           MyProperty: "MyUntils";
           function add(a,b){
               return MyUtils1.add(a,b);
           };
           function subtract(a,b){
               return MyUtils1.subtract(a,b);
           };
           return {
               add:add,
               subtract:subtract
           }
       })(MyUtils1,MyUtils2);
       const viewId=document.getElementById('view');
       const contentId=document.createElement('div');
       var result=MyUtils.add(a,b);
       contentId.innerHTML="a+b="+result;
       viewId.appendChild(contentId);
   </script>
</body>
</html>

但是最终的模块严格意义上并不是真正地继承前面的两个模块,只是依赖这两个模块的注入。

本想在这一篇把所有的演变模式总结完毕,可是后续的内容太多了并且后面的内容才是重点,写到这里文字已经有点多了,还是先写到这里。

来源:https://blog.csdn.net/dawn0718/article/details/128760583

标签:JS,模块化
0
投稿

猜你喜欢

  • 关于鼠标、键盘的几个事件的例子

    2008-07-27 17:00:00
  • Python获取时间戳代码实例

    2023-11-13 04:02:52
  • MYSQL必知必会读书笔记第四章之检索数据

    2024-01-18 03:34:40
  • Mysql主从数据库(Master/Slave)同步配置与常见错误

    2024-01-21 17:48:35
  • 数据库报错:Unknown column 'xxx' in 'where clause'问题的解决过程

    2024-01-22 23:23:04
  • Django中的用户身份验证示例详解

    2023-10-08 17:06:08
  • ASP codepage 页面编码使用说明

    2011-03-03 11:24:00
  • 详解Golang 与python中的字符串反转

    2021-08-01 23:31:08
  • Mysql安装注意事项、安装失败的五个原因分析

    2024-01-22 14:16:48
  • 新浪中用来显示flash的函数

    2024-04-18 09:36:16
  • 交互设计实用指南系列(9)—一次点击

    2010-02-08 12:42:00
  • js模仿php中strtotime()与date()函数实现方法

    2024-04-18 10:01:55
  • 多种语言下获取当前页完整URL及其参数

    2022-02-28 23:23:29
  • Python Scrapy图片爬取原理及代码实例

    2022-04-29 05:51:06
  • WSC脚本部件技术:利用Javascript编写ActiveX控件

    2008-05-05 13:13:00
  • 详谈js遍历集合(Array,Map,Set)

    2024-04-16 09:29:53
  • python实现图像检索的三种(直方图/OpenCV/哈希法)

    2021-08-11 17:15:08
  • Python过滤掉numpy.array中非nan数据实例

    2021-08-25 14:47:44
  • asp.net上传图片保存到数据库的代码

    2024-01-16 05:00:37
  • 解决Vue axios post请求,后台获取不到数据的问题方法

    2024-05-09 09:38:38
  • asp之家 网络编程 m.aspxhome.com