MEAN 全栈工程师手札(二):启程
JavaScript NodeJS
背景知识
script元素
<script>
- 重要属性: async、defer 和 src
- 只要不存在 async 或 defer,浏览器按照其出现的先后顺序依次对其进行解析
- 无阻塞加载脚本: 参看《高性能网站建设进阶指南 - 第 4 章》,后期进行替换总结
命名
|
|
|
|
| 文件 |
filenameslikethis.js |
包 |
foo.namespaceNamesLikeThis.bar |
| 类名 |
ClassNamesLikeThis |
方法 |
methodNamesLikeThis |
| 函数 |
functionNamesLikeThis |
常量 |
CONSTANT_VALUES_LIKE_THIS |
| 枚举 |
EnumNamesLikeThis |
变量 |
variableNamesLikeThis |
Google 规范
- 每个变量声明都要加上
var关键字,否则为全局变量
- 永远不要用
const关键字来进行常量声明
- 每一语句的结尾都要加上分号
- 方法定义:
Foo.prototype.bar = function() { ... };
- 字符串: 单引号(')比双引号(")更好
- 别用
with语句
JavaScript 必知必会
垃圾收集
- 策略
- 标记清除("进入环境"变量列表 + "离开环境"变量列表)
- 引用计数
- 管理内存
- 解除引用(dereferencing): 一旦数据不再有用,最好通过将其值设置为 null 来释放其引用
引用类型
Object 类型
- 创建实例
var person = new Object(); person.name = "Nicholas";
- 对象字面量法:
var person = { name: "Nicholas", age: 29 };【向函数传递大量参数的首选方式】
- 对象属性访问:
person.name、 person["first name"] = "Nicholas"
Array 类型
- 创建实例
var colors = new Array();
- 数组字面量表示法:
var colors = ["red", "blue", "green"];
colors.length
var colors = [“red”, “blue”, “green”]; colors[99] = “black”; // 在位置 99 插入 "black"alert(colors.length); // 长度变为 100 了
- toLocalString、toString 和 valueOf
- 栈方法:
colors.push("red", "green"); colors.pop();
- 队列方法:
var item = colors.shift(); // 取得第一项、 colors.unshift("red"); // 插入
- 重排序方法:
values.sort();、 values.sort();、 values.sort(compare);
- 操作方法
colors.concat("yellow", ["black"]);、 colors.slice(1);、 colors.slice(1, 4);
var removed = colors.splice(0, 1); // 删除第一项
removed = colors.splice(1, 0, "yellow", "orange"); // 从位置 1 开始插入两项
removed = colors.splice(1, 1, "red", "purple"); // 插入亮相,删除一项
- 位置方法:
colors.indexOf(4);、 colors.lastIndexOf(4, 4);
- 迭代方法:
every()、 filter()、 forEach()、 map()、 some()
- 归并方法:
var values = [1, 2, 3, 4, 5];
var sum = values.reduce(function(prev, cur, index, array) { return prev + cur; });
alert(sum); // 15
values.reduceRight()
Date 类型
Date.parse()、 Date.UTC()
var someDate = new Date(Date.parse("May 25, 2004"));;;
var y2k = new Date(Date.UTC(2000, 0));
var allFives = new Date(2005, 4, 5, 17, 55, 55);
var start = Date.now();
toDateString()、toTimeString()、toLocaleDateString()、toLocaleTimeString()、toUTCString()
- 日期/时间组件方法:
getDate() 与 getDay()
RegExp 类型
var expression = /pattern/flags; 【g、i、m】
var patter2 = new RegExp("[bc]at", "i");
reg.test("catastrophe");
- 构造函数属性:
RegExp.input、 RegExp.lastMatch
- 实例属性:
alert(pattern1.global);
- 实例方法:
var pattern = /mom( and dad( and baby)?)?/gi;、 var matches = pattern.exec(text);
Function 类型
- 函数是对象,函数名是指针:
var sum = function(num1, num2) { return num1 + num2; };
- 没有重载(函数名是指针)
- 代码开始执行时,解析器对函数进行函数声明(后面没分号,有分号为初始化语句,如上所示)提升
alert(sum(10, 10)); function sum(num1, num2) { return num1 + num2; }
- 作为值的函数
function callSomeFunction(someFunction, someArgument){ return someFunction(someArgument);}function add10(num){ return num + 10;}var result1 = callSomeFunction(add10, 10);alert(result1); //20
- 函数内部属性
- 两个特殊的对象: arguments["callee"] 和 this(引用的是函数据以执行的环境对象)
- 函数对象的属性: caller
- 函数属性和方法:
- lenght 和 prototype
- apply() 和 call()
function sum(num1, num2){ return num1 + num2;}function callSum1(num1, num2){ return sum.apply(this, arguments); //passing in arguments object}function callSum2(num1, num2){ return sum.apply(this, [num1, num2]); //passing in array}alert(callSum1(10,10)); //20alert(callSum2(10,10)); //20
function sum(num1, num2){ return num1 + num2;} function callSum(num1, num2){ return sum.call(this, num1, num2);}alert(callSum(10,10)); //20
window.color = “red”;var o = { color: “blue” };function sayColor(){ alert(this.color);}sayColor(); //red sayColor.call(this); //redsayColor.call(window); //redsayColor.call(o); //blue
window.color = “red”;var o = { color: “blue” };function sayColor(){ alert(this.color);}var objectSayColor = sayColor.bind(o);objectSayColor(); //blue
命名空间
var com = com || {};com.apress = com.apress || {};com.apress.chapterone = com.apress.chapterone || {};com.apress.chapterone.sectionObject = { ... };var MYAPP = {}; // the container for your applicationMYAPP.stooge = { "first-name": "Joe", "last-name": "Howard"};MYAPP.flight = { airline: "Oceanic", number: 815, departure: { IATA: "SYD", time: "2004-09-22 14:55", city: "Sydney" }, arrival: { IATA: "LAX", time: "2004-09-23 10:42", city: "Los Angeles" }};
创建对象的方法
工厂模式
function createPerson(name, age, job) { var o = new Object(); // ... return o;}
构造函数模式
function Person(name, age, job) { this.name = name; // ... this.sayName = function() { alert(this.name); };}var person1 = new Person("Nicholas", 29, "Software Engineer");
原型模式(in 操作符)
// Define a constructor called Accommodationfunction Accommodation() {}// Assign properties and methods to our "class" blueprint with an object literalAccommodation.prototype = { floors: 0, rooms: 0, sharedEntrance: false, lock: function() {}, unlock: function() {}};
组合使用构造函数模式和原型模式
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.friends = [“Shelby”, “Court”];}Person.prototype = { constructor: Person, sayName : function () { alert(this.name); }};
动态原型模式
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; //methods if (typeof this.sayName != “function”){ Person.prototype.sayName = function(){ alert(this.name); }; }}
寄生构造函数模式
function SpecialArray(){ //create the array var values = new Array(); //add the values values.push.apply(values, arguments); //assign the method values.toPipedString = function(){ return this.join(“|”); }; return values; }var colors = new SpecialArray(“red”, “blue”, “green”);alert(colors.toPipedString()); //”red|blue|green”
稳妥构造函数模式
function Person(name, age, job){ //create the object to return var o = new Object(); //optional: define private variables/functions here o.sayName = function(){ alert(name); }; return o;}
解析对象
var Person = { name: "Nicholas", age: 29, job: "Software Engineer", sayName: function(){ alert(this.name); }};var person1 = new Person();var person2 = new Person();
person1.name = "Greg"; |
 |
function Person(){}var friend = new Person();Person.prototype = { constructor: Person, name : "Nicholas", age : 29, job : "Software Engineer", sayName : function () { alert(this.name); }};
friend.sayName(); //error |
 |
属性管理器
var car = {};Object.defineProperty(car, 'doors', { configurable: true, value: 4});Object.defineProperty(car, 'wheels', { configurable: false, value: 4});delete car.doors;console.log(car.doors); // => "undefined"delete car.wheels;console.log(car.wheels); // => "4"
Object.defineProperty(car, 'doors', { writable: true, configurable: true, enumerable: true, value: 4});Object.defineProperty(car, 'wheels', { writable: true, configurable: true, enumerable: true, value: 4});Object.defineProperty(car, 'trackingEnabled', { enumerable: false, value: true});for (var x in car) { // same as console.log(Object.keys(car)); console.log(x); // output: ['doors', 'wheels']}// => ["doors", "wheels", "trackingEnabled"]console.log(Object.getOwnPropertyNames(car));console.log(car.propertyIsEnumerable('trackingEnabled')); //falseconsole.log(car.trackingEnabled); //true
Object.defineProperty(car, 'wheels', { value: 4, writable: false});car.wheels = 5;console.log(car.wheels); // => 4
({ maxwidth: 600, maxheight: 400, gimmeMax: function () { return this.maxwidth + "x" + this.maxheight; }, init: function () { console.log(this.gimmeMax()); }}).init();
继承
原型链
function SuperType(){ this.colors = [“red”, “blue”, “green”];}function SubType(){}//inherit from SuperTypeSubType.prototype = new SuperType();var instance1 = new SubType();instance1.colors.push(“black”);alert(instance1.colors); //”red,blue,green,black”var instance2 = new SubType();alert(instance2.colors); //”red,blue,green,black”
借用构造函数(伪造对象或经典继承)
function SuperType() { this.colors = [“red”, “blue”, “green”];}function SubType(){ //inherit from SuperType SuperType.call(this);} var instance1 = new SubType();instance1.colors.push(“black”);alert(instance1.colors); //”red,blue,green,black”var instance2 = new SubType();alert(instance2.colors); //”red,blue,green”
组合继承
function SuperType() { this.name = name; this.colors = [“red”, “blue”, “green”];}SuperType.prototype.sayName = function(){ alert(this.name);};function SubType(name, age){ SuperType.call(this, name); this.age = age;}SubType.prototype = new SuperType();SubType.prototype.constructor = SubType;SubType.prototype.sayAge = function(){ alert(this.age);};var instance1 = new SubType(“Nicholas”, 29);instance1.colors.push(“black”);alert(instance1.colors); //”red,blue,green,black”instance1.sayName(); //”Nicholas”;instance1.sayAge(); //29var instance2 = new SubType(“Greg”, 27);alert(instance2.colors); //”red,blue,green”instance2.sayName(); //”Greg”;instance2.sayAge(); //27
原型式继承
function object(o){ function F(){} F.prototype = o; return new F();}var person = { name: “Nicholas”, friends: [“Shelby”, “Court”, “Van”]};var anotherPerson = object(person);anotherPerson.name = “Greg”;anotherPerson.friends.push(“Rob”);var yetAnotherPerson = object(person);yetAnotherPerson.name = “Linda”;yetAnotherPerson.friends.push(“Barbie”);alert(person.friends); //”Shelby,Court,Van,Rob,Barbie”
var person = { name: “Nicholas”, friends: [“Shelby”, “Court”, “Van”]};var anotherPerson = Object.create(person, { name: { value: “Greg” }});alert(anotherPerson.name); //”Greg”
寄生式继承
function createAnother(original){ var clone = object(original); //create a new object by calling a function clone.sayHi = function(){ //augment the object in some way alert(“hi”); }; return clone; //return the object}var person = { name: “Nicholas”, friends: [“Shelby”, “Court”, “Van”]};var anotherPerson = createAnother(person);anotherPerson.sayHi(); //”hi”
寄生组合式继承
function inheritPrototype(subType, superType){ var prototype = object(superType.prototype); //create object prototype.constructor = subType; //augment object subType.prototype = prototype; //assign object}function SuperType(name){ this.name = name; this.colors = [“red”, “blue”, “green”];}SuperType.prototype.sayName = function(){ alert(this.name);};function SubType(name, age){ SuperType.call(this, name); this.age = age;}inheritPrototype(SubType, SuperType);SubType.prototype.sayAge = function(){ alert(this.age);};
NodeJS 入门
创建项目
mkdir first-projectcd first-projectnpm init
必备的包
npm install -g grunt grunt-cli
npm install -g request
npm install -g express
npm install -g nodemon # restart the server when the source code change
npm install -g bower, bower install # for jquery, bootstrap, etc.
npm install -g passport passport-google
npm install -g async tamejs
npm install -g mongoose mysql redis
NodeJS 事件处理流程示例
NodeJS Module
理解 CommonJS Modules
What CommonJS actually represents is a set of specification proposals that will aim to create a standardized system of module loaders.
- Module Context
- In a module, there is a free variable “require”, which is a function.
- In a module, there is a free variable called “exports” that is an object that the module may add its API to as it executes.
Module Sample
function ABC () { this.varA = 10; this.varB = 20; this.functionA = function (var1, var2) { console.log(var1 + " " + var2); }}module.exports = ABC; var ABCClass = require('./abc');var obj = new ABCClass();obj.functionA(1, 2); // ouput: 1 2
function printA() { console.log('A');}function printB() { console.log('B');}function printC() { console.log('C');}module.exports.printA = printA;module.exports.printB = printB;module.exports.pi = Math.PI;var utilTool = require('./utiltool');utilTool.printA(); // -> AutilTool.printB(); // -> Bconsole.log(utilTool.pi); // -> 3.1415
delete require.cache[require.resolve('./myclass')];
- Loading a group of related modules
// group/index.jsmodule.exports = { one: require('./one'), two: require('./two')};// group/one.jsmodule.exports = function() { console.log('one');};// index.jsvar group = require('./group');group.one();group.two();

NodeJS 核心模块
- http
http.createServer()
http.listen()
http.createClient(): is a client and makes requests to other servers
http.ServerRequest(): passes incoming requests to request handlers
data: emitted when a part of the message body is received
end: emitted exactly once for each request
request.method(): the request method as a string
request.url(): request URL string
http.ServerResponse(): creates this object internally by an HTTP server — not by the user— and is used as an output of request handlers
response.writeHead(): sends a response header to the request
response.write(): sends a response body
response.end(): sends and ends a response body
- util
util.inspect(): returns a string representation of an object, which is useful for debugging
- querystring
querystring.stringify(): serializes an object to a query string
querystring.parse(): deserializes a query string to an object
- url
parse(): takes a URL string and returns an object
- fs
fs.readFile(): reads files asynchronously
fs.writeFile(): writes data to files asynchronously
基本工具模块
- Crypto: has randomizer, MD5, HMAC-SHA1, and other algorithms
- Path: handles system paths
- String decoder: decodes to and from buffer and string types
NodeJS 基本示例
命令行
const fs = require('fs') , filename = process.argv[2];if (!filename) { throw Error("A file to watch must be specified!");}fs.watch(filename, function() { console.log("File " + filename + " just changed!");});console.log("Now watching " + filename + " for changes...");
var child_process = require('child_process');var exec = child_process.exec;exec('ls', function(err, stdout, stderr) { // ...});var spawn = require('child_process').spawn;var child = spawn('tail', ['-f', '/var/log/system.log']);child.stdout.on('data', function(data) { console.log('tail output: ' + data);});child.stderr.on('data', function(data) { console.log('tail error output:', data);});
读写
var fs = require('fs');var path = require('path');fs.readFile(path.join(__dirname, '/data/customers.csv'), {encoding: 'utf-8'}, function (err, data) { if (err) throw err; console.log(data);});const fs = require('fs'),data = fs.readFileSync('target.txt'); // data = fs.readFileSync('target.txt', 'utf8');process.stdout.write(data.toString());
var fs = require('fs');fs.writeFile('message.txt', 'Hello World!', function (err) { if (err) throw err; console.log('Writing is done.');});try { fs.writeFileSync('./doesnotexist/newfile.txt', 'content');} catch(err) { console.log('unable to create a file in a non existent sub directory'); console.log(err);}fs.appendFile('write.txt', 'More content', function(err) { if (err) { throw err; } console.log('appended');});
var fs = require('fs');fs.createReadStream('./data/customers.csv').pipe(process.stdout);
使用 Events
var events = require('events') , emitter = new events.EventEmitter();function doATask(status) { if (status === 'success') { emitter.emit('taskSuccess'); // Specific event } else if (status === 'fail') { emitter.emit('taskFail'); } emitter.emit('taskComplete', 'complete', status);}emitter.on('taskSuccess', function() { console.log('task success!');});emitter.on('taskFail', function() { console.log('task fail');});emitter.on('taskComplete', function(type, status) { console.log('the task is ', type, ' with status ', status);});setTimeout(doATask, 500, 'success');setTimeout(doATask, 1000, 'fail');// output:a new listener was addeda new listener was addeda new listener was addedtask successthe task is complete with status successtask failthe task is complete with status fail
有用的代码片段
console.log('__dirname:', __dirname);console.log('__filename:', __filename);console.time('read'); // Benchmarkingconsole.timeEnd('read');
NodeJS TCP
const fs = require('fs'), net = require('net'), filename = process.argv[2], server = net.createServer(function(connection) { console.log('Subscriber connected.'); connection.write("Now watching '" + filename + "' for changes...\n"); // watcher setup let watcher = fs.watch(filename, function() { connection.write("File '" + filename + "' changed: " + Date.now() + "\n"); }); // cleanup connection.on('close', function() { console.log('Subscriber disconnected.'); watcher.close(); }); });if (!filename) { throw Error('No target filename was specified.');}server.listen(5432, function() { console.log('Listening for subscribers...');});
$ node --harmony net-watcher.js target.txtListening for subscribers...
Chat Room 示例
# package.json{ "name": "tcp-chat" , "description": "Our first TCP server" , "version": “0.0.1"}
var net = require('net')var server = net.createServer(function (conn) { var count = 0 , users = {} conn.setEncoding('utf8'); var nickname; conn.write( '\n > welcome to \033[92mnode-chat\033[39m!' + '\n > ' + count + ' other people are connected at this time.' + '\n > please write your name and press enter: ' ); count++; conn.on('data', function (data) { broadcast('\033[90m > ' + nickname + ' joined the room\033[39m\n'); // . . . broadcast('\033[96m > ' + nickname + ':\033[39m ' + data + '\n', true); }); conn.on('close', function () { count--; broadcast('\033[90m > ' + nickname + ' left the room\033[39m\n'); delete users[nickname]; }); function broadcast (msg, exceptMyself) { for (var i in users) { if (!exceptMyself || i != nickname) { users[i].write(msg); } } }});server.listen(3000, function () { console.log('\033[96m server listening on *:3000\033[39m');});
NodeJS HTTP
var http = require('http');var urlOpts = {host: 'www.nodejs.org', path: '/', port: '80'};if (process.argv[2]) { if (!process.argv[2].match('http://')) { process.argv[2] = 'http://' + process.argv[2]; } urlOpts = url.parse(process.argv[2]);}http.get(urlOpts, function (response) { response.on('data', function (chunk) { console.log(chunk.toString()); });}).on('error', function (e) { console.log('error:' + e.message);});
var http = require('http');var urlOpts = { host: 'market.finance.sina.com.cn', path: '/downxls.php?date=2014-07-11&symbol=sz002024', port: '80' };http.get(urlOpts, function (response) { response.on('data', function (chunk) { console.log(chunk.toString()); });});
var http = require('http');http.createServer(function (request, response) { response.writeHead(200, {'Content-Type': 'text/html'}); response.end('Woohoo!');}).listen(8080);
var http = require('http');var form = require('fs').readFileSync('form.html');http.createServer(function (request, response) { if (request.method === "POST") { var postData = ''; request.on('data', function (chunk) { postData += chunk; }).on('end', function() { console.log('User Posted:\n' + postData); response.end('You Posted:\n' + postData); });}}).listen(8080);