如今模块化的 JavaScript 的开发越来越火热,无论是模块加载器还是优秀的 JavaScript 模块,都是层出不穷。既然这么火,肯定是有存在的理由,肯定是解决了某些实际问题。很多没接触过模块化 JavaScript 开发者不禁要问,我真的需要模块化吗,模块化相比于传统的模式有什么优势?

JavaScript 本身是没有模块化支持的,很多语言多有,就连CSS都有这样的加载方式。

@import "fed.css";

虽然因为性能问题不推荐CSS这样来进行加载,但这是一种模块化的思想,这种思想对于 JavaScript 来说很有用。幸好JavaScript是一门灵活的语言,可以通过下面这段代码来进行动态加载 JavaScript 文件。

var script = document.createElement( 'script' ),
head = document.head;

script.src = 'http://example.com/test.js';
script.async = 'async';
head.insertBefore( script, head.firstChild );

传统的加载方式必须在页面中放置一个 script 标签来进行加载。

<script type="text/javascript" src="http://example.com/test.js"></script>

更好的分离

那如果要加载多个就得放置多个 script 标签,如果是加载模块的话,拿 easy.js 来说,页面中始终只要引用 easy.js 即可,这样对于 HTML 和 JavaScript 分离很有好处,在某些场景下这个分离度很重要。

就拿我司的情况来说吧。后端的 view 层并不是由我们前端来开发的,项目上线的时候,前端只能更新 CSS 和 JS 文件,HTML 文件动不了。如果前端要在该页面新增一个 JavaScript 文件的引用是很麻烦的,因为后端程序的更新都要严格按照流程来并有固定的更新时间,如果是用模块加载的方式不用再理会后端的更新。当然,你也许会说,如果原页面中已经有 JavaScript 文件,我直接在原文件中加代码不就行了,那么接下来说说直接在原文件中新增代码会碰到什么样的问题。托福改分

更好的代码组织方式

如果单个文件越来越大,维护起来出问题的几率也会越来越大,一个人开发还好,如果是多人开发,不同的代码风格,超多的业务逻辑混杂在一起,不要说维护了,光想想都蛋痛。模块式的开发,一个文件就是一个模块,控制了文件的粒度,每个模块可以专注于一个功能。正所谓一个萝卜一个坑,多人开发时,各自管好自己坑里的萝卜就行了,这也正是 OOP 的思想托福答案

按需加载

还是围绕单个文件来说事,当文件大到一定的程度,性能问题也随之而来了。合并文件是能减少请求,这是会带来性能的提升,但是当文件大到一定的体积时,此时的下载时间可能并不会比多个小文件的下载时间更短。此时就需要权衡请求数和文件体积的关系了。

单文件还有一个问题,那就是缓存是否能充分的利用好。如果一个大体积的文件内包含了超多的业务逻辑和复杂的功能,而这个文件同时又被很多页面引用到。比如在某页面,实际只用到了该文件一个很少的功能,那么其他的代码对于该页面来说就是多余的,浪费了加载流量。你或许会说,这个文件虽然大,但是它第一次加载的时候就被缓存过了,尽管在某页面只用到了极少部分的功能,但只要缓存过,加载还是挺快的。是的,如果情况有这么理想肯定是好事。但是,往往理想和现实都会有差距,如果产品的迭代更新太快,业务需求一天一个样,那么该文件就会三天两头的更新,更新可能是一个很小的功能,但是这样的更新对于刷新缓存的代价可是很大的。如果确实有这种情况,就说明这种设计确实是有问题。如果能合理的对文件进行模块化的管理,那么可以尽量减少不必要的加载,尽量减少刷新大文件的缓存带来的损失,这也需要权衡好,比如将很少更新的合并成一个文件,常更新的独立成模块。

避免命名冲突

JavaScript 本身是没有命名空间的,为了避免命名冲突,经常会使用对象和闭包的办法来避免。用对象仅仅是降低了冲突的概率而已,拿经常使用 jQuery 的开发来说,无论是往 $ 上扩展还是在 $.fn 上扩展,人多了难免会起冲突。或者用自定义的对象,搞个好几层,不光是写起来难记,这样的调用也会在性能上打折扣的。模块化就很好的解决了这个问题,在该模块内的任何形式的命名都不会再和其他模块有冲突,你想起啥名都行了。当然,你硬要在模块内部给 window 上挂一堆东西,我也没办法。

既然每个模块都是封闭式的,那么模块之间如何通信呢?接口的设计那是必须的。很简单,对于像 seajs 这种 CMD 规范的,需要使用自定义的关键字来向外部暴露一个接口。

define(function( require, exports ){
var hello = 'hello world';
// 向外部暴露该模块的接口
exports.hello = hello;
});
easy.js 遵循 AMD 规范,暴露接口更简单,直接用 return 关键词即可。

define( 'hello', function(){
var hello = 'hello world';
// 向外部暴露该模块的接口
return hello;
});
更好的依赖处理

传统的开发模式,如果 B 文件要依赖 A 文件,那么必须在 B 文件前面用 script 的形式先加载好 A 文件。如果有一天,B 文件不再需要依赖 A 文件,或者要增加依赖文件 C,那么又回到了我说的第一个问题上。如果这个 B 文件被 N 个页面在调用,而且页面还跨业务站点,那改起来简直就是噩梦啊。如果是用模块化,只需要在模块内部声明好依赖就行了,增加删除都直接修改模块即可。调用的时候也不用管该模块依赖了哪些其他模块,放心的用就是了。

