JavaScript有一個(gè)明顯的特征:第一類(lèi)函數(shù)(first-class functions)(wiki) 。
與第一類(lèi)函數(shù)有關(guān)的名詞還有第一類(lèi)對(duì)象和第一類(lèi)公民(頭等公民)(wiki) ,在JavaScript中,函數(shù)是第一類(lèi)對(duì)象或者說(shuō)是第一類(lèi)公民,簡(jiǎn)單理解,就是權(quán)限很大,可調(diào)用的資源多。這是因?yàn)檫@樣,它才可以被當(dāng)做參數(shù)或變量來(lái)使用。
對(duì)于異步程序和非阻塞I/O,記得在知乎上看到過(guò)一個(gè)非常好的舉例:你給圖書(shū)館打電話查書(shū),圖書(shū)館的管理員會(huì)有兩種反應(yīng),第一種:“麻煩等一下,不用掛電話,我查一下”;第二種:“知道了,等我查到了我給您回電話”。這里面的區(qū)別,一個(gè)在你,一個(gè)在電話線路。第一種情況下,你不能去干別的,只能老老實(shí)實(shí)的在電話前面等著,而且,別人在這段時(shí)間里沒(méi)法給你打電話了。第二種情況就無(wú)所謂了,你可以去high,去耍,去上廁所,其他的朋友給你打電話你也接的到。第一種情況就是同步的、阻塞的,第二種就是異步的、非阻塞的。
下面是一個(gè)nodejs的例子,創(chuàng)建一個(gè)rectangle-2.js的文件
module.exports = function(x,y,callback) {
try {
if (x < 0 || y < 0) {
throw new Error("Rectangle dimensions should be greater than zero: l = "
+ x + ", and b = " + y);
}
else
callback(null, {
perimeter: function () {
return (2*(x+y));
},
area:function () {
return (x*y);
}
});
}
catch (error) {
callback(error,null);
}
}
在創(chuàng)建一個(gè)solve-2.js的文件
var rect = require('./rectangle-2');
function solveRect(l,b) {
console.log("Solving for rectangle with l = "
+ l + " and b = " + b);
rect(l,b, function(err,rectangle) {
if (err) {
console.log(err);
}
else {
console.log("The area of a rectangle of dimensions length = "
+ l + " and breadth = " + b + " is " + rectangle.area());
console.log("The perimeter of a rectangle of dimensions length = "
+ l + " and breadth = " + b + " is " + rectangle.perimeter());
}
});
};
solveRect(2,4);
solveRect(3,5);
solveRect(-3,5);
程序是這樣運(yùn)行的,用node命令
node solve-2
- 運(yùn)行solve-2.js,rectangle-2.js文件被引用,并賦值給變量rect。
- 在最后幾行,函數(shù)solveRect被調(diào)用三次,分別賦值(2,4)、(3,5)和(-3,5),
- 在函數(shù)solveRect運(yùn)行到調(diào)用rect時(shí),也相當(dāng)于是一個(gè)賦值的過(guò)程,l賦值給rectangle-2.js文件中函數(shù)的x,b賦值給y,rect的第三個(gè)參數(shù),也就是那個(gè)匿名方程,賦值給了callback。到這里solve-2.js就運(yùn)行完了,可以該干嘛干嘛了。
- 目光放到rectangle-2.js,程序運(yùn)行,先在try里面判斷,確定符合要求之后,就運(yùn)行callback函數(shù),也就是第三步中賦值給callback的那個(gè)函數(shù),求得結(jié)果。