理解模块化和依赖管理:
- 应用一般都会依赖外部库(jQuery和AngularJs),这些库应该使用包管理器处理和更新,而不是手动下载。
- 应用本身也可以分解成为多个相互交互的小部分,学习封装代码的技能,把代码视作自成一体的组件,学习如何设计优秀的接口,如何安排接口;学习如何隐藏数据,只开放用户需要的部分。
- 如何解析依赖,避免手动维护一组有序的script标签。
封装代码
封装是为了让功能自成一体,隐藏实现的细节。任何代码,不管是函数还是模块,都要有明确的职责;隐藏实现的细节,提供简明的API一满足使用的需求。功能自成一体的代码易于理解和修改。
1).理解单一职责原则
2).信息隐藏和接口
3).作用域和this关键字
- js没有动态作用域,只有静态作用域[词法作用域]。
- 理解作用域有助于理解模块模式,模块模式是一种将代码组件化的方式。
- 函数是js的一等公民,处理方式和任何对象一样。
- 严格模式下,this的默认值是undefined,禁止使用eval和arguments等关键字。
js模块
1).闭包和模块化
- 函数也叫闭包,这是为了强调函数也会创建作用域.
- 立即调用表达式
(function(){ //新的作用域 })();
注意:这个函数放在了一堆括号中,不仅告诉了解释器我们声明了一个匿名的函数,还表明我们可以把它当作一个值使用。
- 写法1:
var api = (function(){ })(); api();
- 写法2:
var api = (function(){ window.api = {}; })();
2).原型的模块化
- 很多对象共用一个原型,使用原型能提升性能。
- 原型可以理解为js声明类的方式。
- 原型只是链接,不能覆盖属性
- 不能把原型当成类,否则会为代码的维护带来问题。
我们对作用域、作用域提升和闭包的工作方式深入了解后,引入模块之间的交互方式。
3).CommonJS模块
- 能够使用合理的方式组织代码,又能处理依赖注入。
- 是node采用的规范,用于编写模块化的js文件。
- 一个文件就是一个模块,将之赋给module.exports,作为模块的公开接口。
- 使用模块时,用require调用,参数是相对路径。
这种模块化的好处在于: 变量没有暴露在全局作用域中,也不用把代码放在闭包中。
浏览器原生并不支持CJS,使用browserify将模块编译成浏览器能够处理的形式。
使用CJS相对于原生的好处:
- 没有全局变量,认知负荷少;
- 开发API和使用模块变得简单;
- 模拟依赖的功能让测试模块变得更容易;
- 得益于browserify,能够使用npm中的包;
- 便于测试的模块化;
- 使用node时,便于客户端和服务器共享代码;
4).管理依赖
- 控制反转(Ioc): 不使用对象实例化或引用依赖,而是通过构造方法或者公开的属性把依赖值赋给对象。
- IOC框架用于解析依赖,解决处理依赖中的各种问题,这些框架的基本目的是避免使用new关键字,全部交给IOC容器处理。IOC容器知道如何实例化模块。
- RequireJS:一个异步的模块加载器(AMD),用于定义模块,指定依赖。
require(['lib/text'],function(text){ var result = text('foo bar'); console.log(result); });
说明:
按约定,lib/text对应的文件路径为lib/text.js,这是相对于本文件的路径。这段代码会请求lib/text.js文件解释其中的代码。加载完所有依赖后,调用这个模块中的函数,通过参数把依赖传入到这个模块的函数中。
‘lib/text’模块的定义如下:
define([],function(){ return function(input){ return input.toUpperCase(); } });
说明:
这个模块的定义使用了空数组,因为它没有依赖,返回的函数是模块的公共接口。
RequireJs的优点:
- 自动解析依赖图,不用在花时间排序script标签。
- 支持异步加载模块。
- 在开发过程中无需编译。
- 易于单元测试,只需加载需要测试的模块。
- 强制使用闭包,因为模块定义在一个函数中。
RequireJs的缺点:
- 如果打包代码,就无法使用异步加载功能。
- 开发需要遵守AMD规范。
- AMD的包装代码扰乱了代码。
- 在生产环境中需要编译。
- 发布环境的代码和本地环境的代码不一致。
发布优化的代码,使用gulp编译AMD模块,就不用异步获取这些模块了。
- 好在requirejs有r.js来解决这个问题
var amdOptimize = require("amd-optimize"); //require优化
5).Browserify:在浏览器中使用CJS模块.
- CJS作为AMD的替代方案而使用。
- CJS相对于AMD,更简洁,不会扰乱代码,定义模版时也不需要样板代码。
- npm中的所有包默认都支持CJS的定义的方式使用。
- Browserify会递归分析应用中所有的require()调用,然后打包这些文件。在一个script标签中引入打包好的文件就能在浏览器中使用了。
- 使用browserify编译CJS模块。