好了,讲了这么多,如果你还是觉得无动于衷,要么是你接触到的项目较小,还没复杂到这个程度,要么就是我的表达能力有问题。如果你觉得还有什么需要补充的,欢迎在下面留言。

模块化的JavaScript开发的优势在哪里的更多相关文章

  1. 使用SeaJS实现模块化JavaScript开发

    前言 SeaJS是一个遵循CommonJS规范的JavaScript模块加载框架,可以实现JavaScript的模块化开发及加载机制.与jQuery等JavaScript框架不同,SeaJS不会扩展封 ...

  2. 使用SeaJS实现模块化JavaScript开发【转】

    前言 SeaJS是一个遵循CommonJS规范的JavaScript模块加载框架,可以实现JavaScript的模块化开发及加载机制.与jQuery等JavaScript框架不同,SeaJS不会扩展封 ...

  3. 浅谈模块化的JavaScript

    模块化JavaScript之风早已席卷而来, CommonJS . AMD . NodeJS .RequireJS . SeaJS . curljs  等模块化的JavaScript概念及库扑面而来, ...

  4. 拥抱模块化的JavaScript

    前言 我们再一次被计算机的名词.概念笼罩. Backbone.Emberjs.Spinejs.Batmanjs 等MVC框架侵袭而来.CommonJS.AMD.NodeJS.RequireJS.Sea ...

  5. 模块化的JavaScript

    我们再一次被计算机的名词,概念笼罩. backbone.emberjs.spinejs.batmanjs 等MVC框架侵袭而来. CommonJS.AMD.NodeJS.RequireJS.SeaJS ...

  6. 汇总一些知名的 JavaScript 开发开源项目

    汇总一些知名的 JavaScript 开发开源项目   转自:CTOLib , www.ctolib.com/topics-107352.html ggraph - 图形可视化的凌乱数据 这是一个建立 ...

  7. JavaScript开发工具简明历史

    译者按: JavaScript开发要用到的工具越来越多,越来越复杂,为什么呢?你真的弄明白了吗? 原文: Modern JavaScript Explained For Dinosaurs 为了保证可 ...

  8. Prism 4 文档 ---第4章 模块化应用程序开发

    模块化应用程序是指将一个应用程序拆分成一系列的可以组合的功能单元.一个客户端模块封装了应用程序的一部分,并且通常是一系列相关的关注点.它可以包含一个相关的组件的集合,就像用户界面,应用程序功能,和一些 ...

  9. 4: 模块化应用程序开发 Modular Application Development Using Prism Library 5.0 for WPF (英汉对照版)

    A modular application is an application that is divided into a set of loosely coupled functional uni ...

随机推荐

  1. 最快让你上手ReactiveCocoa之进阶篇

    前言 由于时间的问题,暂且只更新这么多了,后续还会持续更新本文<最快让你上手ReactiveCocoa之进阶篇>,目前只是简短的介绍了些RAC核心的一些方法,后续还需要加上MVVM+Rea ...

  2. SSH 小总

    SSH 为 struts+spring+hibernate的一个集成框架,是目前较流行的一种Web应用程序开源框架. 集成SSH框架的系统从职责上分为四层:表示层.业务逻辑层.数据持久层和域模块层,以 ...

  3. [VMware WorkStation]虚拟机网络

    桥接模式下复制物理网络连接: 复制物理网卡连接状态,就是说把你指定的.本机的.真是网卡的状态信息复制给虚拟机的虚拟网卡,比如说你的本机真是网卡链接到了家用路由器的LAN口上,获得到了DHCP分配的地址 ...

  4. 题目1049:字符串去特定字符——九度OJ

    题目1049:字符串去特定字符 http://ac.jobdu.com/problem.php?pid=1049 时间限制:1 秒 内存限制:32 兆 题目描述: 输入字符串s和字符c,要求去掉s中所 ...

  5. Linux开机执行顺序

      1. 加载 BIOS 的硬件信息,并取得第一个开机装置的代号: 2. 读取第一个开机装置的 MBR 的 boot Loader (亦即是 lilo, grub 等等) 的开机信息: 3. 加载 K ...

  6. Python第一个入门程序

    #!usr/bin/env python3 #在UNIX上,当某程序在控制台中被引用时,该文件的头两个字节先被读入.如果这两个字节是ASCII字符 #!, #shell就会认为该文件将要由解释器执行, ...

  7. Adb connect监听指定的主机和端口/Adb监听Visual Studio Emulator for Android模拟器

    语法: adb connect <host>[:<port>] 使用实例: adb connect //如果连接成功则返回 connected to 说明 在使用Visual ...

  8. 深入理解C指针之五:指针和字符串

    原文:深入理解C指针之五:指针和字符串 基础概念 字符串可以分配到内存的不同区域,通常使用指针来支持字符串操作.字符串是以ASCII字符NUL结尾的字符序列.ASCII字符NUL表示为\0.字符串通常 ...

  9. 关于oracle12c对RAW裸设备的支持?

    关于oracle12c对RAW裸设备的支持? 本文内容由ORACLE运维高级群的讨论,有xifenfei前辈提供. 12C对于裸设备的支持和11G R2没有本质区别,在装rac的时候不能使用裸设备,但 ...

  10. 项目总结二:模块管理之requireJS

    项目开发前期,对究竟用requireJS 还是sea.js 进行讨论,最后采用requireJS,但是后期遇到了问题--当谷歌地图不能加载时,整个页面卡死的状况. requirejs 的作用: 防止j ...