JS模块化

本文概述了JavaScript模块化的发展历程,从最初的全局函数问题,到命名空间模式、IIFE、CommonJS、AMD,最后到达ES6Modules。这些模块化规范解决了代码复用、命名冲突和提升代码组织性的挑战。
摘要由CSDN通过智能技术生成

在 JavaScript 的过去,没有像现在这样流行的模块化开发规范。JavaScript 最初被设计为一种用于网页交互的编程语言,而不是作为一门通用的编程语言来使用。因此,当我们想要创建可重复利用的功能或组件时,常常会将其定义为全局变量或函数。

然而,随着前端应用程序的日益复杂性以及多人合作项目的需求,全局函数的使用导致了命名空间冲突、代码冗余等问题。为了解决这些问题,并提高代码的可维护性和可测试性,模块化开发规范(如 CommonJS、AMD、ES6 Modules)得到广泛接受和支持。

js 模块化发展大致分为6个阶段

1. 全局函数时代
最早直接在一个js文件中定义,全局环境污染,很容易命名冲突。

function foo() {
  //...
}
function fun() {
  //...
}

Namespace模式,把数据放到对象里面简单封装,减少全局的变量数目,但本质上是对象,可以通过对象.属性修改数据,一点都不安全。

var obj = {
  foo: function() {},
  fun: function() {}
}
obj.foo();

2. 命名空间模式
命名空间模式是一种在编程中使用对象来避免变量或函数重复命名的技术。可以创建一个全局对象作为命名空间,然后将相关的属性和方法添加到该对象上,从而达到限制变量作用域的目的。下面是一个示例代码:

// 创建命名空间对象
var myNamespace = {};
 
// 向命名空间对象添加属性和方法
myNamespace.property1 = 'value';
myNamespace.method1 = function() {
    // do something...
};
 
// 调用命名空间内部的属性和方法
console.log(myNamespace.property1);
myNamespace.method1();

3.IIFE(立即执行函数表达式)
立即执行函数表达式(Immediately Invoked Function Expression,IIFE)是一种在定义后立即调用的函数形式。它可以创建一个隐藏作用域,使得变量不会被全局污染,同时也能保护内部变量的
安全性。下面是一个示例的IIFE代码:

(function() {
    // IIFE中的代码
})();

jQuery就是用javascript函数作用域的特性,采用立即调用表达式包裹了自身的方法来解决这个问题的。

(function(window,undefined){
   var jQuery = function(){};//....window.jQuery = window.$ = jQuery;
})(window);

4.CommonJS
CommonJs 是一种 JavaScript 语言的模块化规范,它通常会在服务端的 Nodejs 上使用。项目是由多个模块组成的,模块和模块之间的调用,需要各个模块有相同规范的 API,这样一来在使用的过程中不会有那么多的学习成本,并且对于单个模块来说是类聚的。

在 CommonJs 的模块化规范中,每一个文件就是一个模块,拥有自己独立的作用域、变量、以及方法等,对其他的模块都不可见。CommonJS规范规定,每个模块内部,module 变量代表当前模块。这个变量是一个对象,它的 exports 属性(module.exports)是对外的接口。加载某个模块,其实是加载该模块的 module.exports 属性。require 方法用于加载模块。

//moudle-one.js
moudle.exports = {
    name: 'TK'
};

//moudle-two.js
var nameA = require('./moudle-one');
var bName = nameA.name + 'nameTwo';

5.AMD(异步模块定义)
AMD Async Module Definition 代表的意思为异步模块定义,是js中模块化浏览器解决方案,它采用异步加载方式加载模块,模块加载不影响后面语句的运行,所有依赖这个模块的语句,都定义在回调函数中,等加载完毕后,这个回调函数才会执行。
基本语法:
定义暴露模块:
1. 没有依赖的模块:

define(function(){
    return 模块
})

2. 定义有依赖的模块:

define(['module1','module2'],function(m1,m2){
    return 模块
})

引入使用模块:

require(['module1','module2'],function(m1,m2){
    使用m1/m2
})

主要实现于(浏览器端)典型的库,Require.js
可以看到AMD也采用require()语句加载模块,但是不同于CommonJS,它要求两个参数:

require([module], callback);

第一个参数[module],是一个数组,里面的成员就是要加载的模块;第二个参数callback,则是加载成功之后的回调函数。如果将前面的代码改写成AMD形式,就是下面这样:

require(['math'], function (math) {
     math.add(2, 3);
});

6.ES6模块
ES6 模块化规范中定义:
每个 js 文件都是一个独立的模块。
导入其它模块成员使用 import 关键字。
向外共享模块成员使用 export 关键字。

下面是一段示例代码展示了如何使用 ES6 Modules 进行模块化开发:


// moduleA.js
export function foo() {
    console.log('Hello from module A!');
}
 
// moduleB.js
import {foo} from './moduleA'; // 引入 moduleA 中的 foo 函数
 
function bar() {
    console.log('Hello from module B!');
    foo(); // 调用 moduleA 中的 foo 函数
}
 
bar();

上述代码中,moduleA.js 文件中定义了 foo() 函数,并通过 export 关键字将其导出。moduleB.js 文件中通过 import 关键字从 moduleA.js 中引入了 foo() 函数,并在自身的 bar() 函数内部调用了该函数。

通过使用模块化开发规范,我们可以更好地管理和组织代码,同时也能够确保每个模块之间相对独立,避免命名冲突和代码冗余。

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值