JavaScript有一個(gè)明顯的特征:第一類函數(shù)(first-class functions)(wiki) 闸衫。
與第一類函數(shù)有關(guān)的名詞還有第一類對(duì)象和第一類公民(頭等公民)(wiki) ,在JavaScript中,函數(shù)是第一類對(duì)象或者說是第一類公民级乐,簡單理解,就是權(quán)限很大睹逃,可調(diào)用的資源多亚脆。這是因?yàn)檫@樣,它才可以被當(dāng)做參數(shù)或變量來使用嘹裂。
對(duì)于異步程序和非阻塞I/O妄壶,記得在知乎上看到過一個(gè)非常好的舉例:你給圖書館打電話查書,圖書館的管理員會(huì)有兩種反應(yīng)寄狼,第一種:“麻煩等一下丁寄,不用掛電話,我查一下”泊愧;第二種:“知道了伊磺,等我查到了我給您回電話”。這里面的區(qū)別删咱,一個(gè)在你屑埋,一個(gè)在電話線路。第一種情況下痰滋,你不能去干別的摘能,只能老老實(shí)實(shí)的在電話前面等著续崖,而且,別人在這段時(shí)間里沒法給你打電話了团搞。第二種情況就無所謂了严望,你可以去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è)賦值的過程箕母,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é)果。