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);