forked from BonsaiDen/JavaScript-Garden
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
howardchi
committed
Mar 13, 2013
1 parent
a2d2b63
commit 33a89e7
Showing
23 changed files
with
1,983 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
## `Array` 的建構函式 | ||
|
||
`Array` 的建構函式在處理參數上一直有模糊的地帶,所以建議使用 `array`的字面語法來使用 - `[]` - 來新增一個的Array | ||
|
||
[1, 2, 3]; // 結果: [1, 2, 3] | ||
new Array(1, 2, 3); // 結果: [1, 2, 3] | ||
|
||
[3]; // 結果: [3] | ||
new Array(3); // 結果: [] | ||
new Array('3') // 結果: ['3'] | ||
|
||
在上面的範例 `new Array(3)` 當只有一個參數傳入到 `Array` 的建構函數 | ||
且那個參數事宜個數字,建構函數會回傳空值 | ||
但是 `Array` 長度的屬性會變成跟那個參數一樣(以此範例來看他回傳的長度為 3) | ||
**注意** 只有他長度的屬性會被設定,整個 Array裡面的數值都不會初始化 | ||
|
||
var arr = new Array(3); | ||
arr[1]; // undefined | ||
1 in arr; // false, 數值沒有被設定進去 | ||
|
||
被設定用來當做 `Array` 的長度只有少數情況使用 | ||
先設定 `Array` 的長度可以用一下的範例來避免使用 `for loop` 的麻煩 | ||
|
||
new Array(count + 1).join(stringToRepeat); | ||
|
||
### 結語 | ||
|
||
`Array` 的建構函式需要避免,建議使用字面語法。因為他們比較簡短、也更增加閱讀性 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
## Array 迴圈和屬性 | ||
|
||
雖然在 Javascript 中 Array 都是 Objects,但是沒有好的理由要使用他 | ||
在 [`for in`](#object.forinloop) 的迴圈中。事實上有很多原因要避免使用 `for in` 在 Array 之中 | ||
|
||
> **注意:** Javascript Arrays **不是** *關連性 Arrays* | ||
> 只有 [objects](#object.general) 來管理建值的相對應關係 | ||
> Arrays 是**保持** 順序的,Objects **則沒有** | ||
因為 `for in` 迴圈會列舉所有在原型 Array 上的屬性因為他會使用[`hasOwnProperty`](#object.hasownproperty), 這會使得 Array 比原本的 `for` 迴圈慢上二十幾倍 | ||
|
||
### 迴圈 | ||
|
||
為了要達到最好的性能所以最好使用 `for` 迴圈來讀取一個 Array 裡面的數值。 | ||
|
||
var list = [1, 2, 3, 4, 5, ...... 100000000]; | ||
for(var i = 0, l = list.length; i < l; i++) { | ||
console.log(list[i]); | ||
} | ||
|
||
在上面的例子中利用 `l = list.length` 來處理 Array 的長度問題。 | ||
|
||
雖然 `length` 屬性是屬於 Array 中其中一個屬性,但是他還使有一定的性能消耗在每次循環的訪問。 | ||
近期 Javascript 使用 **may** 來解決在這上面的效率問題,但是在現在的引擎上還不一定有支援。 | ||
|
||
實際上,不使用暫存 Array 長度的方式比使用暫存的版本還要慢很多。 | ||
|
||
### `length` 的屬性 | ||
|
||
`length` 屬性中的 *getter* 直接回傳在 Array 之中的程度,而 *setter* 可以用來 **刪除** Array。 | ||
|
||
var foo = [1, 2, 3, 4, 5, 6]; | ||
foo.length = 3; | ||
foo; // [1, 2, 3] | ||
|
||
foo.length = 6; | ||
foo.push(4); | ||
foo; // [1, 2, 3, undefined, undefined, undefined, 4] | ||
|
||
在上面的例子可以看到,如果給的長度比較小他就會去刪除 Array 中的數值。如果比較大的話,他就會自己增加一些 `undefined` 的數值進去 | ||
|
||
### 結語 | ||
|
||
為了達到更好的效率,建議使用 `for` 迴圈還有暫存 `length` 的屬性。 | ||
而 `for in` 迴圈則是會讓程式中有更多的錯誤和性能問題。 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
## The `delete` Operator | ||
|
||
In short, it's *impossible* to delete global variables, functions and some other | ||
stuff in JavaScript which have a `DontDelete` attribute set. | ||
|
||
### Global code and Function code | ||
|
||
When a variable or a function is defined in a global or a [function | ||
scope](#function.scopes) it is a property of either the Activation object or | ||
the Global object. Such properties have a set of attributes, one of which is | ||
`DontDelete`. Variable and function declarations in global and function code | ||
always create properties with `DontDelete`, and therefore cannot be deleted. | ||
|
||
// global variable: | ||
var a = 1; // DontDelete is set | ||
delete a; // false | ||
a; // 1 | ||
|
||
// normal function: | ||
function f() {} // DontDelete is set | ||
delete f; // false | ||
typeof f; // "function" | ||
|
||
// reassigning doesn't help: | ||
f = 1; | ||
delete f; // false | ||
f; // 1 | ||
|
||
### Explicit properties | ||
|
||
Explicitly set properties can be deleted normally. | ||
|
||
// explicitly set property: | ||
var obj = {x: 1}; | ||
obj.y = 2; | ||
delete obj.x; // true | ||
delete obj.y; // true | ||
obj.x; // undefined | ||
obj.y; // undefined | ||
|
||
In the example above, `obj.x` and `obj.y` can be deleted because they have no | ||
`DontDelete` atribute. That's why the example below works too. | ||
|
||
// this works fine, except for IE: | ||
var GLOBAL_OBJECT = this; | ||
GLOBAL_OBJECT.a = 1; | ||
a === GLOBAL_OBJECT.a; // true - just a global var | ||
delete GLOBAL_OBJECT.a; // true | ||
GLOBAL_OBJECT.a; // undefined | ||
|
||
Here we use a trick to delete `a`. [`this`](#function.this) here refers | ||
to the Global object and we explicitly declare variable `a` as its property | ||
which allows us to delete it. | ||
|
||
IE (at least 6-8) has some bugs, so the code above doesn't work. | ||
|
||
### Function arguments and built-ins | ||
|
||
Functions' normal arguments, [`arguments` objects](#function.arguments) | ||
and built-in properties also have `DontDelete` set. | ||
|
||
// function arguments and properties: | ||
(function (x) { | ||
|
||
delete arguments; // false | ||
typeof arguments; // "object" | ||
delete x; // false | ||
x; // 1 | ||
function f(){} | ||
delete f.length; // false | ||
typeof f.length; // "number" | ||
})(1); | ||
|
||
### Host objects | ||
|
||
The behaviour of `delete` operator can be unpredictable for hosted objects. Due | ||
to the specification, host objects are allowed to implement any kind of behavior. | ||
|
||
### In conclusion | ||
|
||
The `delete` operator often has unexpected behaviour and can only be safely | ||
used to delete explicitly set properties on normal objects. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
## 為什麼不要使用 `eval` | ||
|
||
因為 `eval` 函數會在 Javascript 的區域性的區間執行那段程式碼。 | ||
|
||
var foo = 1; | ||
function test() { | ||
var foo = 2; | ||
eval('foo = 3'); | ||
return foo; | ||
} | ||
test(); // 3 | ||
foo; // 1 | ||
|
||
但是, `eval` 只接受直接的呼叫而且那個函數只能叫做 `eval`,才能在一個區段中執行。 | ||
|
||
var foo = 1; | ||
function test() { | ||
var foo = 2; | ||
var bar = eval; | ||
bar('foo = 3'); | ||
return foo; | ||
} | ||
test(); // 2 | ||
foo; // 3 | ||
|
||
所有的 `eval` 都應該去比免試用。有 99.9% 的使用情況都可以 **不必** 使用到而達到同等效果。 | ||
|
||
### 偽裝的 `eval` | ||
|
||
[定時函數](#other.timeouts) `setTimeout` 和 `setInterval` 都可以接受一個字串當做他們第一個參數。這些字串 **永遠** 都會在全域範圍內執行,因此在這種情況下 `eval` 沒有被直接的使用。 | ||
|
||
### 安全上的顧慮 | ||
|
||
`eval` 同樣有安全上的問題,因為所有的程式碼都可以被直接執行。 | ||
而他不應去執行一串未知的字串或是來自不幸任的來源。 | ||
|
||
### 結語 | ||
|
||
`eval` 應該永遠不要去只用它,任何的程式在被他執行後都有性能和安全上的考慮。如果有情況需要去使用他,他都不應該列為第一順位的解決方法。 | ||
|
||
應該有更好的方法能夠去使用,但是最好都不要去使用 `eval`。 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
## 自動插入分號 | ||
|
||
雖然 JavaScript 有 C 語言的語法,但是他不強制一定要加上分號。 | ||
所以分號可以被忽略。 | ||
|
||
Javascript 並 **不是** 一個不需要分號的語言。實際上,它需要分號來讓程式碼更容易被理解。因此 Javascript 的編譯器中遇到了缺少分號的情形,它會自動的在程式碼中插入分號。 | ||
|
||
var foo = function() { | ||
} // 編輯錯誤,因沒分號 | ||
test() | ||
|
||
這時候編譯器在編輯的時候,會自動的加上分號,然後重新編輯。 | ||
|
||
var foo = function() { | ||
}; // 沒有錯誤,編輯繼續 | ||
test() | ||
|
||
自動的加入分號是被認為 **最大** 的設計缺陷之一,因為它能改變程式碼的行為。 | ||
|
||
### 工作原理 | ||
|
||
下面的程式碼中沒有使用任何的分號,所以編譯器需要去決定在哪些地方加入分號。 | ||
|
||
(function(window, undefined) { | ||
function test(options) { | ||
log('testing!') | ||
|
||
(options.list || []).forEach(function(i) { | ||
|
||
}) | ||
|
||
options.value.test( | ||
'long string to pass here', | ||
'and another long string to pass' | ||
) | ||
|
||
return | ||
{ | ||
foo: function() {} | ||
} | ||
} | ||
window.test = test | ||
|
||
})(window) | ||
|
||
(function(window) { | ||
window.someLibrary = {} | ||
|
||
})(window) | ||
|
||
下面的程式碼是編譯器 **猜測** 的結果。 | ||
|
||
(function(window, undefined) { | ||
function test(options) { | ||
|
||
// 沒有加入分號,兩行被合併為一行 | ||
log('testing!')(options.list || []).forEach(function(i) { | ||
|
||
}); // <- 插入分號 | ||
|
||
options.value.test( | ||
'long string to pass here', | ||
'and another long string to pass' | ||
); // <- 插入分號 | ||
|
||
return; // <- 插入分號,改變了 return 的表達行為 | ||
{ // 作為另一個程式碼的處理 | ||
|
||
// 被當做一個獨立的函數來看 | ||
foo: function() {} | ||
}; // <- 插入分號 | ||
} | ||
window.test = test; // <- 插入分號 | ||
|
||
// 兩行又被合併 | ||
})(window)(function(window) { | ||
window.someLibrary = {}; // <- 插入分號 | ||
|
||
})(window); //<- 插入分號 | ||
|
||
> **注意:** 在這個範例中 Javascript 編譯器沒有正確的處理 `return` ,因為緊接的換行符號。 | ||
> 雖然這不能算是自動分號插入的錯誤,但是它是非常不樂見的效果。 | ||
編譯器在上面的程式碼中改變了原本程式碼的行為。在一些情況下,會做出 **錯誤的行為** | ||
|
||
### 前置括號 | ||
|
||
在這種前置括號的情況下,編譯器 **不會** 自動的插入分號。 | ||
|
||
log('testing!') | ||
(options.list || []).forEach(function(i) {}) | ||
|
||
上面的程式碼被編譯器轉為只有一行程式 | ||
|
||
log('testing!')(options.list || []).forEach(function(i) {}) | ||
|
||
以上的範例中 `log` 有 **很大** 的可能 **不是** 回傳一個函數。然而這個情況下會出現 `TypeError` 的錯誤或是會出現 `undefined is not a function` . | ||
|
||
### 結語 | ||
|
||
建議永遠 **不要** 忽略分號。同樣的也建議大括號應在他對應的表達式在同一行。在 `if... else...`的表達式中也是如此,不應省略大括號。 | ||
這個習慣可以不僅僅是讓你的程式更一致,也可以避免編譯器因為改變程式而出錯。 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
## `undefined` 和 `null` | ||
|
||
JavaScript 中有兩個表示空值的方式, `null` 和 `undefined` , `undefined`式比較常用的一種。 | ||
|
||
### `undefined` 的值 | ||
|
||
`undefined` 是一個值為 `undefined` 的類型。 | ||
|
||
語言中也定義了一個全域變數,它的值為 `undefined`,這個變數的被稱作 `undefined` 。 | ||
這個變數 **不是** 一個常數,也不是一個關鍵字。這表示它的值可以被輕易的覆蓋。 | ||
|
||
> **ES5 提示: ** `undefined` 在 ECMAScript 5 裡 **不再是** *可寫* 的 | ||
> 但是它的名稱還是可以被隱藏,比如說定義一個函數為 `undefined`。 | ||
這裡有一些例子會回傳 `undefined` 的值: | ||
|
||
- Accessing the (unmodified) global variable `undefined`. | ||
- Accessing a declared *but not* yet initialized variable. | ||
- Implicit returns of functions due to missing `return` statements. | ||
- `return` statements that do not explicitly return anything. | ||
- Lookups of non-existent properties. | ||
- Function parameters that do not have any explicit value passed. | ||
- Anything that has been set to the value of `undefined`. | ||
- Any expression in the form of `void(expression)` | ||
|
||
### Handling Changes to the Value of `undefined` | ||
|
||
Since the global variable `undefined` only holds a copy of the actual *value* of | ||
`undefined`, assigning a new value to it does **not** change the value of the | ||
*type* `undefined`. | ||
|
||
Still, in order to compare something against the value of `undefined`, it is | ||
necessary to retrieve the value of `undefined` first. | ||
|
||
To protect code against a possible overwritten `undefined` variable, a common | ||
technique used is to add an additional parameter to an [anonymous | ||
wrapper](#function.scopes) that gets no argument passed to it. | ||
|
||
var undefined = 123; | ||
(function(something, foo, undefined) { | ||
// undefined in the local scope does | ||
// now again refer to the value `undefined` | ||
|
||
})('Hello World', 42); | ||
|
||
Another way to achieve the same effect would be to use a declaration inside the | ||
wrapper. | ||
|
||
var undefined = 123; | ||
(function(something, foo) { | ||
var undefined; | ||
... | ||
|
||
})('Hello World', 42); | ||
|
||
The only difference here is that this version results in 4 more bytes being | ||
used in case it is minified, and there is no other `var` statement inside the | ||
anonymous wrapper. | ||
|
||
### Uses of `null` | ||
|
||
While `undefined` in the context of the JavaScript language is mostly used in | ||
the sense of a traditional *null*, the actual `null` (both a literal and a type) | ||
is more or less just another data type. | ||
|
||
It is used in some JavaScript internals (like declaring the end of the | ||
prototype chain by setting `Foo.prototype = null`), but in almost all cases, it | ||
can be replaced by `undefined`. | ||
|
||
|
Oops, something went wrong.