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)); //20
alert(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); //red
sayColor.call(window); //red
sayColor.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 application
MYAPP.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 Accommodation
function Accommodation() {}
// Assign properties and methods to our "class" blueprint with an object literal
Accommodation.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')); //false
console.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 SuperType
SubType.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(); //29
var 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-project
cd first-project
npm 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(); // -> A
utilTool.printB(); // -> B
console.log(utilTool.pi); // -> 3.1415
delete require.cache[require.resolve('./myclass')];
- Loading a group of related modules
// group/index.js
module.exports = {
one: require('./one'),
two: require('./two')
};
// group/one.js
module.exports = function() {
console.log('one');
};
// index.js
var 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 added
a new listener was added
a new listener was added
task success
the task is complete with status success
task fail
the task is complete with status fail
有用的代码片段
console.log('__dirname:', __dirname);
console.log('__filename:', __filename);
console.time('read'); // Benchmarking
console.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.txt
Listening 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);