CHAPTER2 JavaScript概览
继承
使用
Ferret.prototype = new Animal();
来继承
重写:
Ferret.prototype.eat = function(food){
Animal.prototype.eat.call(this, food);
//ferret特有逻辑写在这里
}
这个方法的不足之处就是,如果Animal的初始化函数里面有什么操作就麻烦了,解决方案是
A: 在构造器中添加判断条件
function Animal(a){
if(a === false) return;
//初始化
}
B: 写一个新的空构造函数
function Animal(){
//consstructor stuff
}
function f(){};
f.prototype = Animal.prototype;
Ferret.prototype=new f;
防止迭代属性的时候迭代到父类属性的方法
for(var i in a){
if(a.hasOwnProperty(i)){}
}
V8
在V8里面获取所有自有键的快速方法
var a= {a:'b',c:'d'};
Object.keys(a); // ['a', 'c']
数组
检测某对象是否是数组
Array.isArray(new Array) //true
Array.isArray([]) //true
Array.isArray(null) //false
Array.isArray(arguments) //false
V8
遍历数组
// 会打印出 1, 2, 3
[1,2,3].forEach(function(v){
console.log(v);
});
过滤数组使用 filter
改变数组用map
[5, 10, 15].map(function(v){
return v * 2;
}); // 会返回 [10,20,30]
js的trim
' hello '.trim(); // 'hello'
JSON编码解码:JSON.stringify 和 JSON.parse
BIND
.bind 改变this引用
function a(){
this.hello='world';
};
var b = a.bind({hello: 'world'});
b();
__PROTO__继承,使得继承简化了
function Animal(){}
function Ferret(){}
Ferret.prototype.__proto__=Animal.prototype;
__defineGetter__
Date.protptype.__defineGetter__('ago',function(){
.....
}
CHAPTER3 阻塞与非阻塞IO
变量是公共的
nodejs共享状态的并发,也就是说一个线程会影响到另一个线程的变量,就好像所有函数外的变量都是static的感觉一样,比如
var books=[
'aaa','bbb'];
function serveBooks(){
var html='.....';
books=[];
return html;
}
运行结果为:第一次将完整的图书列表返回,第二次则返回一个空的列表非阻塞
node并发使用事件轮询,注册一个事件,随后不停的询问内核这些事件是否已经分发。(也就是说你定的时间不是绝对准确的,后面说道怎么个不准确法)。文件描述符是抽象的句柄。本质上来说,当node接受到从浏览器发来的http请求时,底层的tcp连接会分配一个文件描述符。随后,如果客户端向服务器发送数据,node就会受到该文件描述符上的通知,然后触发javascript的回调函数。
单线程
node是单线程的,也就是说事件轮询跟别的事情一样是在一个线程里面,之前提到有可能你定的时间是不准确的,现在演示一个不准确的例子
var start = Date.now();
setTimeout(function(){
console.log(Date.now() - start);
for(var i=0;i<1000000000;i++){}
},1000);
setTimeout(function()){
console.log(Date.now()-start);
},2000);
输出
1000
3738
原因就是事件轮询被js代码阻塞了。
为什么单线程+非阻塞=高并发
因为一般的语言会经常被阻塞在数据库操作,文件操作等动作上,所以才会消耗性能,造成并发量小,nodejs的方式是:“当你获取数据库响应时记得通知我”之后,node就可以继续处理其他事情了。单线程使用的堆栈看起来是同一个时间只能处理一个请求的操作,但是由于在很快的状态下,你看起来像是并发一样。
注:我个人的理解的为什么node比别的语言并发高,因为cpu本身的原理就是处理并发用的是时间片来模拟,我们都知道其实如果有3件事情,你让电脑一次只干一件事情,总时间是最快的,如果让电脑同时干,每件事情的时间会延长到超过3倍,也就是说node遵循计算机的本质,让计算机做最擅长的事情:一次只干一件事情,这样在一个时间段,比如1s内,看起来并发量就提高了
错误处理
书中使用 process.on('uncaughtException',funcion(){}); 的方式,但是我们知道其实最好是使用domain + forever的方式。
堆栈追踪
格外注意你并不知道(也无法知道)抛出的异常的回调函数是从哪个函数注册进去的。
CHAPTER4 Node中的JavaScript
global对象
浏览器中全局对象是window,setTimeout其实就是window.setTimeout , document其实就是 window.ducument。 而在node 中是这样的:
- global:和window一样任何global对象上的属性都可以被全局访问到
- process:所有全局执行上下文中的内容都在process对象中。在浏览器中只有一个window对象,在node中也只有一个process对象。举例来说,在浏览器中窗口的名字是window.name,在node中进程的名字是 process.title
实用的全局对象
setImmediate相当于 process.nextTick。nextTick可以将函数的执行时间规划到下一个事件中
console.log(1);
process.nextTick(function(){
console.log(3);
})
console.log(2);
打印出来是 123
模块系统
传统的js模块是自己来定义全局变量,这样没有规范,容易污染。 Node把这个行为规范了起来: require, module, exports
暴露API
做一个module_a.js
exports.name='john';
exports.data='something';
var privateV = 5;
exports.getPrivate=function(){
return privateV;
};
测试一下:
在module_a.js边上建一个index.js 写上
var a =require('./module_a');
console.log(a.name);
console.log(a.data);
console.log(a.getPrivate());
输出
john
something
5
exports 其实就是对 module.exports 的引用。其在默认情况下是一个对象。甚至可以直接重写exports对象person.js
module.exports=Person;
function Person(name){
this.name=name;
}
Person.prototype.talk=function(){
console.log('my name is',this.name);
};
index.js
var Person = require('./person');
var john = new Person('john');
john.talk();