更新記錄
item | note |
---|---|
20160815 | 第一版 |
目錄
- Chapter2
- Chapter2 命名慣例
- Chapter2 Variable Hoisting
- Chapter3 物件實体
- Chapter4 函數(待增加)
- Chapter5 物件建立模式(待增加)
- Chapter6 程式碼重用模式(待增加)
- Chapter7 設計模式(待增加)
- Chapter8 DOM和劉覽器的模式(待增加)
- 參考
Chapter2
永遠使用var來宣告變數
建議方式
1
2
3
4
5function sum(x,y){
//定義result為區域變數
var result = x + y;
return result;
}不建議方式
1
2
3
4
5function sum(x,y){
//有可能使用到全域變數result
result = x + y;
return result;
}
變數var
- 用var定義全域變不可以刪除
不使用var定義全域變數(即不小心在函數中產生)可以刪除
範例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15$ cat test-var.js
var g_var = 1;
g_novar = 2;
(function (){
g_fromfunc = 3;
}());
console.log(delete g_var);
console.log(delete g_novar);
console.log(delete g_fromfunc);
console.log(typeof g_var);
console.log(typeof g_novar);
console.log(typeof g_fromfunc);測試
1
2
3
4
5
6false
true
true
number
undefined
undefined
用單個var定義多個變數
- 用單個var定義多個變數
1
2
3
4
5
6
7
8
9
10
function func(){
var a = 1,
b = 2,
sum = a + b,
myobject = {},
i,
j;
//
}
物件實字語法
- 將物件用 { } 包起來
- 用逗號(,)分開物件內每個屬性及函數
1
2
3
4
5
6var dog = {
name: "Benji"
getName: function () {
return this.name;
}
};
避免隱含的型別轉換
JavaScript在比較時會隱含的做型別轉換
false == 0 或 “” == 0 會回傳true使用確定的比較 === , !==
1
2
3
4var zero = 0;
if ( zero === false ){
// 不會執行,因為zero是0非false
}避免隱含的型別轉換比較,除非你知道你在做什麼
1
2
3
4var zero = 0;
if ( zero == false ){
// 會執行
}
分號插入機制(semicolon insertion mechanism)
JavaScrpt允語你在行尾遺漏分號,還會自動幫你加一個
要養成左括號 { 的位置要寫在同行,避免隱含的分號
永遠應該加上分號,即便JavaScript解析器會隱含的補上正確的寫法方式
1
2
3
4
5function func() {
return {
name: "Batman"
};
}錯誤的寫法方式 : 非預期的回傳值
1
2
3
4
5
6function func() {
return
{
name: "Batman"
};
}由於隱含的分號,等同於下面的寫法
1
2
3
4
5
6function func() {
return undefined;
{
name: "Batman"
};
}
寫作習慣:空格
for中各部分的分號之後
1
2
3for ( var i = 0; i < 10; i += 1){
...
}區隔array物件的逗號之後
1
var a = [1, 2, 3];
區隔屬性名稱和值的分號之後
1
var o = {a: 1, b: 2};
函數宣告的左括號之前
1
function myFunc() {}
區隔所有的運算元和運算子
+, -, *, =, <1
2
3
4
5
6
7var d = 0,
a = b + 1;
if ( a && b && c) {
d = a % c;
a += d;
}左括號 { 之前應該加上空格,ex. 函數、if-else, loop..等
- 右括號 } 和else, while之間應該加上空格
1
2
3
4
5if (true) {
alert(1);
} else {
alert(2);
}
Chapter2 命名慣例
讓建構試為首字母大寫
- js沒有class,但有使用new引發的建構式函式
1
2
3
4
5function MyConstructor() {...}
function Person() {...}
function myFunction() {...}
var adam = new Person();
字詞的分隔方式
建構式,採用大駝峰式命名法(upper camel case)
MyConstructor()一般的函數名稱採用小駝峰式命名法(lower camerl case)
myFunction(), calculateArea(), getFirstName()非函式的變數,採用小駝峰式命名法
lastIndex, ignoreCase
其他命名模式
用全部大寫字母命名全域變數
1
2var PI = 3.14,
MAX_WIDTH = 800;用底線 _ 當成private成員
getName()表示為public
_getFirst(), _getLast()表示為private
它們雖然仍是普通的public函式,但加上低線便是提醒使用者1
2
3
4
5
6
7
8
9
10
11var person = {
getName: function () {
return this._getFirst() + ' ' + this._getLast();
}
_getFirst: function() {
...
}
_getLast: function() {
...
}
}
Chapter2 Variable Hoisting
了解變數的拉升(Variable Hoisting)
- 變數player在其中被宣告的最接近的範疇(scop)
- JavaScript不支援 block scoping
在同一個function內變數,在執行時會被拉升到function的頭
即定義var player,而在後才由程式設定值
變數只有var xx ,此時尚未define,當設定值時才會define ex. number , class , function某些程式設計師偏好,把所有的var宣告放到它們函數的頂端
等同於手動起把它們的變數拉升,以避免歧義(ambiguity)
錯誤的寫法如下
此時的player非外部傳內,而是function定義1
2
3
4
5
6
7
8
9
10
11function isWinner(player, others) {
var highest = 0;
for (var i = 0, n = other.length; i < n; i++){
var player = other[i];
if(player.score > highest){
highest = player.score;
}
}
return player.score > highest;
}變數的拉升
左邊為程式內容,右邊為實際在跑時直譯的解析方式
在function內的變數會先在頭定義,之後在設定值(此時才會define變數)
圖片來源:Effective JavaScript page 45
Variable Hoisting Example
範例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23$ cat ja-hoisting.js
function foo(){
console.log('global foo');
}
function bar(){
console.log('global bar');
}
function hoistMe(){
console.log(typeof foo);
console.log(typeof bar);
foo();
// bar();
function foo(){
console.log('local foo');
}
var bar = function(){
console.log('local bar');
};
}
hoistMe();測試
1
2
3function
undefined
local foo
單元測試
同事提供了不錯的測試範例
- 先想一下,會打印結果
再用node試一下真正的結果跟預期的是否相同
Variable Hoisting 測試一
1
2
3
4
5
6
7
8
9
10var y = 1;
function f() {
if(!y){
var y = 0;
}
console.log(y);
}
f();Variable Hoisting 測試二
1
2
3
4
5
6
7
8
9var y = 1;
function f(){
y = 0;
return;
function y(){}
}
f();
console.log(y);
Chapter3 物件實体
物件 (Creating objects)
空物件
An empty object with no properties can be created like this:1
var dog = {};
非空物件
1
2
3
4
5
6var dog = {
name: "Benji" ,
getName: function () {
return this.name;
}
}Accessing properties
1
2dog.name; // "Benji"
dog["name"]; // "Benji"物件實体語法
物件用大括號包起來 { }
用逗號分隔物件內每個屬性和函式
用逗號分隔屬性名稱和屬性值1
2
3
4
5
6
7
8
9
10
11
12
13var apple = {
type: "macintosh",
color: "red",
getInfo: function () {
return this.color + ' ' + this.type + ' apple';
}
}
apple.color = "reddish";
console.log(apple.getInfo());
$ node class.js
reddish macintosh apple
用建構式(new ..)建立物件
- 可以使用自已的建構函式建位物件,
- 或使用內建的建構式Object()、Date()、String()
建立物件方式有下例兩個方式
<1> 建議採用方式1>
1
var car = {goes: "far"};
<2> 不建議採用方式
Creates a new object by copying the values of all enumerable own properties from one or more source objects to a target object.
不要使用new Object(),應該使用較簡單而且更可靠的物件實子替代2>1
2var car = new Object();
car .goes = "far";
自訂建構式函數
$ cat chapter3-person.js
1
2
3
4
5
6
7
8
9var Person = function (name) {
this.name = name;
this.say = function () {
return "I am " + this.name;
};
}
var adm = new Person("Adam");
console.log(adm.say());$node chapter3-person.js
1
I am Adam
New建構式程序如下
- 建立空物件,參考至this變數
- 使用this加入變數及函數
- 回傳this
1
2
3
4
5
6
7
8
9var Person = function (name) {
// var this = {};
this.name = name;
this.say = function () {
return "I am " + this.name;
};
// return this;
}
如何把function加入物件原型(prototype)中
- 由於每個new Person都會建立新的say function
但皆是相同的功同,可以使用prototype功能,讓所有的
Person都參考同一個功能,減少記憶体 - 如何把say function加入Persion原型中
- $ cat chapter3-person2.js
1
2
3
4
5
6
7
8
9
10var Person = function (name) {
this.name = name;
}
Person.prototype.say = function () {
return "I am " + this.name;
}
var adm = new Person("Adam");
console.log(adm.say());