Node中的JavaScript
global对象
- 在浏览器中,全局对象指的就是window对象;
- Node中有两个类似却各自代表着不同含义的对象:global和process;
- 任何global对象上的属性都可以被全局访问到;
- 所有全局执行上下文中的内容都在process对象中。在浏览器中,只有一个window对象,在Node中,也只有一个process对象;
模块系统
- Javascript语言标准中并未为模块以来以及模块独立定义专门的API。通过直接引入多个模块的方式,会导致多个模块对全局命名控件的污染及命名冲突的问题。
- Node中引入了一个强大的模块系统,该模块系统有三个核心的全局对象:require、module和exports。(其实遵循的就是CommonJS的规范)
绝对和相对模块
- 绝对模块是指Node通过在其内部node_modules查找到的模块,或者Node内置的如fs这样的模块;
- 不一定非要将应用中的每一部分都作为一个单独的模块和各自单独的package.json文件,可以使用相对模块;
- 那么什么是相对模块呢?相对模块是将require指向了一个相对工作目录中的JavaScript文件。如:
module_a.js
console.log('Module A');
module_b.js
console.log('Module B');
main.js
require('./module_a');
require('./module_b');
运行结果可想而知咯。
注意:在main.js中如果是这样 require(‘module_a’);的话就会报错。原因在于它们并没有通过NPM安装,也不在node_modules目录中,而且Node自带模块中没有以此为名的模块。
暴露API
- 要让模块暴露一个API成为require调用的返回值,就要依靠module和exports这两个全局变量。其中exports就是对module.exports的引用(既然是对module.exports的引用,那么exports与module.exports当然有所不同。实际上暴露的是module.exports对象,而exports变量不过是指向了module.exports的实际内容,即exports可以添加属性,但是exports变量如果为重新赋值,那么将毫无意义,exports已经指向了其他地方。);
- 需要暴露API给外部,可以通过向全局变量exports对象添加属性,如:
module_a.js
exports.name = 'DreamBoy';
exports.age = 18;
exports.show = function() {
console.log('It is funny.');
};
main.js
var a = require('./module_a.js');
console.log(a.name);
console.log(a.age);
console.log(a.show());
当然在exports对象上逐个添加属性的方式无法满足需求时,也可以采用彻底重写module.exports的方式。如:
person.js
module.exports = Person;
function Person(name) {
this.name = name;
}
Person.prototype.talk = function() {
console.log('My name is ' + this.name);
};
那么在引用该模块的模块中,将获得一个Person对象(函数也是对象,难道不是吗?)。如:
index.js
var Person = require('./person.js');
var boy = new Person('DreamBoy');
boy.talk();
事件
*1. 在Node中,暴露了Event EmitterAPI,实现事件的监听和分发。该API上定义了on、emit以及removeListener方法。它以process.EventEmitter形式暴露出来。如:
index.js
var EventEmitter = require('events').EventEmitter, a = new EventEmitter();
a.on('event', function() {
console.log('event called');
}); // 绑定事件
a.emit('event'); // 触发事件
*2. 也可以很容易地将EventEmitter添加到自己的类中。如:
var EventEmitter = process.EventEmitter, MyClass = function() {};
MyClass.prototype.__proto__ = EventEmitter.prototype;
这样,所有MyClass的实例都具备了事件功能:
var a = new MyClass;
a.on('事件名', function() {
// 执行某一事件被触发后的操作
});
*3. 事件时Node非阻塞设计的重要体现。Node通常不会直接返回数据(因为这样 可能会在等待某个资源的时候发生线程阻塞),而是采用分发事件来传递数据的方式;
*4. 不管某个事件在将来会被触发多少次,我们都希望只调用一次回调函数。Node为这类需求提供了一个名字简洁的方法:
a.once('事件名', function() {
// 执行某一事件被触发后的操作
});
buffer
- buffer是一个表示固定内存分配的全局对象;
- 在Node.js中,绝大部分进行数据IO操作的API都用buffer来接收和返回数据。如:
var mybuffer = new Buffer('==ii1j2i3h1i23h', 'base64');
console.log(mybuffer);
require('fs').writeFile('logo.png', mybuffer);
运行代码:
$ node index
$ open logo.png
上述脚本中,从用base64表示的buffer中创建图片,显示了Node.js的logo。