• javascript模块化


    模块化的意义:

    • 组件的复用,降低开发成本和维护成本
    • 组件单独开发,方便分工合作
    • 模块化遵循标准,方便自动化依赖管理,代码优化,部署

    1.模块化标准

    ES6之前,JavaScript并没有原生的模块机制,好在JavaScript非常灵活,有很多种写法可以将代码天然隔离,起到模块化的功能:

      	//define
      	var modules = {}  
      	modules.mod1 = {  
    		foo : function(){...},
    		bar : function(){...}
    		...
      	}
      	//call
      	modules.mod1.foo()

    在客户端这种方式基本是够用的,然而问题依然存在:你无法管理依赖,所有的代码都必须load到内存中,需要哪些模块必须由人工处理。分模块是工程化的产物,也是自然发展的结果,自然有很多尝试。很显然,模块之间互相依赖需要编写模块的时候遵循一定的规范。现存的规范还真不少,不知道ES6 能否终结这场混战:

    • AMD
    • CMD
    • closure
    • CommonJS
    • ES6

    AMD和CMD分别是requireJS和seaJS定义的标准。使用纯原生的ES5语法意味者其只能使用闭包,书写和阅读都很怪异。值得一提的是AngularJS也使用类似的方式,以至于Angular的作者们都受不了,决定在AngularJS 2 使用新的语言AtScript,前端轮子太多,又造了一个,好在这个轮子造的比较好,兼容ES6 TypeScript规范,扯的远了,看看AMD长得啥样:

    AMD:

      	define(['./a', './b'], function(a, b) {  
    		...
      	})

    Closure是google出品的前端工具,Closure提供了一系列工具和库,谷歌自己的多个项目都是使用Closure开发的。closure compiler通过模块间依赖的声明把所有被依赖的文件打包到一起,而且Closure的一大优势是如果采用破坏性压缩(ADVANCED)压缩率极高。

      	//文件A
      	goog.provide('module1')  
      	com.foo.bar = {  
    	 	...
      	}
      	....
      	
      	//文件B
      	goog.require('module1')  
      	var a = com.foo.bar;

    然而Closure并不完美,不同的文件共享同一个全局对象,所以你不得不这样写 a.b.c=…。

    CommonJS是Node.js使用的模块化标准。Node.js对于前端开发者来说不仅仅可以提供一个Server,还是一个完美的开发平台,在Node上使用Grunt/gulp构建web项目是件很爽的事情。Node的模块化声明的方式与Closure类似,只是更进一步,天然隔离了命名空间。上面的代码如果使用CommonJS的模块化规范可以这么写:

      	//文件A
      	module.exports = {...}  
      	....
      	
      	//文件B
      	var a = require('./foo/bar')

    browserify让使用CommonJS模块化规范的代码可以运行在客户端上。

    2.静态加载与动态加载

    在看ES6之前我们先看模块加载的两种方式:

    • 静态加载:在编译阶段进行,把所有需要的依赖打包到一个文件中
    • 动态加载:在运行时加载依赖

    AMD标准是动态加载的代表,而CommonJS是静态加载的代表。AMD的目的是用在浏览器上,所以是异步加载的。而NodeJS是运行在服务器上的,同步加载的方式显然更容易被人接收,所以使用了CommonJS。同样的道理,如果静态加载,那就使用同步的加载方式,如果动态加载就必须用异步的加载方式。

    那么ES6采用何种加载机制?

    ES6既希望用简单的声明方式来完成静态加载,又不愿放弃动态加载的特性,而这两种方式几乎不可能简单的同时实现,所以ES6提供了两种独立的模块加载方法。

    2.1 声明的方式

      	import {foo} from module1  

    2.2 通过System.import API的方式

      	System.import('some_module')  
    	  	.then(some_module => {
    		  	// Use some_module
    	  	})
    	  	.catch(error => {
    		  	...
    	  	});

    再看下export的语法,与CommonJS很像,只不过没有了module这个对象,而直接调用export。 可以export任何一个 函数,变量,对象

      	//expt.js
      	export function abc(){}//export 一个命名的function  
      	export default function(){} //export default function  
      	export num=123 //export 一个数值  
      	export obj={}  
      	export { obj as default };
      	
      	//import
      	import expt from 'expt'//default export  
      	import {default as myModule} from 'expt' //rename  
      	import {abc,num,obj} from 'expt'

    更多细节可以看这篇文章:http://www.2ality.com/2014/09/es6-modules-final.html

    目前来看,使用预编译的方式显然要好于使用动态加载,浏览器对ES6语法支持还很差,如果使用动态加载ES6,在浏览器端要做ES6到ES5的翻译工作,这个显然是重复低效的。但是随着浏览器对ES6支持增强,尤其是浏览器实现了动态加载API后,动态加载的优势就会展现:

    • 更流畅的用户体验,动态加载可以实现类似lazyload的加载方式,将download的时间分散
    • 更简洁的项目,无需预编译,项目可以少配置很多工具
    • HTTP/2的普及更倾向于使用多个小的请求,适合动态加载
  • 相关阅读:
    (CVE-2020-1938)Apache Tomcat AJP文件包含漏洞复现
    Linux rm 反向删除/排除制定文件(夹)
    Linux下JDK安装及配置 (tar.gz版)
    Linux内核源码分析 -- 同步原语 -- 互斥锁 mutex(未完成)
    Linux内核源码分析 -- 同步原语 -- 自旋锁 spinlock
    Linux内核源码分析 -- 同步原语 -- 信号量 semaphore
    Linux 内核源码分析 -- getuid, geteuid
    Linux 内核源码分析 -- chroot
    手动模拟 Linux 内核 mmu 内存寻址
    glibc-free-_int_free
  • 原文地址:https://www.cnblogs.com/leeSmile/p/9008764.html
Copyright © 2020-2023  润新知