本人不是技术专家,该笔记只是从使用语言进行开发的层面上记录一些体会,不包含也不想尝试从源码或者更深的层次去讨论语言自己的优劣。文章内容是笔者的我的感悟,既不保证正确性,也不保证别人能看懂。html
这是该笔记的第一篇,虽然不肯定之后会不会有第二篇。node
最近不在项目里,因此打算趁此机会了解一下MEANJS架构,磕磕绊绊的配置好环境以后就尝试开始熟悉它了。学习的捷径就是模仿,这是个人我的经验,可是模仿以前总要先看明白示例代码吧,结果悲剧的发现,我被随处可见的 require, exports 和 module.exports 搞晕了,又是一通各类搜索前人经验的过程,而后终于有点明白了,特此记录下来。json
require方法按照必定的规则(规则见附录)去寻找传入的参数对应的js文件,这个文件必须为exports或者module.exports赋值,这个值会被做为require方法的返回值传递给调用者。架构
示例代码 main.js学习
'use strict'; var me = require('./module.js'); console.log(me); //Hello require!
示例代码 module.jsui
'use strict'; exports = module.exports = 'Hello require!'; // 也能够写成 exports = 'Hello require!'; // 也能够写成 module.exports = 'Hello require!'; // 可是一般仍是使用 exports = module.exports = something 这种格式
exports和module.exports有细微的区别,能够参考这篇文章《nodejs中exports与module.exports的区别》,这里很少说。this
从另外一个角度来讲,require模拟了其余语言的面向对象开发机制,咱们能够在一个文件中声明对象,而后用require来引用,只要记得在声明对象的结尾写上prototype
exports = module.exports = yourClass;
就能够了。下面是一个扩展的示例。code
//demo.js 'use strict'; var mT = require('./test.js'); var mT1 = new mT(); //此时a = 5 mT1.e(); //此时a = 6 var mT2 = new mT(); console.log(mT1.d()); //6 console.log(mT1.d()); //7 console.log(mT1.d()); //8 console.log(mT2.d()); //7 console.log(mT2.d()); //8 //test.js 'use strict'; var a = 5; var b = function(){ this.c = a; this.d = function() { this.c ++; return this.c; }; this.e = function() { a++; }; return this; }; exports = module.exports = b;
以上test.js中的b是对象的声明,a能够理解为一个静态变量,所以mT1修改了a的值以后致使mT2中c的初始值是6而再也不是5,而因为变量做用域的关系,mT1中的c的值的变化并不会对mT2中的c的值形成影响。理解这一点以后,咱们就能够自如的声明出普通对象、单件对象,以及对访问域进行区别(公开的或者受保护的),一样的也能够用来模拟抽象方法,如htm
var o = function() {}; o.prototype.getName = function() { throw "请在子类中实现该方法!"; }; var oc = function() {}; oc.prototype = new o(); oc.prototype.getName = function() { console.log('yes'); }; var t1 = new oc(); t1.getName(); // yes var t2 = new o(); t.getName(); // exception
虽然这个作法看起来很傻,可是确实能够帮到咱们。
如今,我终于能比较流畅的去阅读示例的源码了,相信这是一个好的开始。阅读源码实际上是一件颇有趣的事情,你能够先去推测做者的思路,而后看看本身是否是猜对了,若是猜对了,那么我能够节约不少时间(既然思路同样,那么具体的实现方式其实不是很重要),若是猜错了,想一下他为何这么作,补益自身。
require方法寻址规则
require(X) from module at path Y 1. If X is a core module, a. return the core module b. STOP 2. If X begins with './' or '/' or '../' a. LOAD_AS_FILE(Y + X) b. LOAD_AS_DIRECTORY(Y + X) 3. LOAD_NODE_MODULES(X, dirname(Y)) 4. THROW "not found" LOAD_AS_FILE(X) 1. If X is a file, load X as JavaScript text. STOP 2. If X.js is a file, load X.js as JavaScript text. STOP 3. If X.json is a file, parse X.json to a JavaScript Object. STOP 4. If X.node is a file, load X.node as binary addon. STOP LOAD_AS_DIRECTORY(X) 1. If X/package.json is a file, a. Parse X/package.json, and look for "main" field. b. let M = X + (json main field) c. LOAD_AS_FILE(M) 2. If X/index.js is a file, load X/index.js as JavaScript text. STOP 3. If X/index.json is a file, parse X/index.json to a JavaScript object. STOP 4. If X/index.node is a file, load X/index.node as binary addon. STOP LOAD_NODE_MODULES(X, START) 1. let DIRS=NODE_MODULES_PATHS(START) 2. for each DIR in DIRS: a. LOAD_AS_FILE(DIR/X) b. LOAD_AS_DIRECTORY(DIR/X) NODE_MODULES_PATHS(START) 1. let PARTS = path split(START) 2. let I = count of PARTS - 1 3. let DIRS = [] 4. while I >= 0, a. if PARTS[I] = "node_modules" CONTINUE c. DIR = path join(PARTS[0 .. I] + "node_modules") b. DIRS = DIRS + DIR c. let I = I - 1 5. return DIRS