javascript 模块化开发(一)
什么是模块化
将一组模块(及其依赖项)以正确的顺序拼接到一个文件(或一组文件)中的过程。
传统的模块化做法。
模块是实现特定功能的一组属性和方法的封装。
将模块写成一个对象,所有的模块成员都放到这个对象里面。
var module1 = new Object({
_count:0,
f1:function(){},
f2:function(){}
})
module1.f1()
module1.f2()
上面的对象可以改变里面的属性和方法,不安全
var module1 = (function(){
var count=0;
return {
f1:function(){},
f2:function(){}}
}());
module1.f1()
module1.f2()
module1.count //undefined
使用立即执行函数 将相应的方法和属性封装在函数中,这样就不会暴露私有成员
利用构造函数封装对象
function Father (){
var arr =[];
this.add = function (val){
arr.push(val)
}
this.toString = function(){
return arr.join('');
}
}
var a = new Father();
a.add(1);//[1]
a.toString();//"1"
a.arr // undefined
上面的函数将 arr 变成私有变量,在函数外部无法访问,但是形成了闭包,非常耗费内存;
违背了构造函数与实例对象在数据上相分离的原则(即实例对象的数据,不应该保存在实例对象以外)。
function ToString() {
this._buffer = [];
}
ToString.prototype = {
constructor: ToString,
add: function (str) {
this._buffer.push(str);
},
toString: function () {
return this._buffer.join('');
}
};
虽然上面的构造函数未生成闭包,但是外部可以修改方法和属性,不安全
放大模式
如果一个模块很大或者一个模块需要继承另一个模块可以利用立即执行函数的特效来封装
var module1 = (function(m1){
mod1.col=function(){
console.log(this)
};
return mod1;
}(window.modlue2 ||{})) //有些模块可能是null 确保函数正常执行 采用兼容模式 window.modlue2 ||{}
- 独立性是模块的重要特点,模块内部最好不与程序的其他部分直接交互。
var module1 = (function ($, Swiper) {
//...
}(jQuery, Swiper));
上面的 module1 引入 jQuery 和 Swiper 当做两个参数传入模块中,保证了模块的独立性,还使得模块之间的依赖关系变得明显。
立即执行函数还可以起到命名空间的作用。
(function($, window, document) {
function go(num) {
}
function handleEvents() {
}
function initialize() {
}
function dieCarouselDie() {
}
//attach to the global scope
window.finalCarousel = {
init : initialize,
destroy : dieCarouselDie
}
}( jQuery, window, document ));
以上都有一个共同点:使用单个全局变量箭头代码包装在函数中,使用闭包建立私有空间
但是都有缺点:
- 不知道模块(库) 的加载顺序
- 还是有可能引起命名冲突,比如两个库都有相同的名称,或者使用哪个版本
有几种良好实施的方法:CommonJS、AMD和CMD。可以解决以上的缺陷
CommonJS
CommonJS是一种思想, 本质上是可复用的JavaScript,它导出特定的对象,提供其它程序使用。由于
JavaScript没有模块系统、标准库较少、缺乏包管理工具,因此CommonJS是为它的表现来制定规范。每个JavaScript 文件 都将模块存储在自己独有的作用域中。
需要使用
module.exports和exports.obj来导出对象,并在需要它的程序中使用require('module')加载
//文件1
function myModule() {
this.hello = function() {
return 'hello!';
}
this.goodbye = function() {
return 'goodbye!';
}
}
module.exports = myModule;
//文件2
var myModule = require('myModule');
var myModuleInstance = new myModule();
myModuleInstance.hello(); // 'hello!'
myModuleInstance.goodbye(); // 'goodbye!'
实现原理
var module1 = {
export1:{}
};
(function (module,exports){
exports.add = functon(val){
return val *10
}
}(module1,module1.export1));
var fn = module1.export1.add;
fn(2)//20
利用立即执行函数 接受两个参数 module 和 exports, 模块就通过立即执行函数赋值,然后导出模块,即可实现模块的加载
这种方法的好处:
- 避免全局污染
- 明确依赖项目
- 语法清晰
缺点: - 由于
CommonJS采用服务器优先方法并且同步加载模块,因此在浏览器中使用它会阻止浏览器运行其他内容,直到加载完成。
我们可以使用 AMD 来异步加载
AMD(Asynchromous Module Definition)
- 定义了一套 JavaScript 模块依赖异步加载标准,来解决同步加载的问题。
- AMD模块加载不影响后面语句的运行。所有依赖某些模块的语句均放置在回调函数中。
- 定义了一个函数
define,通过define方法定义模块。
define(['myModule', 'myOtherModule'], function(myModule, myOtherModule) {
console.log(myModule.hello());
});
上面的 define 函数将每个模块的依赖项,以数组的形式作为参数。
这些依赖项会在后台异步加载,一旦加载完成,
define函数就调用模块给出的回调函数
myModule可能像下面一样定义:
define([], function() {
return {
hello: function() {
console.log('hello');
},
goodbye: function() {
console.log('goodbye');
}
};
});
CMD(Common Module Definition)
CMD由玉伯大佬提出并用于SeaJS- CMD 和 AMD 很相似,都有 define 函数, 通过 require 加载
CMD和AMD 不同点:
- 对于依赖的模块 CMD 延迟执行, AMD 提前执行(requireJS 高版本也开始延迟执行)
- CMD使用依赖就近原则(按需加载):
define(function(require, exports, module) {
var near = require('./a')
near.doSomething()
// 此处略去 100 行
var nearOne = require('./b') // 依赖可以就近书写
nearOne.doSomething() // ...
})
- AMD使用依赖前置原则(必须先加载完依赖):
define(['./a', './b'], function(nearTow, nearThree) { // 必须一开始加载
nearTow.doSomething()
// 此处略去 100 行
nearThree.doSomething()
...
})
CMD里,没有全局 require,而是根据模块系统的完备性,提供 seajs.use 来实现模块系统的加载启动。CMD 里,每个 API 都简单纯粹。AMD的 API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。比如 AMD 里,require 分全局 require 和局部 require,都叫 require。
AMD 和 CommonJS 不同点:
AMD:
- 采用浏览器优先的方法,异步加载,主要用于浏览器
- 先加载依赖项
- 依赖项可以说 对象、函数、构造函数、字符串等等其他JS类型
CommonJS:
- 采用服务器优先的方法,同步加载,主要用于服务器
- 支持对象作为模块
共同点: 先加载依赖项
通用模块定义 UMD
同时支持
AMD和CommonJS
本质 创建了一种方法来使用两者的任何一种,同时支持全局变量定义,(JS兼容性的常用思想)所以UMD可以在客户端和服务器上工作
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['myModule', 'myOtherModule'], factory);
} else if (typeof exports === 'object') {
// CommonJS
module.exports = factory(require('myModule'),
require('myOtherModule'));
} else {
root.returnExports = factory(root.myModule, root.myOtherModule);
}
}(this, function (myModule, myOtherModule) {
function notHelloOrGoodbye(){};
function hello(){};
function goodbye(){};
return {
hello: hello,
goodbye: goodbye
}
}));
ES6模块(即 ES2015/ECMAScript 6、ES6)
- 使用
import关键字引入模块,通过export关键字导出模块 - ES6目前无法在浏览器中执行,只能通过babel将不被支持的import编译为当前受到广泛支持的 require。
//a.js
export let cun =1;
export function add() {
cun++;
}
//----------------
import { cun, add } from './a.js';
console.log(cun); // 1
incCounter();
console.log(cun); // 2
export var fo ='a';
setTimeout(() => fo ='b',500);
import {fo} from './a.js';
console.log(fo);//'a'
setTimeout(()=> console.log(fo),500)//'b'
//ES6 输入的模块变量,只是一个“符号连接”,所以这个变量是只读的,对它进行重新赋值会报错。
fo = 's' //error
- ES6 模块之中,顶层的this指向undefined,即不应该在顶层代码使用this。
CommonJS、AMD和CMD相比: ES6模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。- ES6 对外接口只是一种静态定义,在代码静态解析阶段就会生成。
- ES6 module编译时输出接口(加载),输出的是值的引用。(静态编译)
- CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。
- CommonJS 模块运行时加载,输出的是一个值的拷贝。(动态编译)
一旦输出一个值,模块内部的变化就影响不到这个值。
// lib/counter.js
var counter = 1;
function increment() {
counter++;
}
function decrement() {
counter--;
}
module.exports = {
counter: counter,
increment: increment,
decrement: decrement
};
// src/main.js
var counter = require('../../lib/counter');
counter.increment();
console.log(counter.counter); // 1
javascript 模块化开发(一)的更多相关文章
- Javascript模块化开发,使用模块化脚本加载工具RequireJS,提高你代码的速度和质量。
随着前端JavaScript代码越来越重,如何组织JavaScript代码变得非常重要,好的组织方式,可以让别人和自己很好的理解代码,也便于维护和测试.模块化是一种非常好的代码组织方式,本文试着对Ja ...
- Javascript 模块化开发上线解决方案
最近又换部门了,好频繁地说...于是把这段时间搞的小工具们简单整理了一下,作了一个小的总结.这次用一个简单业务demo来向大家介绍一下Javascript模块化开发的方式和自动化合并压缩的一些自己的处 ...
- JavaScript模块化开发整理
在网上已经有很多关于模块化开发的文章了,这里还是按照自己的理解来整理一下. 随着项目文件的越来越大和需求的越来越贴近现实(我发现现在客户不如:一个领导说我要审批你们报上来的资料,系统发布以后用的还不错 ...
- Javascript模块化开发-轻巧自制
Javascript模块化开发-轻巧自制 一.前言现在javascript的流行,前端的代码越来越复杂,所以我们需要软件工程的思想来开发前端.模块化是必不可少的,这样不仅能够提高代码的可维护性.可扩展 ...
- JavaScript模块化开发的那些事
模块化开发在编程开发中是一个非常重要的概念,一个优秀的模块化项目的后期维护成本可以大大降低.本文主要介绍了JavaScript模块化开发的那些事,文中通过一个小故事比较直观地阐述了模块化开发的过程. ...
- 详解JavaScript模块化开发
什么是模块化开发? 前端开发中,起初只要在script标签中嵌入几十上百行代码就能实现一些基本的交互效果,后来js得到重视,应用也广泛起来了,jQuery,Ajax,Node.Js,MVC,MVVM等 ...
- 2.精通前端系列技术之JavaScript模块化开发 seajs(一)
在使用seajs模块化开发之前,直接在页面引用js会容易出现冲突及依赖相关的问题,具体问题如下 问题1:多人开发脚本的时候容易产生冲突(比如全局参数冲突,方法名冲突),可以使用命名空间降低冲突,不能完 ...
- JavaScript模块化开发实例
最近接触了一些JavaScript开发的例子,在这里与大家一起分享一下: 例子:当我们一个团队在写Js文件的时候,你一个人写的JS代码自己可以看懂也可以维护,但是别人想对你的JS进行扩展的话,如果都在 ...
- JavaScript模块化开发&&模块规范
在做项目的过程中通常会有一些可复用的通用性功能,之前的做法是把这个功能抽取出来独立为一个函数统一放到commonFunctions.js里面(捂脸),实现类似于snippets的代码片段收集. fun ...
- (转)详解JavaScript模块化开发
https://segmentfault.com/a/1190000000733959 什么是模块化开发? 前端开发中,起初只要在script标签中嵌入几十上百行代码就能实现一些基本的交互效果,后来j ...
随机推荐
- Java多态之向下转型
目录 Java多态之向下转型 强制类型转换 instanceof Java多态之向下转型 往期回顾:我们学习了向上转型和动态绑定的概念,可以知道在继承关系中,将一个子类对象赋值给父类的引用变量,调用父 ...
- mysql分表之水平分割
一.背景 老大安排要对某张大容量表进行分割,根据年份分割成多张表. 二.水平分割 水平拆分是指数据表行的拆分,表的行数超过百万行时,就会变慢,这时可以把一张的表的数据拆成多张表来存放. 定义规则分表后 ...
- SpringMVC的自动配置解析
https://docs.spring.io/spring-boot/docs/1.5.10.RELEASE/reference/htmlsingle/#boot-features-developin ...
- 【30天自制操作系统】day05:结构体、文字显示与 GDT/IDT 初始化
输出一个 16 行 8 列的点阵字符 void putfont8(char *vram, int xsize, int x, int y, char c, char *font) { int i; c ...
- ReactNative: 使用弹出框组件ActionSheetIOS组件
一.简介 在上一篇文章中,详细介绍了对话框组件,除此之外,React-Native系统还给开发者提供了一个弹框框组件ActionSheetIOS组件,它的弹出方式与对框框不同,它是从底部弹出,与iOS ...
- Nacos 集群部署
关于nacos 集群部署,网上的示例往往不全或不可用,而官方的教程太简单了.官方也提供了一个 docker + nacos 的伪集群的 部署示例.但毕竟是 伪, 不能实际生产使用. 全网就几乎就没有 ...
- 测试人员必备之 mysql 常用命令学习指南
1.数据库连接 1.通过命令行连接数据库 [root@localhost ~]# mysql -u root -p Enter password: 输入以上命令,回车后输入密码,回车,出现 mysql ...
- Choose the WinForms UI Type 选择 WinForms UI 类型
In this lesson, you will learn how to change the UI Type of the WinForms application. By default, th ...
- EF实体类指定部分属性不映射成数据库字段特性
添加NotMapped 特性 /// <summary> /// 用户名 /// </summary> [NotMapped] public string user_name ...
- Bootstrap4 本地编译运行
Step1. 获取Bootstrap源代码 https://github.com/twbs/bootstrap Step2. 进入目录并切换npm源 npm --registry https://re ...