From cfcee4614eb5e6acf07e062d50fe1182798caa29 Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Tue, 22 Nov 2011 01:48:40 +0900 Subject: [PATCH 001/277] fix translate in "Clousures and References" --- doc/ja/function/closures.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ja/function/closures.md b/doc/ja/function/closures.md index 618af73f..809f906d 100644 --- a/doc/ja/function/closures.md +++ b/doc/ja/function/closures.md @@ -1,6 +1,6 @@ ## クロージャと参照 -JavaScriptの一番パワフルな特徴の一つとして*クロージャ*が使える事が挙げられます。これはスコープが**いつも**外部に定義されたスコープにアクセスできるという事です。JavaScriptの唯一のスコープは[関数スコープ](#function.scopes)ですが、全ての関数は標準でクロージャとして振る舞います。 +JavaScriptの一番パワフルな特徴の一つとして*クロージャ*が使える事が挙げられます。これはスコープが自身の定義されている外側のスコープに**いつでも**アクセスできるという事です。JavaScriptの唯一のスコープは[関数スコープ](#function.scopes)ですが、全ての関数は標準でクロージャとして振る舞います。 ### プライベート変数をエミュレートする From f14a45621a017e69a88fcb4f6c698e9d7265685e Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Tue, 22 Nov 2011 01:57:24 +0900 Subject: [PATCH 002/277] fix translate in "Avoiding the Reference Problem" --- doc/ja/function/closures.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ja/function/closures.md b/doc/ja/function/closures.md index 809f906d..ed06014b 100644 --- a/doc/ja/function/closures.md +++ b/doc/ja/function/closures.md @@ -66,7 +66,7 @@ JavaScriptでは、スコープ自体を参照・代入する事が出来無い `e`を参照している`setTimeout`を受け取った匿名関数はループによって値が変わる事が**ありません**。 -他にこのような事を実現する方法があります。それは匿名ラッパーから関数を返してあげる事です。これは上記のコードと同じような効果があります。 +他にこのような事を実現する方法があります。それは匿名ラッパーから関数を返してあげる事です。これは上記のコードと同じ振る舞いをします。 for(var i = 0; i < 10; i++) { setTimeout((function(e) { From 9f67e37d9b4fb5d2d84f4808fe960e92323cac52 Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Tue, 22 Nov 2011 02:03:42 +0900 Subject: [PATCH 003/277] fix strong range --- doc/ja/function/closures.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ja/function/closures.md b/doc/ja/function/closures.md index ed06014b..b17f6eb3 100644 --- a/doc/ja/function/closures.md +++ b/doc/ja/function/closures.md @@ -64,7 +64,7 @@ JavaScriptでは、スコープ自体を参照・代入する事が出来無い 外部の匿名関数は`i`を即座に第一引数として呼び出し、引数`e`を`i`の**値**のコピーとして受け取ります。 -`e`を参照している`setTimeout`を受け取った匿名関数はループによって値が変わる事が**ありません**。 +`e`を参照している`setTimeout`を受け取った匿名関数はループによって値が変わる事が**ありません。** 他にこのような事を実現する方法があります。それは匿名ラッパーから関数を返してあげる事です。これは上記のコードと同じ振る舞いをします。 From 3e1802b5448a1bcd22fbe03597a0bc7d532808e2 Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Tue, 22 Nov 2011 02:28:57 +0900 Subject: [PATCH 004/277] fix translate "Constructors" --- doc/ja/function/constructors.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/ja/function/constructors.md b/doc/ja/function/constructors.md index 99290411..4d0728a1 100644 --- a/doc/ja/function/constructors.md +++ b/doc/ja/function/constructors.md @@ -18,7 +18,7 @@ JavaScriptのコンストラクタは色々ある他のプログラム言語と 上記で`Foo`はコンストラクタとして呼び出され、`Foo.prototype`として新規に生成された`prototype`を設定されています。 -明示的に`return`ステートメントがある場合、`Object`の値を返す**だけでなく**関数はこのステートメントを返します。 +明示的に`return`ステートメントがある場合、関数は返り値が`Object`である場合に**限り**ステートメントで明示した値を返します。 function Bar() { return 2; @@ -64,16 +64,16 @@ JavaScriptのコンストラクタは色々ある他のプログラム言語と `Bar`で呼び出されたものは両方とも全く同じものものになります。これには、`method`と呼ばれるプロパティを持ったオブジェクトが新しく生成されますが、これは[クロージャ](#function.closures)です。 -また、注意する点として呼び出された`new Bar()`は返ってきたオブジェクトのプロトタイプに影響**しません**。プロトタイプが新しく生成されたオブジェクトにセットされるまで、`Bar`は絶対に新しいオブジェクトを返さないのです。 +また、注意する点として呼び出された`new Bar()`は返ってきたオブジェクトのプロトタイプに影響**しません**。プロトタイプは新しく生成されたオブジェクトにセットされはしますが、`Bar`は絶対にその新しいオブジェクトを返さないのです。 上記の例では、`new`キーワードの使用の有無は機能的に違いがありません。 ### ファクトリーとして新しくオブジェクトを作成する -大半の場合に推奨されるのは、`new`の付け忘れによるバグを引き起こしやすいので使用**しない**事です。 +多くの場合に推奨される事として、`new`の付け忘れによるバグを引き起こしやすいので、`new`を使用**しない**ようにするという事があります。 -新しいオブジェクトを作成するためにファクトリーを使用するか、そのファクトリー内部に新しいオブジェクトを構築する必要があります。 +新しいオブジェクトを作成するためにファクトリーを使用して、そのファクトリー内部に新しいオブジェクトを作成すべきだという事です。 function Foo() { var obj = {}; @@ -98,6 +98,6 @@ JavaScriptのコンストラクタは色々ある他のプログラム言語と ### 終わりに -`new`キーワードが省略される事により、バグの可能性がもたらされますがプロトタイプを使わない確実な理由には**なりません**。最終的には、アプリケーションの必要性により、どちらの解決法がより良いかが決まってきます。特に大切なのは、オブジェクトの作成に特定のスタイルを選ぶ事、また**そのスタイルに固執する事**です。 +`new`キーワードが省略される事によりバグの可能性がもたらされますが、それによりプロトタイプを全く使わないという確かな理由には**なりません**。最終的には、アプリケーションの必要性により、どちらの解決法がより良いかが決まってきます。特に大切なのは、オブジェクトの作成に特定のスタイルを選ぶ事、また**そのスタイルに固執する事**です。 From 2499aed2a385d97720ab012c4d1d587fe7d03754 Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Sun, 27 Nov 2011 21:24:49 +0900 Subject: [PATCH 005/277] fix translateion in "prototype" --- doc/ja/object/prototype.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/ja/object/prototype.md b/doc/ja/object/prototype.md index eb37cc39..c188ce85 100644 --- a/doc/ja/object/prototype.md +++ b/doc/ja/object/prototype.md @@ -39,7 +39,7 @@ JavaScriptはプロトタイプベースが採用されている唯一の広範 Object.prototype { toString: ... /* その他 */ } -上記では`test`は`Bar.prototype`と`Foo.prototype`の2つのオブジェクトより継承されます。その為`Foo`の中で設定された`method`関数にアクセスできるようになります。また、`Foo`のプロトタイプとしてのインスタンス**それ自体**の`value`プロパティにもアクセスが可能です。`new Bar()`は`Foo`のインスタンスを新しく作ら**ない**という事は非常に注目されるべき点ですが、それ自身のプロトタイプを再利用しています。従って全ての`Bar`インスタンスは**同じ**`value`プロパティを共有します。 +上記では`test`は`Bar.prototype`と`Foo.prototype`の2つのオブジェクトより継承されます。その為`Foo`の中で設定された`method`関数にアクセスできるようになります。また、`Foo`のプロトタイプとしてのインスタンス**それ自体**の`value`プロパティにもアクセスが可能です。`new Bar()`は`Foo`のインスタンスを新しく作**りません**が、プロトタイプに割り合てられた`Foo`インスタンスを再利用している事は注目に値します。従って全ての`Bar`インスタンスは**同じ**`value`プロパティを共有します。 > **注意:** `Bar.prototype = Foo`のような使い方は**しない**で下さい。`Foo`はそのプロトタイプではなく、 > 関数オブジェクト`Foo`自体を指しているからです。 @@ -54,12 +54,12 @@ JavaScriptはプロトタイプベースが採用されている唯一の広範 ### プロトタイププロパティ -プロトタイププロパティはJavaScriptの中でプロトタイプチェーンを構築する為に使われていますが、**任意**の値を代入する事も可能になっています。この時プロトタイプに代入されている値は単に無視されるだけです。 +プロトタイププロパティはJavaScriptの中でプロトタイプチェーンを構築する為に使われていますが、**任意**の値を代入する事も可能になっています。しかし、プロトタイプとしてプリミティブが代入された場合は単に無視されるだけです。 function Foo() {} Foo.prototype = 1; // 効果無し -割り当てられているオブジェクトは上記の例で示されている通りに動作し、動的にプロトタイプチェーンを作ります。 +オブジェクトの代入は上記の例のように動作し、動的にプロトタイプチェーンを作る事ができます。 ### パフォーマンス From e077114a821c9d843d5de155e33d5937acb7f86b Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Sun, 27 Nov 2011 21:27:54 +0900 Subject: [PATCH 006/277] fix translation in "for in loop" --- doc/ja/object/forinloop.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ja/object/forinloop.md b/doc/ja/object/forinloop.md index ffd6eb1c..180620be 100644 --- a/doc/ja/object/forinloop.md +++ b/doc/ja/object/forinloop.md @@ -2,7 +2,7 @@ `in`オペレーターは単に、`for in`ループの中でオブジェクトのプロパティをプロトタイプチェーンの中で繰り返し遡る為にあるものです。 -> **注意:** `for in`ループは`列挙`される属性が`false`にセットされているプロパティを反復処理**しません**。; +> **注意:** `for in`ループは`enumerable`属性が`false`にセットされているプロパティを反復処理**しません**。; > 例えば、配列の`length`プロパティなどがそれに当たります。 // Object.prototype汚染 From a55f6bef57ff8d270c84c3c3610a7692fc878286 Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Sun, 27 Nov 2011 21:41:07 +0900 Subject: [PATCH 007/277] fix translation in "general" --- doc/ja/function/general.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/doc/ja/function/general.md b/doc/ja/function/general.md index d3ce0237..a1c490b5 100644 --- a/doc/ja/function/general.md +++ b/doc/ja/function/general.md @@ -25,14 +25,13 @@ しかし、コードの実行時にのみこの割り当てがされるため、`foo`という変数は対応するコードが実行される前にデフォルト値である[undefined](#core.undefined)が代入されるのです。 -### 名前付き関数宣言 +### 名前付き関数式 -他に特殊なケースとして、命名関数があります。 +他に特殊なケースとして、名前付き関数があります。 var foo = function bar() { bar(); // 動作する } bar(); // ReferenceError -この場合の`bar`は`foo`に対して関数を割り当てるだけなので、外部スコープでは使用できません。しかし、`bar`は内部では使用できます。これはJavaScriptでは[名前解決](#function.scopes)による動作です。関数名は*いつも*関数自体のローカルスコープ内で有効になっています。 - +この場合の`bar`は`foo`に対して関数を割り当てるだけなので、外部スコープでは使用できません。しかし、`bar`は内部では使用できます。これはJavaScriptの[名前解決](#function.scopes)の方法によるもので、関数名は*いつも*関数自身のローカルスコープ内で有効になっています。 From cf2da10a43ded4d82a71172e81d5b8c4433d7445 Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Sun, 27 Nov 2011 21:47:21 +0900 Subject: [PATCH 008/277] fix translate in "clusures" --- doc/ja/function/closures.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ja/function/closures.md b/doc/ja/function/closures.md index b17f6eb3..718f84c5 100644 --- a/doc/ja/function/closures.md +++ b/doc/ja/function/closures.md @@ -32,7 +32,7 @@ JavaScriptでは、スコープ自体を参照・代入する事が出来無い count = 1337; }; -上記のコードは`Counter`のスコープ中にある変数`count`の値を変更する事は**ありません**。`foo.hack`は**その**スコープで定義されていないからです。これは*グローバル*変数`count`の作成 -またはオーバーライド- の代わりになるでしょう。 +上記のコードは`Counter`のスコープ中にある変数`count`の値を変更する事は**ありません**。`foo.hack`は**その**スコープで定義されていないからです。これは(`Counter`内の変数`count`の変更)の代わりに*グローバル*変数`count`の作成 -または上書き- する事になります。 ### ループ中のクロージャ From 07bf7e487bfa2ce0f31a27835ba590459e340b63 Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Sun, 27 Nov 2011 21:49:05 +0900 Subject: [PATCH 009/277] fix translation in "aruguments" --- doc/ja/function/arguments.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ja/function/arguments.md b/doc/ja/function/arguments.md index e1738aaf..cb0982c9 100644 --- a/doc/ja/function/arguments.md +++ b/doc/ja/function/arguments.md @@ -3,7 +3,7 @@ JavaScriptの全ての関数スコープは`arguments`と呼ばれる特別な変数にアクセスできます。この変数は関数が受け取った全ての引数を保持する変数です。 > **注意:** `arguments`が既に`var`や正式なパラメーターにより -> 関数のスコープが定義されている場合は +> 関数のスコープ内部で定義されている場合は > `arguments`オブジェクトは作られません。 `arguments`オブジェクトは`Array`では**ありません**。これは配列と同じような -`length`プロパティと名付けられています- 文法を持っていますが、`Array.prototype`を継承している訳では無いので、実際`Object`になります。 From 786c17056cc82af05b3d91ad6a2f5b6e5119118d Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Mon, 28 Nov 2011 00:42:05 +0900 Subject: [PATCH 010/277] fix transition in "scopes" --- doc/ja/function/scopes.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/ja/function/scopes.md b/doc/ja/function/scopes.md index 451140f3..f6c97854 100644 --- a/doc/ja/function/scopes.md +++ b/doc/ja/function/scopes.md @@ -27,7 +27,7 @@ JavaScriptはまた明確な名前空間を持ちません。この事は全て 上記の2つのスクリプトは同じ効果を持って**いません**。スクリプト Aは`foo`と呼ばれる変数を、*グローバル*スコープに定義しており、スクリプト Bは`foo`を*現在*のスコープで定義ています。 -再び、`var`が重大な影響を持っていない、*同じ効果*では**無い**スクリプトになります。 +繰り返しますが、この2つのスクリプトは*同じ影響*を全く持って**いない**スクリプトになります。`var`を使用しない事は重大な意味を持ちます。 // グローバルスコープ var foo = 42; @@ -38,7 +38,7 @@ JavaScriptはまた明確な名前空間を持ちません。この事は全て test(); foo; // 21 -`test`関数の中の`var`ステートメントを省略すると`foo`の値をオーバーライドします。最初の内は大した事ではないように思いますが、JavaScriptが何千行規模になると、`var`を使っていない事で恐怖とバグの追跡の困難さを招くことになります。 +`test`関数の中の`var`ステートメントを省略すると`foo`の値をオーバーライドします。最初の内は大した事ではないように思いますが、JavaScriptが何千行規模になると、`var`を使っていない事でバグの追跡が酷く困難になります。 // グローバルスコープ var items = [/* 同じリスト */]; @@ -53,7 +53,7 @@ JavaScriptはまた明確な名前空間を持ちません。この事は全て } } -外側のループは`subloop`が最初に呼ばれた後に終了します。なぜなら、`subloop`がグローバル変数`i`の値で上書きされているからです。2番目の`for`ループに`var`を使用する事によって簡単にこのエラーを回避する事ができます。`var`ステートメントは*希望する影響*を外側のスコープに与える場合を除いては、**絶対**に残してはいけません。 +外側のループは`subloop`が最初に呼ばれた後に終了します。なぜなら、`subloop`がグローバル変数`i`の値で上書きされているからです。2番目の`for`ループに`var`を使用する事によって簡単にこのエラーを回避する事ができます。*目的とする効果*を外側のスコープに与えようとしない限り、**絶対**に`var`ステートメントは省略してはいけません。 ### ローカル変数 @@ -73,11 +73,11 @@ JavaScriptのローカル変数の為の唯一のソースは[function](#functio } test(10); -`foo`と`i`は、関数`test`のスコープ内のローカル変数ですが、`bar`の割り当ては同じ名前のグローバル変数で上書きされてしまいます。 +`foo`と`i`は、関数`test`のスコープ内のローカル変数ですが、`bar`の代入は同じ名前のグローバル変数で上書きしてしまいます。 ### 巻き上げ -JavaScriptの**巻き上げ**宣言。この言葉の意味は`var`ステートメントと`function`宣言が、それらの外側のスコープに移動するというものです。 +JavaScriptは宣言を**巻き上げ**ます。これは`var`ステートメントと`function`宣言が、それらを含むスコープの一番先頭に移動するという事を意味します。 bar(); var bar = function() {}; @@ -96,7 +96,7 @@ JavaScriptの**巻き上げ**宣言。この言葉の意味は`var`ステート } } -上記のコードは何も実行されないうちに変換されてしまいます。JavaScriptは`var`ステートメントと同じように、直近で囲んでいる`function`宣言を先頭に移動させます。 +上記のコードは、実行を開始する前に変換されてしまいます。JavaScriptは`var`ステートメントと同じように、直近で囲んでいる`function`宣言を先頭に移動させます。 // varステートメントはここに移動する var bar, someValue; // 'undefined'がデフォルト @@ -121,7 +121,7 @@ JavaScriptの**巻き上げ**宣言。この言葉の意味は`var`ステート test(); -ブロックスコープの欠落はループ外の`var`ステートメントの移動だけでなく、その本体も移動させます。これはまた`if`が直感的じゃない結果になってしまいます。 +ブロックスコープの欠落は`var`ステートメントをループやボディの外に移動するだけでなく、`if`の構成を直感的ではないものにしてしまいます。 元のコードの中の`if`ステートメントは*グローバル変数*である`goo`も変更しているように見えますが、実際には -巻き上げが適用された後に- *ローカル変数*を変更しています。 From 563d23ebd386b4c95612007503fc74af9e9b1865 Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Mon, 28 Nov 2011 01:15:11 +0900 Subject: [PATCH 011/277] fix translation in "general" --- doc/ja/array/general.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/ja/array/general.md b/doc/ja/array/general.md index c9331224..521ad177 100644 --- a/doc/ja/array/general.md +++ b/doc/ja/array/general.md @@ -1,6 +1,6 @@ ## 配列の繰り返しとプロパティ -JavaScriptの配列もまたオブジェクトですので[`for in ループ`](#object.forinloop)を配列の繰り返しで使用するような理由はありません。実際、配列に`for in`を使用**しない**為の正当な理由はたくさんあります。 +JavaScriptの配列もまたオブジェクトですが、[`for in ループ`](#object.forinloop)を配列の繰り返し処理で使用することの良い理由は1つもありません。実際、配列に`for in`を使用**しない**為の正当な理由はたくさんあります。 > **注意:** JavaScriptの配列は*連想配列*では**ありません**。JavaScriptは[objects](#object.general)だけがキーバリューをマッピングするものです。 > また、連想配列は順序を**保持**しますが、オブジェクトは**保持しません**。 @@ -16,9 +16,9 @@ JavaScriptの配列もまたオブジェクトですので[`for in ループ`](# console.log(list[i]); } -上記の例では一つ余分に変数がありますが、それは配列の長さを取るための`l = list.length`の部分です。 +上記の例では1つ追加の仕掛けがありますが、それは配列の長さを取るための`l = list.length`の部分です。 -また、`length`プロパティは配列自身に定義されていますが、ループのそれぞれの繰り返しで探索する為のオーバーヘッドがまだあります。最近のJavaScriptエンジンはこのような場合に最適化する**はず**です。新しいエンジンか古いエンジンで実行されるかどうかをコードが知る方法はありません。 +また、`length`プロパティは配列自身に定義されていますが、ループ中の繰り返し毎回参照を行なうというオーバーヘッドがまだ存在します。最近のJavaScriptエンジンはこのような場合に最適化する**はず**ですが、コードが新しいエンジンで実行されるかどうか、知る方法はありません。 実際には、キャッシュを抜きにするとループの結果はキャッシュされたものに比べて、**半分だけ高速**になっています。 From 8507575343317044a2538b5a3c29b0cebe0e403b Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Mon, 28 Nov 2011 02:41:11 +0900 Subject: [PATCH 012/277] fix translation in "equality" --- doc/ja/types/equality.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ja/types/equality.md b/doc/ja/types/equality.md index ea99d187..a37828ed 100644 --- a/doc/ja/types/equality.md +++ b/doc/ja/types/equality.md @@ -1,6 +1,6 @@ ## 等価と比較 -JavaScriptはオブジェクトの値の等価の比較方法が2種類持っています。 +JavaScriptはオブジェクトの値の等価の比較方法を2種類持っています。 ### 等価演算子 From 6523453156df47c90944eb0dafb32ef8ea70c21d Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Mon, 28 Nov 2011 02:41:48 +0900 Subject: [PATCH 013/277] fix translation in "instans of" --- doc/ja/types/instanceof.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ja/types/instanceof.md b/doc/ja/types/instanceof.md index 9efd399c..82a5b80f 100644 --- a/doc/ja/types/instanceof.md +++ b/doc/ja/types/instanceof.md @@ -24,7 +24,7 @@ 'foo' instanceof String; // false 'foo' instanceof Object; // false -ここで一つ重要な事は、この`instanceof`は異なるJavaScriptのコンテキストが起源のオブジェクト(例:ブラウザの異なるウィンドウ)では、そのコンストラクタが正確に同じオブジェクトになる訳では無いので、同じオブジェクトとして動作しないという事です。 +ここで1つ重要な事は、異なるJavaScriptのコンテキスト(例えば、ブラウザの異なるウィンドウ)を元としたオブジェクトでは、コンストラクタが厳密に同じものでは無い為に`instanceof`は上手く動作しません。 ### 終わりに From d314228f454cf9c4184dda6542604f16cf52b15b Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Sat, 10 Dec 2011 01:46:31 +0900 Subject: [PATCH 014/277] fix representation in "undefined" --- doc/ja/core/undefined.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/ja/core/undefined.md b/doc/ja/core/undefined.md index 9d6949f3..e3a895c1 100644 --- a/doc/ja/core/undefined.md +++ b/doc/ja/core/undefined.md @@ -11,14 +11,14 @@ JavaScriptは`nothing`を表す2つの別個の値を持っています。`undef > **ES5での注意点:** ECMAScript 5での`undefined`は **もはや** strict modeでは *書き変えられない* > ようになっています。しかし、この名前は`undefined`という名前の関数の例に痕跡が見られるだけです。 -`undefined`が帰される時の例をいくつか挙げます。 +`undefined`が返される時の例をいくつか挙げます。 - (未定義の)グローバル変数`undefined`にアクセスした時 - `return`文が無い為に、暗黙のうちに関数が返された時 - 何も返されない`return`がある時 - 存在しないプロパティを探索する時 - 関数のパラメーターで明示的な値が何も無い時 - - 全ての`undefined`が設定された値 + - `undefined`が設定された全ての値 ### `undefined`の値に変更する処理 From 1cc24a47d1f1cb63541473be18a118258aa904ac Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Sat, 10 Dec 2011 01:56:45 +0900 Subject: [PATCH 015/277] fix translate in "others" --- doc/ja/other/timeouts.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/ja/other/timeouts.md b/doc/ja/other/timeouts.md index c1875b4f..3f5d2deb 100644 --- a/doc/ja/other/timeouts.md +++ b/doc/ja/other/timeouts.md @@ -10,7 +10,7 @@ JavaScriptは非同期なので、`setTimeout`と`setInterval`関数を使って `setTimeout`が呼ばれた時に、タイムアウトのIDと`foo`この先の**おおよそ**1000msに実行するスケジュールを返します。`foo`は正確に**1度**だけ実行されます。 -コードが実行されているJavaScriptエンジンのタイマー分解能によって決まります。この事実はJavaScriptがシングルスレッドのなので、他のスレッドでの実行を妨害してしまう事があるかもしれません。これは、`setTimeout`の呼び出しにより指定された正確なディレイで実行するという確実な賭けという**意味ではありません**。 +コードが実行されているJavaScriptエンジンのタイマー分解能によって決まります。この事実はJavaScriptがシングルスレッドのなので、他のスレッドでの実行を妨害してしまう事があるかもしれません。これは、`setTimeout`関数の呼び出しで指定した遅延時間を正確に間違いなく得られるという**意味では決してありません**。 第一パラメーターを渡された関数は*グローバルオブジェクト*によって呼び出されます。これは呼び出された関数の内部で[`this`](#functionis)がまさにこのオブジェクトを参照しているという事になります。 @@ -99,10 +99,10 @@ JavaScriptは非同期なので、`setTimeout`と`setInterval`関数を使って この場合、`eval`は[直接](#core.eval)呼ばれないので、文字列が渡された`setTimeout`は*global scope*で実行されます。よって、`bar`のスコープから`foo`のローカル変数は使われないのです。 -さらに、文字列を関数に渡さ**ない**ように推奨される理由として、それぞれのタイムアウト関数から呼び出されるという事があります。 +タイムアウト関数によって呼び出される関数を引数に渡すために文字列を使わ**ない**という事は、それ以上に推奨されています。 function foo(a, b, c) {} - + // 絶対にこのように使わない setTimeout('foo(1,2, 3)', 1000) @@ -119,7 +119,7 @@ JavaScriptは非同期なので、`setTimeout`と`setInterval`関数を使って `setTimeout`や`setInterval`のパラメーターに文字列を使用する事は**絶対**するべきではありません。引数が関数に呼び出される必要がある場合**本当**に悪いコードの明確なサインになります。実際の呼び出しには*匿名関数*を渡すべきです。 -その上で、`setInterval`の使用はそのスケジューラーがJavaScriptの実行をブロックするので避けるべきでしょう。 +さらに、`setInterval`の使用はスケジューラーがJavaScriptの実行によってブロックされないので、避けるべきでしょう。 [1]: http://en.wikipedia.org/wiki/Document_Object_Model "Document Object Model" From d4c46e6254dc13f8d474b90854f93974cc739534 Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Mon, 19 Dec 2011 02:57:25 +0900 Subject: [PATCH 016/277] fix translate in "constuctors" --- doc/ja/function/constructors.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/ja/function/constructors.md b/doc/ja/function/constructors.md index 4d0728a1..792d5fa6 100644 --- a/doc/ja/function/constructors.md +++ b/doc/ja/function/constructors.md @@ -16,7 +16,7 @@ JavaScriptのコンストラクタは色々ある他のプログラム言語と var test = new Foo(); -上記で`Foo`はコンストラクタとして呼び出され、`Foo.prototype`として新規に生成された`prototype`を設定されています。 +上記は、`Foo`をコンストラクタとして呼び出し、新規に生成されたオブジェクトの`prototype`を`Foo.prototype`に設定しています。 明示的に`return`ステートメントがある場合、関数は返り値が`Object`である場合に**限り**ステートメントで明示した値を返します。 @@ -41,7 +41,7 @@ JavaScriptのコンストラクタは色々ある他のプログラム言語と } Foo(); // undefinedが返る -上記の例では、いくつかのケースでは動作するように見える場合があります。JavaScriptの[`this`](#function.this)の働きのせいで、*グローバルオブジェクト*が`this`の値として使用されるからです。 +JavaScriptの[`this`](#function.this)の働きのせいで、上記の例ではいくつかのケースでは動作するように見える場合がありますが、それは*グローバルオブジェクト*が`this`の値として使用されるからです。 ### ファクトリー From 8d1819ef89577291d0b80fc92ff59b32edb4bf92 Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Mon, 19 Dec 2011 03:09:01 +0900 Subject: [PATCH 017/277] fix transition in "constructors" --- doc/ja/function/constructors.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ja/function/constructors.md b/doc/ja/function/constructors.md index 792d5fa6..94561c08 100644 --- a/doc/ja/function/constructors.md +++ b/doc/ja/function/constructors.md @@ -2,7 +2,7 @@ JavaScriptのコンストラクタは色々ある他のプログラム言語とは一味違います。`new`キーワードが付いているどんな関数呼び出しも、コンストラクタとして機能します。 -コンストラクタ内部では -呼び出された関数の事です- `this`の値は新規に生成された`Object`を参照しています。この**新規**のオブジェクトの[`prototype`](#object.prototype)は、コンストラクタとして起動した関数オブジェクトの`prototype`として設定されています。 +コンストラクタ内部では -呼び出された関数の事です- `this`の値は新規に生成された`Object`を参照しています。この**新規**のオブジェクトの[`prototype`](#object.prototype)は、コンストラクタとして起動した関数オブジェクトの`prototype`に設定されています。 もし呼び出された関数が、`return`ステートメントを明示していない場合は、暗黙の了解で`this`の値を -新規のオブジェクトとして- 返します。 From 887ece3ba8c12750e75c586694f305cb56e55162 Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Mon, 19 Dec 2011 03:09:50 +0900 Subject: [PATCH 018/277] fix transition in "scopes" --- doc/ja/function/scopes.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/ja/function/scopes.md b/doc/ja/function/scopes.md index f6c97854..997c6e4a 100644 --- a/doc/ja/function/scopes.md +++ b/doc/ja/function/scopes.md @@ -10,7 +10,7 @@ JavaScriptはブロックに2つのペアの中括弧を使うのが素晴しい } > **注意:** 代入が使用されてない時、return文や関数の引数、`{...}`表記はブロック文として -> 解釈されて、オブジェクトリテラルトは**なりません**。これは[セミコロン自動挿入](#core.semicolon) +> 解釈されて、オブジェクトリテラルとは**なりません**。これは[セミコロン自動挿入](#core.semicolon) > と連動して奇妙なエラーを引き起こすことになります。 JavaScriptはまた明確な名前空間を持ちません。この事は全て一つの*グローバルで共有された*名前空間で定義されるという事です。 @@ -41,7 +41,7 @@ JavaScriptはまた明確な名前空間を持ちません。この事は全て `test`関数の中の`var`ステートメントを省略すると`foo`の値をオーバーライドします。最初の内は大した事ではないように思いますが、JavaScriptが何千行規模になると、`var`を使っていない事でバグの追跡が酷く困難になります。 // グローバルスコープ - var items = [/* 同じリスト */]; + var items = [/* 何かのリスト */]; for(var i = 0; i < 10; i++) { subLoop(); } @@ -57,7 +57,7 @@ JavaScriptはまた明確な名前空間を持ちません。この事は全て ### ローカル変数 -JavaScriptのローカル変数の為の唯一のソースは[function](#function.general)パラメーターと`var`ステートメントを宣言された変数になります。 +JavaScriptのローカル変数の為の唯一の作成方法は[function](#function.general)パラメーターと`var`ステートメントによって宣言された変数になります。 // グローバルスコープ var foo = 1; @@ -73,7 +73,7 @@ JavaScriptのローカル変数の為の唯一のソースは[function](#functio } test(10); -`foo`と`i`は、関数`test`のスコープ内のローカル変数ですが、`bar`の代入は同じ名前のグローバル変数で上書きしてしまいます。 +`foo`と`i`は、関数`test`のスコープ内のローカル変数ですが、`bar`の代入は同じ名前でグローバル変数で上書きしてしまいます。 ### 巻き上げ @@ -132,7 +132,7 @@ JavaScriptは宣言を**巻き上げ**ます。これは`var`ステートメン var SomeImportantThing = {}; } -しかし、勿論上記の動きは`val`ステートメントが*グローバルスコープ*の上に移動しているという事実に基づいています。 +しかし、勿論上記の動きは`var`ステートメントが*グローバルスコープ*の上に移動しているという事実に基づいています。 var SomeImportantThing; From 92e134a23614a5547c72dfd91047d6a96aaaa2df Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Mon, 19 Dec 2011 03:17:37 +0900 Subject: [PATCH 019/277] fix transition in "scopes" --- doc/ja/function/scopes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ja/function/scopes.md b/doc/ja/function/scopes.md index 997c6e4a..ddbe08c6 100644 --- a/doc/ja/function/scopes.md +++ b/doc/ja/function/scopes.md @@ -147,7 +147,7 @@ JavaScriptは宣言を**巻き上げ**ます。これは`var`ステートメン JavaScriptの*グローバルスコープ*を含む、全てのスコープは、*現在のオブジェクト*を参照している特殊な名前[`this`](#function.this)を持っています。 -関数スコープはまた、関数を通過してきた引数を含んでいる[`arguments`](#function.arguments)という名前も持っています。 +関数スコープはまた、[`arguments`](#function.arguments)という名前も持っています。それは関数スコープの中で定義され、関数に渡された引数を含んでいます。 例として、関数の中で`foo`と命名された変数にアクセスしようとする場合を考えましょう。JavaScriptは以下の順番で、その名前を探索しようとします。 From 1db1d02590d79978b3bdd60cd80d82f36cdc267b Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Sun, 25 Dec 2011 01:20:49 +0900 Subject: [PATCH 020/277] fix translate in "General" --- doc/ja/array/general.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/ja/array/general.md b/doc/ja/array/general.md index 521ad177..0b7925dc 100644 --- a/doc/ja/array/general.md +++ b/doc/ja/array/general.md @@ -16,11 +16,11 @@ JavaScriptの配列もまたオブジェクトですが、[`for in ループ`](# console.log(list[i]); } -上記の例では1つ追加の仕掛けがありますが、それは配列の長さを取るための`l = list.length`の部分です。 +上記の例では1つ追加の仕掛けがありますが、それは`l = list.length`によって配列の長さをキャッシュする部分です。 また、`length`プロパティは配列自身に定義されていますが、ループ中の繰り返し毎回参照を行なうというオーバーヘッドがまだ存在します。最近のJavaScriptエンジンはこのような場合に最適化する**はず**ですが、コードが新しいエンジンで実行されるかどうか、知る方法はありません。 -実際には、キャッシュを抜きにするとループの結果はキャッシュされたものに比べて、**半分だけ高速**になっています。 +実際には、キャッシュを抜きにするとループの結果はキャッシュされたものに比べてたった**半分の速度**にしかなりません。 ### `length`プロパティ From 83649e4b7d733bcc35db5711c0496b58a7a89ebd Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Sun, 25 Dec 2011 01:25:10 +0900 Subject: [PATCH 021/277] fix translate "Equality" --- doc/ja/types/equality.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ja/types/equality.md b/doc/ja/types/equality.md index a37828ed..617d38af 100644 --- a/doc/ja/types/equality.md +++ b/doc/ja/types/equality.md @@ -50,7 +50,7 @@ JavaScriptは*弱い型付け*を特徴としています。これは等価演 var foo = {}; foo === foo; // true -これら2つの演算子は**同一性**と等価**ではない**事を比較しています。これは、これらの演算子はPythonの`is`演算子やCのポインター比較と同じように、同じオブジェクトの**インスタンス**を比較するという事になります。 +これら2つの演算子は**同一性**を比較していているのであって、等価を比較しているわけでは**ありません**。これは、これらの演算子はPythonの`is`演算子やCのポインター比較と同じように、同じオブジェクトの**インスタンス**を比較するという事になります。 ### 終わりに From e3704b30bf12ac3809ccc19fb65f391928d7a558 Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Sun, 25 Dec 2011 01:27:27 +0900 Subject: [PATCH 022/277] fix translate in "typeof" --- doc/ja/types/typeof.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ja/types/typeof.md b/doc/ja/types/typeof.md index 8843c368..f0a4233d 100644 --- a/doc/ja/types/typeof.md +++ b/doc/ja/types/typeof.md @@ -29,7 +29,7 @@ {} Object object new Object() Object object -上記のテーブルの*Type*は値を参照しており、`typeof`演算子が返ってきます。はっきりと分かるように、この値はどれでも一貫しています。 +上記のテーブルにおいて*Type*は`typeof`演算子が返す値を参照しています。はっきりと分かるように、この値はどれでも一貫しています。 *Class*はオブジェクト内部の`[[Class]]`プロパティの値を参照しています。 From e3ec38616696b78fe5e2d441309e0574e962587b Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Sun, 25 Dec 2011 01:29:56 +0900 Subject: [PATCH 023/277] fix translate in "typeof" --- doc/ja/types/typeof.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ja/types/typeof.md b/doc/ja/types/typeof.md index f0a4233d..a70ac820 100644 --- a/doc/ja/types/typeof.md +++ b/doc/ja/types/typeof.md @@ -55,7 +55,7 @@ > **ES5での注意点:** 便宜上、ECMAScript 5では > `Object.prototype.toString`の -> `null`と`undefined`は`Object`から +> `null`と`undefined`の返す値は`Object`から > `Null`と`Undefined`に**変更され**ました。 ### 未定義変数のテスト From 5d52cdf792c431817f13309312fef049e4b356e1 Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Sun, 25 Dec 2011 01:33:41 +0900 Subject: [PATCH 024/277] fix translte in "casting" --- doc/ja/types/casting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ja/types/casting.md b/doc/ja/types/casting.md index 44446ea1..42561de7 100644 --- a/doc/ja/types/casting.md +++ b/doc/ja/types/casting.md @@ -19,7 +19,7 @@ JavaScriptは*弱い型付け*の言語なので、可能な**限り**に*型強 > **ES5での注意点:** `0`から始まるNumberリテラルは8進数(基数が8)として解釈されます。 > このような8進数のサポートはECMAScript5のstrict modeでは**削除されました**。 -上記の自体を避ける為に、[strict equal operator](#types.equality)を使用する事を**強く**推奨します。また、これはたくさんある落し穴を避けますが、それでもまだJavaScriptの弱い型付けシステムから発生する色々な課題が残っています。 +上記の自体を避ける為に、[厳格等価演算子](#types.equality)を使用する事を**強く**推奨します。また、これはたくさんある落し穴を避けますが、それでもまだJavaScriptの弱い型付けシステムから発生する色々な課題が残っています。 ### 組み込み型のコンストラクタ From 9c87e5b8d58ab52fbd8984963fc50fb2b193a460 Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Sun, 25 Dec 2011 01:36:01 +0900 Subject: [PATCH 025/277] fix translate in "undefined" --- doc/ja/core/undefined.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ja/core/undefined.md b/doc/ja/core/undefined.md index e3a895c1..ac8761a4 100644 --- a/doc/ja/core/undefined.md +++ b/doc/ja/core/undefined.md @@ -1,6 +1,6 @@ ## `undefined`と`null` -JavaScriptは`nothing`を表す2つの別個の値を持っています。`undefined`はこれら2つの内より便利な存在です。 +JavaScriptは`nothing`を表す2つの別個の値を持っています。これら2つの内で`undefined`はより便利な存在です。 ### `undefined`の値 From 901b13f46b9127b37350620f44ef2bd8f3ad06ec Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Sun, 25 Dec 2011 01:41:29 +0900 Subject: [PATCH 026/277] fix translate in "semicolon" --- doc/ja/core/semicolon.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/ja/core/semicolon.md b/doc/ja/core/semicolon.md index f7d7c07d..72b00011 100644 --- a/doc/ja/core/semicolon.md +++ b/doc/ja/core/semicolon.md @@ -77,9 +77,10 @@ JavaScriptはセミコロン無しの言語ではありません。実際に、 })(window); //<- 挿入 -> **注意点:** JavaScriptパーサーは新しい行のreturn文を「正しく」返してはいないですが、 -> これは必要という訳では無いので自動セミコロン挿入の障害になります。 -> このお陰で不必要な副作用を無くす事にもなります。 +> **注意点:** JavaScriptパーサーは、すぐ後に改行が続く return文を正しく扱いません。 +> これは必ずしも自動セミコロン挿入の欠点によるものではありませんが、 +> それもまた望まない副作用となりえます。 + パーサーは上記のコードの振舞いを劇的に変化させます。あるケースにおいては、**間違っている事**にもなってしまいます。 @@ -98,4 +99,4 @@ JavaScriptはセミコロン無しの言語ではありません。実際に、 ### 終わりに -セミコロンを省略するのは**絶対**にお勧めしません。この事はまた括弧をその終端と一緒の行に書く事が推奨されてますし、1つの`if`や`else`文を絶対に省略してはなりません。これら両方の処理がコードの整合性を高めてくれる上、JavaScriptパーサーの振舞いを変えてしまうのを防いでくれるでしょう。 +セミコロンを省略するのは**絶対**にお勧めしません。括弧を対応する文と同じ行に記述すること、および一行の`if / else`文に対して括弧を省略しないことが推奨されています。これら両方の処理がコードの整合性を高めてくれるだけでなく、JavaScriptパーサーの振舞いを変えてしまうのを防いでくれるでしょう。 From d738831621967d0639abc462853d31bafafa0f60 Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Mon, 2 Jan 2012 18:45:55 +0900 Subject: [PATCH 027/277] fix translate in "timeout" --- doc/ja/other/timeouts.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/ja/other/timeouts.md b/doc/ja/other/timeouts.md index 3f5d2deb..3a4cbda1 100644 --- a/doc/ja/other/timeouts.md +++ b/doc/ja/other/timeouts.md @@ -8,9 +8,9 @@ JavaScriptは非同期なので、`setTimeout`と`setInterval`関数を使って function foo() {} var id = setTimeout(foo, 1000); // Number > 0を返す -`setTimeout`が呼ばれた時に、タイムアウトのIDと`foo`この先の**おおよそ**1000msに実行するスケジュールを返します。`foo`は正確に**1度**だけ実行されます。 +`setTimeout`が呼ばれた時に、タイムアウトのIDを返し、この先**おおよそ**1000ms以内に実行する`foo`をスケジュールします。`foo`は正確に**1度**だけ実行されます。 -コードが実行されているJavaScriptエンジンのタイマー分解能によって決まります。この事実はJavaScriptがシングルスレッドのなので、他のスレッドでの実行を妨害してしまう事があるかもしれません。これは、`setTimeout`関数の呼び出しで指定した遅延時間を正確に間違いなく得られるという**意味では決してありません**。 +これは、`setTimeout`関数の呼び出しで指定した遅延時間を正確に間違いなく得られるという**事では決してありません**。コードが実行されているJavaScriptエンジンのタイマー分解能によって決まります。この事実はJavaScriptがシングルスレッドなので、他のスレッドでの実行を妨害してしまう事があるかもしれません。 第一パラメーターを渡された関数は*グローバルオブジェクト*によって呼び出されます。これは呼び出された関数の内部で[`this`](#functionis)がまさにこのオブジェクトを参照しているという事になります。 @@ -44,7 +44,7 @@ JavaScriptは非同期なので、`setTimeout`と`setInterval`関数を使って 上記のコードでは、`foo`が1回呼び出されて、1秒ブロックされます。 -`foo`がコードをブロックしている間、`setInterval`は呼び出される予定を確保しています。`foo`が完了した瞬間に、実行を待っている間に**10回**以上呼び出されている事になります。 +`foo`がコードをブロックしている間、`setInterval`は呼び出される予定を確保しています。`foo`が完了した瞬間に、実行を待っている呼び出しが**10回**以上存在しているでしょう。 ### ブロッキング可能なコードの取り扱い @@ -74,7 +74,7 @@ JavaScriptは非同期なので、`setTimeout`と`setInterval`関数を使って clearTimeout(i); } -ここまでもまだ、任意の数字を与えられた為に影響を受けないタイムアウトがあるかもしれません。しかし、全てのタイムアウトのIDを追跡していく事は推奨されないので、それらは個別にクリアされます。 +ここまでもまだ、任意の数字を与えられた為に影響を受けないタイムアウトがあるかもしれません。そのため、代わりに全てのタイムアウトのIDを追跡する事が推奨されます。それで個別にクリアされます。 ### 隠された`eval`の使用 @@ -99,7 +99,7 @@ JavaScriptは非同期なので、`setTimeout`と`setInterval`関数を使って この場合、`eval`は[直接](#core.eval)呼ばれないので、文字列が渡された`setTimeout`は*global scope*で実行されます。よって、`bar`のスコープから`foo`のローカル変数は使われないのです。 -タイムアウト関数によって呼び出される関数を引数に渡すために文字列を使わ**ない**という事は、それ以上に推奨されています。 +いずれかのタイムアウト関数によって呼び出される関数に引数を渡すために文字列を使わ**ない**という事は、さらに推奨されています。 function foo(a, b, c) {} From 4ac4dfdc28d9d10462a50919fa9bc4172595b757 Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Mon, 9 Jan 2012 01:08:27 +0900 Subject: [PATCH 028/277] fix translate in "Array" --- doc/ja/array/general.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ja/array/general.md b/doc/ja/array/general.md index 0b7925dc..7afc71df 100644 --- a/doc/ja/array/general.md +++ b/doc/ja/array/general.md @@ -18,7 +18,7 @@ JavaScriptの配列もまたオブジェクトですが、[`for in ループ`](# 上記の例では1つ追加の仕掛けがありますが、それは`l = list.length`によって配列の長さをキャッシュする部分です。 -また、`length`プロパティは配列自身に定義されていますが、ループ中の繰り返し毎回参照を行なうというオーバーヘッドがまだ存在します。最近のJavaScriptエンジンはこのような場合に最適化する**はず**ですが、コードが新しいエンジンで実行されるかどうか、知る方法はありません。 +`length`プロパティは配列自身に定義されてはいますが、ループ中の繰り返しで毎回これを参照してしまうと、やはりオーバーヘッドが存在してしまいます。最近のJavaScriptエンジンはこのような場合に最適化する**はず**ですが、コードが新しいエンジンで実行されるかどうか、知る方法はありません。 実際には、キャッシュを抜きにするとループの結果はキャッシュされたものに比べてたった**半分の速度**にしかなりません。 From 2c719a22327f7cae8137e6f3b12bce2d71900d54 Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Mon, 9 Jan 2012 01:17:55 +0900 Subject: [PATCH 029/277] cp core/delete --- doc/ja/core/delete.md | 87 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 doc/ja/core/delete.md diff --git a/doc/ja/core/delete.md b/doc/ja/core/delete.md new file mode 100644 index 00000000..37a12816 --- /dev/null +++ b/doc/ja/core/delete.md @@ -0,0 +1,87 @@ +## 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 +Activation object or Global object. Such properties have a set of attributes, +one of these is `DontDelete`. Variable and function declarations in global +and function code always create properties with `DontDelete`, 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 + +There are things which can be deleted normally: these are explicitly set +properties. + + // 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 an 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 it's property +which allows us to delete it. + +IE (at least 6-8) has some bugs, so code above doesn't work. + +### Function arguments and built-ins + +Functions' normal arguments, [`arguments` object](#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 + +Behaviour of `delete` operator can be unpredictable for hosted objects. Due to +specification, host objects are allowed to implement any kind of behavior. + +### In conclusion + +`delete` operator often has an unexpected behaviour and can be safely used +only for dealing with explicitly set properties on normal objects. From 985299bfd1fce480cdf5cd8dfd56eee083518619 Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Tue, 17 Jan 2012 02:41:12 +0900 Subject: [PATCH 030/277] fix typo --- doc/ja/function/general.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ja/function/general.md b/doc/ja/function/general.md index a1c490b5..f53e2dd3 100644 --- a/doc/ja/function/general.md +++ b/doc/ja/function/general.md @@ -1,6 +1,6 @@ ## 関数の宣言と式 -関数はJavaScriptの第一級オブジェクトです。この事は、その他の値と同じように渡す事が出来るという事です。この機能で良く使われる一つとして**匿名関数**を他のオジェクトにコールバックとして渡すというものがあり、これで非同期での実装が可能になります。 +関数はJavaScriptの第一級オブジェクトです。この事は、その他の値と同じように渡す事が出来るという事です。この機能で良く使われる一つとして**匿名関数**を他のオブジェクトにコールバックとして渡すというものがあり、これで非同期での実装が可能になります。 ### `関数`宣言 From cd7c86a6a401218158f18b0ad5fc2577cc62fd21 Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Sun, 29 Jan 2012 20:55:05 +0900 Subject: [PATCH 031/277] translate 'The delete Operator' in 'delete' to ja --- doc/ja/core/delete.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/doc/ja/core/delete.md b/doc/ja/core/delete.md index 37a12816..900c67f5 100644 --- a/doc/ja/core/delete.md +++ b/doc/ja/core/delete.md @@ -1,7 +1,6 @@ -## The `delete` Operator +## `delete`演算子 -In short, it's *impossible* to delete global variables, functions and some other -stuff in JavaScript which have a `DontDelete` attribute set. +端的に言って、JavaScriptの関数やその他の要素は`DontDelete`属性が設定されているので、グローバル変数を消去する事は*不可能*です。 ### Global code and Function code From 623ba2c67b6423d270e6f059a1738d4ba38499be Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Sun, 29 Jan 2012 21:37:17 +0900 Subject: [PATCH 032/277] translate "Global code and Function code" in "delete" to ja --- doc/ja/core/delete.md | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/doc/ja/core/delete.md b/doc/ja/core/delete.md index 900c67f5..ff01e373 100644 --- a/doc/ja/core/delete.md +++ b/doc/ja/core/delete.md @@ -2,26 +2,21 @@ 端的に言って、JavaScriptの関数やその他の要素は`DontDelete`属性が設定されているので、グローバル変数を消去する事は*不可能*です。 -### 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 -Activation object or Global object. Such properties have a set of attributes, -one of these is `DontDelete`. Variable and function declarations in global -and function code always create properties with `DontDelete`, therefore -cannot be deleted. +変数や、関数がグローバルまたは[関数スコープ](#function.scopes)で定義された時は、そのプロパティは有効なオブジェクトかグローバルオブジェクトになります。このようなプロパティは属性のセットを持っていますが、それらの内の1つが`DontDelete`になります。変数や関数がグローバルや関数コードで宣言されると、常に`DontDelete`属性を作るために、消去できません。 - // global variable: - var a = 1; // DontDelete is set + // グローバル変数: + var a = 1; // DontDelete属性が設定される delete a; // false a; // 1 - // normal function: - function f() {} // DontDelete is set + // 通常関数: + function f() {} // DontDelete属性が設定される delete f; // false typeof f; // "function" - // reassigning doesn't help: + // 再代入も役に立たない: f = 1; delete f; // false f; // 1 From 414e75038a70aa95a9c1821037a945b9e0de06c6 Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Wed, 8 Feb 2012 17:23:02 +0900 Subject: [PATCH 033/277] add delete menu into "core" --- doc/ja/index.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/ja/index.json b/doc/ja/index.json index 70be20fc..6fdb018d 100644 --- a/doc/ja/index.json +++ b/doc/ja/index.json @@ -54,7 +54,8 @@ "articles": [ "eval", "undefined", - "semicolon" + "semicolon", + "delete" ] }, { From 777a432f352a8c5c1c72a1fa4a81e71fc954822a Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Mon, 20 Feb 2012 03:10:57 +0900 Subject: [PATCH 034/277] translate "Explicit properties" in "delete" to ja --- doc/ja/core/delete.md | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/doc/ja/core/delete.md b/doc/ja/core/delete.md index ff01e373..ebb512d2 100644 --- a/doc/ja/core/delete.md +++ b/doc/ja/core/delete.md @@ -21,12 +21,11 @@ delete f; // false f; // 1 -### Explicit properties +### 明示的なプロパティ -There are things which can be deleted normally: these are explicitly set -properties. +普通にプロパティを消去できる方法が存在します:プロパティを明示的に設定するのです。 - // explicitly set property: + // プロパティを明示的に設定する var obj = {x: 1}; obj.y = 2; delete obj.x; // true @@ -34,21 +33,19 @@ properties. 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 an example below works too. +上記の例の中で、`obj.x`と`obj.y`はそれぞれ`DontDelete`属性が無い為に削除できます。これが下記の例でも動作する理由です。 - // this works fine, except for IE: + // IE以外では、これも動作する var GLOBAL_OBJECT = this; GLOBAL_OBJECT.a = 1; - a === GLOBAL_OBJECT.a; // true - just a global var + a === GLOBAL_OBJECT.a; // true - ただのグローバルの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 it's property -which allows us to delete it. +ここでは`a`. [`this`](#function.this)を消す為にグローバルオブジェクトと明示的に宣言した`a`をそのプロパティとして参照させて、消去する事を許可するトリックを使います。 + +IE(最低でも6-8で)は多少のバグがある為に、上記のコードは動作しません。 -IE (at least 6-8) has some bugs, so code above doesn't work. ### Function arguments and built-ins From 23f1d007878c942141c41a294d3efe19fddf48a5 Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Fri, 24 Feb 2012 19:06:54 +0900 Subject: [PATCH 035/277] translate "Function arguments and built-ins" in delete --- doc/ja/core/delete.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/doc/ja/core/delete.md b/doc/ja/core/delete.md index ebb512d2..df3b5e65 100644 --- a/doc/ja/core/delete.md +++ b/doc/ja/core/delete.md @@ -47,24 +47,23 @@ IE(最低でも6-8で)は多少のバグがある為に、上記のコードは動作しません。 -### Function arguments and built-ins +### 関数の引数と組み込み引数 -Functions' normal arguments, [`arguments` object](#function.arguments) -and built-in properties also have `DontDelete` set. +関数の通常の引数である、[`arguments` object](#function.arguments)と組み込みのプロパティもまた、`DontDelete`が設定されています。 - // 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 From 49ed22c25151555da46e62acf4858300af3a29ed Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Sat, 25 Feb 2012 20:18:05 +0900 Subject: [PATCH 036/277] translate "Host objects" to ja in "delete" --- doc/ja/core/delete.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/doc/ja/core/delete.md b/doc/ja/core/delete.md index df3b5e65..b63e4189 100644 --- a/doc/ja/core/delete.md +++ b/doc/ja/core/delete.md @@ -66,10 +66,9 @@ IE(最低でも6-8で)は多少のバグがある為に、上記のコードは })(1); -### Host objects - -Behaviour of `delete` operator can be unpredictable for hosted objects. Due to -specification, host objects are allowed to implement any kind of behavior. +### ホストオブジェクト + +`delete`演算子の振る舞いはホストオブジェクトにとって予測不可能になりかねません。仕様によりホストオブジェクトは、あらゆる振る舞いの実行が許可されている為です。 ### In conclusion From 698ff8e1f8d87ea86f32879228a00b0d8805bee7 Mon Sep 17 00:00:00 2001 From: HIRAKI Satoru Date: Sat, 25 Feb 2012 20:21:52 +0900 Subject: [PATCH 037/277] translate "In conclusion" to ja in "delete" --- doc/ja/core/delete.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/doc/ja/core/delete.md b/doc/ja/core/delete.md index b63e4189..632dc142 100644 --- a/doc/ja/core/delete.md +++ b/doc/ja/core/delete.md @@ -68,9 +68,8 @@ IE(最低でも6-8で)は多少のバグがある為に、上記のコードは ### ホストオブジェクト -`delete`演算子の振る舞いはホストオブジェクトにとって予測不可能になりかねません。仕様によりホストオブジェクトは、あらゆる振る舞いの実行が許可されている為です。 +`delete`演算子の挙動はホストオブジェクトにとって予測不可能になりかねません。仕様によりホストオブジェクトは、あらゆる挙動の実行が許可されている為です。 -### In conclusion +### 終わりに -`delete` operator often has an unexpected behaviour and can be safely used -only for dealing with explicitly set properties on normal objects. +`delete`演算子は、しばしば予期せぬ挙動をします。唯一安全な仕様方法は通常のオブジェクトに明示的に設定されたプロパティを扱う場合だけです。 From b8bada45df81f5951bd84d9bd783c8dbaf9fd4c3 Mon Sep 17 00:00:00 2001 From: ambar Date: Mon, 9 Apr 2012 10:47:40 +0800 Subject: [PATCH 038/277] [lang=zh] correct some typing errors --- doc/zh/function/arguments.md | 2 +- doc/zh/function/general.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/zh/function/arguments.md b/doc/zh/function/arguments.md index b86e72f6..ef351e9e 100755 --- a/doc/zh/function/arguments.md +++ b/doc/zh/function/arguments.md @@ -80,7 +80,7 @@ JavaScript 中每个函数内都能访问一个特别变量 `arguments`。这个 `arguments` 对象总会被创建,除了两个特殊情况 - 作为局部变量声明和作为形式参数。 而不管它是否有被使用。 -`arguments` 的 *getters* 和 *setters* 方法总会被创佳;因此使用 `arguments` 对性能不会有什么影响。 +`arguments` 的 *getters* 和 *setters* 方法总会被创建;因此使用 `arguments` 对性能不会有什么影响。 除非是需要对 `arguments` 对象的属性进行多次访问。 > **ES5 提示:** 这些 *getters* 和 *setters* 在严格模式下(strict mode)不会被创建。 diff --git a/doc/zh/function/general.md b/doc/zh/function/general.md index 41a63a3d..964ce094 100755 --- a/doc/zh/function/general.md +++ b/doc/zh/function/general.md @@ -1,7 +1,7 @@ ##函数声明与表达式 函数是JavaScript中的一等对象,这意味着可以把函数像其它值一样传递。 -一个常见的用法是把*匿名函数*作为回调函数传递对异步函数中。 +一个常见的用法是把*匿名函数*作为回调函数传递到异步函数中。 ###函数声明 From 569be23e30a4a1c507a25910c882e04b92db382e Mon Sep 17 00:00:00 2001 From: David Matas Date: Fri, 13 Apr 2012 13:28:23 +0200 Subject: [PATCH 039/277] Improved some spanish translation --- doc/es/object/general.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/doc/es/object/general.md b/doc/es/object/general.md index bd3bab18..ccdd1cce 100644 --- a/doc/es/object/general.md +++ b/doc/es/object/general.md @@ -1,22 +1,22 @@ ## Uso de objetos y propiedades -Todo en JavaScript actúa como un objeto, con las dos únicas excepciones de +Todo en JavaScript actúa como un objeto, con las dos únicas excepciones de [`null`](#core.undefined) y [`undefined`](#core.undefined). false.toString() // 'false' [1, 2, 3].toString(); // '1,2,3' - + function Foo(){} Foo.bar = 1; Foo.bar; // 1 -Un error muy común es el uso de literales númericos como objetos. +Un error muy común es el uso de literales númericos como objetos. Esto se debe a un error en el parser de JavaScript que intenta analizar la *notación de puntos* como un literal de punto flotante. 2.toString(); // lanza SyntaxError -Existe un par de soluciones que pueden utilizarse para hacer que los +Existe un par de soluciones que pueden utilizarse para hacer que los literales númericos actúen como objetos. 2..toString(); // el segundo punto es reconocido correctamente @@ -25,30 +25,30 @@ literales númericos actúen como objetos. ### Objetos como un tipo de datos -Los objetos en JavaScript también pueden ser utilizados como una Tabla Hash o conocido como [*Hashmap*][1] en inglés, consisten +Los objetos en JavaScript también pueden ser utilizados como una Tabla Hash o conocido como [*Hashmap*][1] en inglés, consisten principalmente en nombres de propiedades asignadoles valores a estos. -El uso de un objeto literal - con notación `{}` - puede crear un +El uso de un objeto literal - con notación `{}` - puede crear un objeto plano. Este nuevo objeto [heredado](#object.prototype) desde `Object.prototype` no posee [propiedades propias](#object.hasownproperty) definidas. var foo = {}; // un nuevo objeto vacío // un nuevo objeto con la propiedad llamada 'test' con el valor 12 - var bar = {test: 12}; + var bar = {test: 12}; ### Acceso a las propiedades Se puede acceder a las propiedades de un objeto de dos maneras, ya sea a través de la -notación de punto o desde la notación de corchetes. - +notación de punto o desde la notación de corchetes. + var foo = {name: 'Kitten'} foo.name; // kitten foo['name']; // kitten - + var get = 'name'; foo[get]; // kitten - + foo.1234; // SyntaxError foo['1234']; // ¡funciona! @@ -59,8 +59,8 @@ el uso de propiedades que de otro modo daría lugar a error de sintaxis. ### Eliminando propiedades La única manera de eliminar una propiedad desde un objeto es usando el -operador `delete`; Se establece la propiedad a `undefined` o `null` sólo al -*valor* asociado de la propiedad, pero no ha un *key* (valor clave). +operador `delete`; establecer la propiedad a `undefined` o `null` solamente +elimina el *valor* asociado a la propiedad, pero no la *key* (valor clave). var obj = { bar: 1, From 3928be67c914932cdeddc50a33a184993c9c537e Mon Sep 17 00:00:00 2001 From: "Michael C. Harris" Date: Thu, 31 May 2012 18:55:07 +1000 Subject: [PATCH 040/277] Specify minimum version of forever. Rather than using a specific version of forever, which is no longer available via npm, use it as a minimum. Without this `npm install` fails. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 98500980..fdaecf9b 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "version": "0.0.0", "dependencies": { "fomatto": "0.5.0", - "forever": "0.4.1", + "forever": ">=0.4.1", "jade": "0.9.1", "neko": "1.1.2", "node-markdown": "0.1.0" From 9e3e75664e49ef7ae30c7aee6d3355e4be07d08e Mon Sep 17 00:00:00 2001 From: "Michael C. Harris" Date: Sun, 3 Jun 2012 12:06:48 +1000 Subject: [PATCH 041/277] Clean up language in the function section. --- doc/en/function/arguments.md | 9 ++++----- doc/en/function/closures.md | 4 ++-- doc/en/function/constructors.md | 32 ++++++++++++++++---------------- doc/en/function/general.md | 6 +++--- doc/en/function/scopes.md | 28 ++++++++++++++-------------- doc/en/function/this.md | 8 ++++---- 6 files changed, 43 insertions(+), 44 deletions(-) diff --git a/doc/en/function/arguments.md b/doc/en/function/arguments.md index 37f3a634..2394177d 100644 --- a/doc/en/function/arguments.md +++ b/doc/en/function/arguments.md @@ -79,9 +79,9 @@ of the corresponding property on the `arguments` object, and the other way aroun ### Performance Myths and Truths -The `arguments` object is always created with the only two exceptions being the -cases where it is declared as a name inside of a function or one of its formal -parameters. It does not matter whether it is used or not. +The only time the `arguments` object is not created is where it is declared as +a name inside of a function or one of its formal parameters. It does not matter +whether it is used or not. Both *getters* and *setters* are **always** created; thus, using it has nearly no performance impact at all, especially not in real world code where there is @@ -108,8 +108,7 @@ needs to know about both itself and its caller. This not only defeats possible performance gains that would arise from inlining, but it also breaks encapsulation because the function may now be dependent on a specific calling context. -It is **highly recommended** to **never** make use of `arguments.callee` or any of -its properties. +Making use of `arguments.callee` or any of its properties is **highly discouraged**. > **ES5 Note:** In strict mode, `arguments.callee` will throw a `TypeError` since > its use has been deprecated. diff --git a/doc/en/function/closures.md b/doc/en/function/closures.md index 2e2a4ef6..76f2d078 100644 --- a/doc/en/function/closures.md +++ b/doc/en/function/closures.md @@ -27,7 +27,7 @@ were defined. Since the only scoping that JavaScript has is Here, `Counter` returns **two** closures: the function `increment` as well as the function `get`. Both of these functions keep a **reference** to the scope of `Counter` and, therefore, always keep access to the `count` variable that was -defined in that very scope. +defined in that scope. ### Why Private Variables Work @@ -47,7 +47,7 @@ override - the *global* variable `count`. ### Closures Inside Loops One often made mistake is to use closures inside of loops, as if they were -copying the value of the loops index variable. +copying the value of the loop's index variable. for(var i = 0; i < 10; i++) { setTimeout(function() { diff --git a/doc/en/function/constructors.md b/doc/en/function/constructors.md index 42e152b4..bf9771dc 100644 --- a/doc/en/function/constructors.md +++ b/doc/en/function/constructors.md @@ -25,7 +25,7 @@ The above calls `Foo` as constructor and sets the `prototype` of the newly created object to `Foo.prototype`. In case of an explicit `return` statement, the function returns the value -specified that statement, **but only** if the return value is an `Object`. +specified by that statement, but **only** if the return value is an `Object`. function Bar() { return 2; @@ -72,13 +72,13 @@ explicitly return a value. new Bar(); Bar(); -Both calls to `Bar` return the exact same thing, a newly create object which -has a property called `method` on it, which is a +Both calls to `Bar` return the same thing, a newly create object that +has a property called `method`, which is a [Closure](#function.closures). -It is also to note that the call `new Bar()` does **not** affect the prototype -of the returned object. While the prototype will be set on the newly created -object, `Bar` never returns that new object. +It should also be noted that the call `new Bar()` does **not** affect the +prototype of the returned object. While the prototype will be set on the newly +created object, `Bar` never returns that new object. In the above example, there is no functional difference between using and not using the `new` keyword. @@ -86,10 +86,10 @@ not using the `new` keyword. ### Creating New Objects via Factories -An often made recommendation is to **not** use `new` because forgetting its use -may lead to bugs. +It is often recommended to **not** use `new` because forgetting its use may +lead to bugs. -In order to create new object, one should rather use a factory and construct a +In order to create a new object, one should rather use a factory and construct a new object inside of that factory. function Foo() { @@ -113,16 +113,16 @@ downsides. 1. It uses more memory since the created objects do **not** share the methods on a prototype. - 2. In order to inherit the factory needs to copy all the methods from another + 2. In order to inherit, the factory needs to copy all the methods from another object or put that object on the prototype of the new object. 3. Dropping the prototype chain just because of a left out `new` keyword - somehow goes against the spirit of the language. + is contrary to the spirit of the language. ### In Conclusion -While omitting the `new` keyword might lead to bugs, it is certainly **not** a -reason to drop the use of prototypes altogether. In the end it comes down to -which solution is better suited for the needs of the application, it is -especially important to choose a specific style of object creation **and stick** -with it. +While omitting the `new` keyword might lead to bugs, it is certainly **not** a +reason to drop the use of prototypes altogether. In the end it comes down to +which solution is better suited for the needs of the application. It is +especially important to choose a specific style of object creation and use it +**consistently**. diff --git a/doc/en/function/general.md b/doc/en/function/general.md index e3d2a0bc..b2788e46 100644 --- a/doc/en/function/general.md +++ b/doc/en/function/general.md @@ -8,9 +8,9 @@ an *anonymous function* as a callback to another, possibly an asynchronous funct function foo() {} -The above function gets [hoisted](#function.scopes) before the execution of the -program starts; thus, it is available *everywhere* in the scope it was *defined* -in, even if called before the actual definition in the source. +The above function gets [hoisted](#function.scopes) before the execution of the +program starts; thus, it is available *everywhere* in the scope it was +*defined*, even if called before the actual definition in the source. foo(); // Works because foo was created before this code runs function foo() {} diff --git a/doc/en/function/scopes.md b/doc/en/function/scopes.md index 022ecaed..879e1e8a 100644 --- a/doc/en/function/scopes.md +++ b/doc/en/function/scopes.md @@ -73,7 +73,7 @@ unless the *desired effect* is to affect the outer scope. ### Local Variables The only source for local variables in JavaScript are -[function](#function.general) parameters and variables that were declared via the +[function](#function.general) parameters and variables declared via the `var` statement. // global scope @@ -115,8 +115,8 @@ JavaScript **hoists** declarations. This means that both `var` statements and } } -The above code gets transformed before any execution is started. JavaScript moves -the `var` statements, as well as the `function` declarations to the top of the +The above code gets transformed before execution starts. JavaScript moves +the `var` statements, as well as `function` declarations, to the top of the nearest surrounding scope. // var statements got moved here @@ -150,7 +150,7 @@ In the original code, although the `if` statement seemed to modify the *global variable* `goo`, it actually modifies the *local variable* - after hoisting has been applied. -Without the knowledge about *hoisting*, the below code might seem to raise a +Without knowledge of *hoisting*, one might suspect the code below would raise a `ReferenceError`. // check whether SomeImportantThing has been initialized @@ -158,7 +158,7 @@ Without the knowledge about *hoisting*, the below code might seem to raise a var SomeImportantThing = {}; } -But of course, the above works due to the fact that the `var` statement is being +But of course, this works due to the fact that the `var` statement is being moved to the top of the *global scope*. var SomeImportantThing; @@ -176,10 +176,10 @@ All scopes in JavaScript, including the *global scope*, have the special name [`this`](#function.this), defined in them, which refers to the *current object*. Function scopes also have the name [`arguments`](#function.arguments), defined in -them, which contains the arguments that were passed to a function. +them, which contains the arguments that were passed to the function. For example, when trying to access a variable named `foo` inside the scope of a -function, JavaScript will lookup the name in the following order: +function, JavaScript will look up the name in the following order: 1. In case there is a `var foo` statement in the current scope, use that. 2. If one of the function parameters is named `foo`, use that. @@ -191,9 +191,9 @@ function, JavaScript will lookup the name in the following order: ### Namespaces -A common problem of having only one global namespace is the likeliness of running -into problems where variable names clash. In JavaScript, this problem can -easily be avoided with the help of *anonymous wrappers*. +A common problem associated with having only one global namespace is the +likelihood of running into problems where variable names clash. In JavaScript, +this problem can easily be avoided with the help of *anonymous wrappers*. (function() { // a self contained "namespace" @@ -208,13 +208,13 @@ easily be avoided with the help of *anonymous wrappers*. Unnamed functions are considered [expressions](#function.general); so in order to being callable, they must first be evaluated. - ( // evaluate the function inside the paranthesis + ( // evaluate the function inside the parentheses function() {} ) // and return the function object () // call the result of the evaluation -There are other ways for evaluating and directly calling the function expression; which, -while different in syntax, do behave the exact same way. +There are other ways to evaluate and directly call the function expression +which, while different in syntax, behave the same way. // A few other styles for directly invoking the !function(){}() @@ -224,7 +224,7 @@ while different in syntax, do behave the exact same way. ### In Conclusion -It is recommended to always use an *anonymous wrapper* for encapsulating code in +It is recommended to always use an *anonymous wrapper* to encapsulate code in its own namespace. This does not only protect code against name clashes, but it also allows for better modularization of programs. diff --git a/doc/en/function/this.md b/doc/en/function/this.md index c2ef238f..48070d2e 100644 --- a/doc/en/function/this.md +++ b/doc/en/function/this.md @@ -1,7 +1,7 @@ ## How `this` Works JavaScript has a different concept of what the special name `this` refers to -than most other programming languages do. There are exactly **five** different +than most other programming languages. There are exactly **five** different ways in which the value of `this` can be bound in the language. ### The Global Scope @@ -55,7 +55,7 @@ inside of `foo` will be set to `bar`. ### Common Pitfalls -While most of these cases make sense, the first one is to be considered another +While most of these cases make sense, the first can be considered another mis-design of the language because it **never** has any practical use. Foo.method = function() { @@ -69,7 +69,7 @@ A common misconception is that `this` inside of `test` refers to `Foo`; while in fact, it **does not**. In order to gain access to `Foo` from within `test`, it is necessary to create a -local variable inside of `method` which refers to `Foo`. +local variable inside of `method` that refers to `Foo`. Foo.method = function() { var that = this; @@ -105,7 +105,7 @@ fact, it is what makes [prototypal inheritance](#object.prototype) work. new Bar().method(); -When `method` gets called on a instance of `Bar`, `this` will now refer to that +When `method` gets called on an instance of `Bar`, `this` will now refer to that very instance. From 1246d87583bf590b3c412095b368a3248f27d214 Mon Sep 17 00:00:00 2001 From: "Michael C. Harris" Date: Sun, 3 Jun 2012 12:13:54 +1000 Subject: [PATCH 042/277] Clean up language in the array section. --- doc/en/array/constructor.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/en/array/constructor.md b/doc/en/array/constructor.md index 1d9abe18..8930b605 100644 --- a/doc/en/array/constructor.md +++ b/doc/en/array/constructor.md @@ -21,15 +21,15 @@ the actual indexes of the array will not be initialized. arr[1]; // undefined 1 in arr; // false, the index was not set -The behavior of being able to set the length of the array upfront only comes in -handy in a few cases, like repeating a string, in which it avoids the use of a -`for loop` code. +Being able to set the length of the array in advance is only useful in a few +cases, like repeating a string, in which it avoids the use of a `for loop` +code. new Array(count + 1).join(stringToRepeat); ### In Conclusion -The use of the `Array` constructor should be avoided as much as possible. -Literals are definitely preferred. They are shorter and have a clearer syntax; -therefore, they also increase the readability of the code. +The use of the `Array` constructor should be avoided. Literals are definitely +preferred. They are shorter, have a clearer syntax, and increase code +readability. From 23dac36960c06495dbffe2c65096dd65db87a856 Mon Sep 17 00:00:00 2001 From: "Michael C. Harris" Date: Sun, 3 Jun 2012 12:39:25 +1000 Subject: [PATCH 043/277] Clean up language in the types section. --- doc/en/types/casting.md | 8 ++++---- doc/en/types/equality.md | 6 +++--- doc/en/types/instanceof.md | 4 ++-- doc/en/types/typeof.md | 17 ++++++++--------- 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/doc/en/types/casting.md b/doc/en/types/casting.md index 34d6fd78..0dcbc92b 100644 --- a/doc/en/types/casting.md +++ b/doc/en/types/casting.md @@ -21,7 +21,7 @@ JavaScript is a *weakly typed* language, so it will apply *type coercion* > (Base 8). Octal support for these has been **removed** in ECMAScript 5 strict > mode. -In order to avoid the above, use of the [strict equal operator](#types.equality) +To avoid the issues above, use of the [strict equal operator](#types.equality) is **highly** recommended. Although this avoids a lot of common pitfalls, there are still many further issues that arise from JavaScript's weak typing system. @@ -38,8 +38,8 @@ Using a built-in type like `Number` as a constructor will create a new `Number` object, but leaving out the `new` keyword will make the `Number` function behave like a converter. -In addition, having literals or non-object values in there will result in even -more type coercion. +In addition, passing literals or non-object values will result in even more +type coercion. The best option is to cast to one of the three possible types **explicitly**. @@ -47,7 +47,7 @@ The best option is to cast to one of the three possible types **explicitly**. '' + 10 === '10'; // true -By prepending an empty string, a value can easily be casted to a string. +By prepending an empty string, a value can easily be cast to a string. ### Casting to a Number diff --git a/doc/en/types/equality.md b/doc/en/types/equality.md index 5665917f..e47752a4 100644 --- a/doc/en/types/equality.md +++ b/doc/en/types/equality.md @@ -31,7 +31,7 @@ to another number. The strict equality operator consists of **three** equal signs: `===`. -It works exactly like the normal equality operator, except that strict equality +It works like the normal equality operator, except that strict equality operator does **not** perform type coercion between its operands. "" === "0" // false @@ -50,8 +50,8 @@ the operands are of different types. ### Comparing Objects -While both `==` and `===` are stated as **equality** operators, they behave -differently when at least one of their operands happens to be an `Object`. +While both `==` and `===` are called **equality** operators, they behave +differently when at least one of their operands is an `Object`. {} === {}; // false new String('foo') === 'foo'; // false diff --git a/doc/en/types/instanceof.md b/doc/en/types/instanceof.md index 84251128..2fe41064 100644 --- a/doc/en/types/instanceof.md +++ b/doc/en/types/instanceof.md @@ -13,8 +13,8 @@ nearly as useless as the [typeof operator](#types.typeof). new Bar() instanceof Bar; // true new Bar() instanceof Foo; // true - // This just sets Bar.prototype to the function object Foo - // But not to an actual instance of Foo + // This just sets Bar.prototype to the function object Foo, + // but not to an actual instance of Foo Bar.prototype = Foo; new Bar() instanceof Foo; // false diff --git a/doc/en/types/typeof.md b/doc/en/types/typeof.md index 00377db4..637ea2bc 100644 --- a/doc/en/types/typeof.md +++ b/doc/en/types/typeof.md @@ -2,16 +2,16 @@ The `typeof` operator (together with [`instanceof`](#types.instanceof)) is probably the biggest -design flaw of JavaScript, as it is near of being **completely broken**. +design flaw of JavaScript, as it is almost **completely broken**. -Although `instanceof` still has its limited uses, `typeof` really has only one +Although `instanceof` still has limited uses, `typeof` really has only one practical use case, which does **not** happen to be checking the type of an object. -> **Note:** While `typeof` can also be called with a function like syntax -> i.e. `typeof(obj)`, this is not a function call. The two parenthesis will -> behave like normal and the return value will be used as the operand of the -> `typeof` operator. There is **no** `typeof` function. +> **Note:** While `typeof` can also be called with a function like syntax, i.e. +> `typeof(obj)`, this is not a function call. The parentheses behave as normal +> and the return value will be used as the operand of the `typeof` operator. +> There is **no** `typeof` function. ### The JavaScript Type Table @@ -79,9 +79,8 @@ referencing it would result in a `ReferenceError`. This is the only thing In order to check the type of an object, it is highly recommended to use `Object.prototype.toString` because this is the only reliable way of doing so. As shown in the above type table, some return values of `typeof` are not defined -in the specification; thus, they can differ across various implementations. +in the specification; thus, they can differ between implementations. -Unless checking whether a variable is defined, `typeof` should be avoided at -**all costs**. +Unless checking whether a variable is defined, `typeof` should be avoided. From d9aeb54a3fc9e08db17f4dfa62fe045b9bdd3c9d Mon Sep 17 00:00:00 2001 From: "Michael C. Harris" Date: Sun, 3 Jun 2012 12:58:22 +1000 Subject: [PATCH 044/277] Clean up language in the core section. --- doc/en/core/delete.md | 28 +++++++++++++--------------- doc/en/core/eval.md | 18 +++++++++--------- doc/en/core/semicolon.md | 12 ++++++------ doc/en/core/undefined.md | 20 ++++++++++---------- 4 files changed, 38 insertions(+), 40 deletions(-) diff --git a/doc/en/core/delete.md b/doc/en/core/delete.md index fdde18a4..067fcfdb 100644 --- a/doc/en/core/delete.md +++ b/doc/en/core/delete.md @@ -5,12 +5,11 @@ 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 -Activation object or Global object. Such properties have a set of attributes, -one of these is `DontDelete`. Variable and function declarations in global -and function code always create properties with `DontDelete`, therefore -cannot be deleted. +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 @@ -29,8 +28,7 @@ cannot be deleted. ### Explicit properties -There are things which can be deleted normally: these are explicitly set -properties. +Explicitly set properties can be deleted normally. // explicitly set property: var obj = {x: 1}; @@ -40,8 +38,8 @@ properties. 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 an example below works too. +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; @@ -58,7 +56,7 @@ IE (at least 6-8) has some bugs, so the code above doesn't work. ### Function arguments and built-ins -Functions' normal arguments, [`arguments` object](#function.arguments) +Functions' normal arguments, [`arguments` objects](#function.arguments) and built-in properties also have `DontDelete` set. // function arguments and properties: @@ -78,10 +76,10 @@ and built-in properties also have `DontDelete` set. ### Host objects -Behaviour of `delete` operator can be unpredictable for hosted objects. Due to -specification, host objects are allowed to implement any kind of behavior. +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 -`delete` operator often has an unexpected behaviour and can be safely used -only for dealing with explicitly set properties on normal objects. +The `delete` operator often has unexpected behaviour and can only be safely +used to delete explicitly set properties on normal objects. diff --git a/doc/en/core/eval.md b/doc/en/core/eval.md index 160ba1f0..2d929902 100644 --- a/doc/en/core/eval.md +++ b/doc/en/core/eval.md @@ -12,7 +12,7 @@ The `eval` function will execute a string of JavaScript code in the local scope. foo; // 1 However, `eval` only executes in the local scope when it is being called -**directly** *and* when the name of the called function is actually `eval`. +directly *and* when the name of the called function is actually `eval`. var foo = 1; function test() { @@ -24,8 +24,8 @@ However, `eval` only executes in the local scope when it is being called test(); // 2 foo; // 3 -The use of `eval` should be avoided at **all costs**. 99.9% of its "uses" can be -achieved **without** it. +The use of `eval` should be avoided. 99.9% of its "uses" can be achieved +**without** it. ### `eval` in Disguise @@ -35,13 +35,13 @@ in the global scope since `eval` is not being called directly in that case. ### Security Issues -`eval` also is a security problem. Because it executes **any** code given to it, -it should **never** be used with strings of unknown or untrusted origins. +`eval` also is a security problem, because it executes **any** code given to it. +It should **never** be used with strings of unknown or untrusted origins. ### In Conclusion -`eval` should never be used. Any code that makes use of it is to be questioned in -its workings, performance and security. In case something requires `eval` in -order to work, it should **not** be used in the first place. -A *better design* should be used, that does not require the use of `eval`. +`eval` should never be used. Any code that makes use of it should be questioned +in its workings, performance and security. If something requires `eval` in +order to work, it should **not** be used in the first place. A *better design* +should be used, that does not require the use of `eval`. diff --git a/doc/en/core/semicolon.md b/doc/en/core/semicolon.md index f03f7d82..a2529da9 100644 --- a/doc/en/core/semicolon.md +++ b/doc/en/core/semicolon.md @@ -84,7 +84,7 @@ Below is the result of the parser's "guessing" game. })(window); //<- inserted > **Note:** The JavaScript parser does not "correctly" handle return statements -> which are followed by a new line, while this is not neccessarily the fault of +> that are followed by a new line. While this is not neccessarily the fault of > the automatic semicolon insertion, it can still be an unwanted side-effect. The parser drastically changed the behavior of the code above. In certain cases, @@ -106,9 +106,9 @@ the above will yield a `TypeError` stating that `undefined is not a function`. ### In Conclusion -It is highly recommended to **never** omit semicolons; it is also advocated to -keep braces on the same line with their corresponding statements and to never omit -them for one single-line `if` / `else` statements. Both of these measures will -not only improve the consistency of the code, but they will also prevent the -JavaScript parser from changing its behavior. +It is highly recommended to **never** omit semicolons. It is also recommended +that braces be kept on the same line as their corresponding statements and to +never omit them for single-line `if` / `else` statements. These measures will +not only improve the consistency of the code, but they will also prevent the +JavaScript parser from changing code behavior. diff --git a/doc/en/core/undefined.md b/doc/en/core/undefined.md index c819920f..1bea5411 100644 --- a/doc/en/core/undefined.md +++ b/doc/en/core/undefined.md @@ -1,7 +1,7 @@ ## `undefined` and `null` -JavaScript has two distinct values for `nothing`, the more useful of these two -being `undefined`. +JavaScript has two distinct values for nothing, `null` and `undefined`, with +the latter being more useful. ### The Value `undefined` @@ -16,14 +16,14 @@ overwritten. > mode, but its name can still be shadowed by for example a function with the name > `undefined`. -Some examples for when the value `undefined` is returned: +Here are some examples of when the value `undefined` is returned: - Accessing the (unmodified) global variable `undefined`. - - Accessing a declared *but not* yet initialized variable + - Accessing a declared *but not* yet initialized variable. - Implicit returns of functions due to missing `return` statements. - - `return` statements which do not explicitly return anything. + - `return` statements that do not explicitly return anything. - Lookups of non-existent properties. - - Function parameters which do not had any explicit value passed. + - 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)` @@ -36,14 +36,14 @@ Since the global variable `undefined` only holds a copy of the actual *value* of Still, in order to compare something against the value of `undefined`, it is necessary to retrieve the value of `undefined` first. -In order 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. +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 + // now again refer to the value `undefined` })('Hello World', 42); From 5f55365986d11375538cf22fa6128887cb78f787 Mon Sep 17 00:00:00 2001 From: "Michael C. Harris" Date: Sun, 3 Jun 2012 13:09:36 +1000 Subject: [PATCH 045/277] Clean up language in the other section. --- doc/en/other/timeouts.md | 50 ++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/doc/en/other/timeouts.md b/doc/en/other/timeouts.md index 28e672e0..578fad5f 100644 --- a/doc/en/other/timeouts.md +++ b/doc/en/other/timeouts.md @@ -1,7 +1,7 @@ ### `setTimeout` and `setInterval` Since JavaScript is asynchronous, it is possible to schedule the execution of a -function by using the `setTimeout` and `setInterval` functions. +function using the `setTimeout` and `setInterval` functions. > **Note:** Timeouts are **not** part of the ECMAScript Standard. They are > implemented as part of the [DOM][1]. @@ -9,18 +9,18 @@ function by using the `setTimeout` and `setInterval` functions. function foo() {} var id = setTimeout(foo, 1000); // returns a Number > 0 -When `setTimeout` gets called, it will return the ID of the timeout and schedule -`foo` to run in **approximately** one thousand milliseconds in the future. -`foo` will then get executed exactly **once**. +When `setTimeout` is called, it returns the ID of the timeout and schedule +`foo` to run **approximately** one thousand milliseconds in the future. +`foo` will then be executed **once**. -Depending on the timer resolution of the JavaScript engine that is running the -code, as well as the fact that JavaScript is single threaded and other code that -gets executed might block the thread, it is by **no means** a safe bet that one -will get the exact delay that was specified in the `setTimeout` call. +Depending on the timer resolution of the JavaScript engine running the code, as +well as the fact that JavaScript is single threaded and other code that gets +executed might block the thread, it is by **no means** a safe bet that one will +get the exact delay specified in the `setTimeout` call. The function that was passed as the first parameter will get called by the *global object*, which means that [`this`](#function.this) inside the called function -refers to that very object. +refers to the global object. function Foo() { this.value = 42; @@ -34,7 +34,7 @@ refers to that very object. > **Note:** As `setTimeout` takes a **function object** as its first parameter, an -> often made mistake is to use `setTimeout(foo(), 1000)`, which will use the +> common mistake is to use `setTimeout(foo(), 1000)`, which will use the > **return value** of the call `foo` and **not** `foo`. This is, most of the time, > a silent error, since when the function returns `undefined` `setTimeout` will > **not** raise any error. @@ -72,21 +72,21 @@ the function itself. foo(); Not only does this encapsulate the `setTimeout` call, but it also prevents the -stacking of calls and it gives additional control. `foo` itself can now decide +stacking of calls and gives additional control. `foo` itself can now decide whether it wants to run again or not. ### Manually Clearing Timeouts Clearing timeouts and intervals works by passing the respective ID to -`clearTimeout` or `clearInterval`, depending which `set` function was used in -the first place. +`clearTimeout` or `clearInterval`, depending on which `set` function was used +in the first place. var id = setTimeout(foo, 1000); clearTimeout(id); -### Clearing all timeouts +### Clearing All Timeouts -Because there is no built-in method for clearing all timeouts and/or intervals, +As there is no built-in method for clearing all timeouts and/or intervals, it is necessary to use brute force in order to achieve this functionality. // clear "all" timeouts @@ -94,7 +94,9 @@ it is necessary to use brute force in order to achieve this functionality. clearTimeout(i); } -But there might still be timeouts that are unaffected by this arbitrary number. Another way of doing this is to consider that the ID given to a timeout is incremented by one everytime you call `setTimeout`. +But there might still be timeouts that are unaffected by this arbitrary number. +Another way of doing this is to consider that the ID given to a timeout is +incremented by one every time you call `setTimeout`. // clear "all" timeouts var biggestTimeoutId = window.setTimeout(function(){}, 1), @@ -103,17 +105,19 @@ But there might still be timeouts that are unaffected by this arbitrary number. clearTimeout(i); } -But even though this works on all main browsers nowadays, it isn't specified that the IDs should be ordered that way and it may change. Therefore, it is instead recommended to keep track of all the timeout IDs, so -they can be cleared specifically. +Even though this works on all major browsers today, it isn't specified that +the IDs should be ordered that way and it may change. Therefore, it is instead +recommended to keep track of all the timeout IDs, so they can be cleared +specifically. -### Hidden use of `eval` +### Hidden Use of `eval` `setTimeout` and `setInterval` can also take a string as their first parameter. This feature should **never** be used because it internally makes use of `eval`. > **Note:** Since the timeout functions are **not** specified by the ECMAScript > standard, the exact workings when a string is passed to them might differ in -> various JavaScript implementations. For example, Microsoft's JScript makes use of +> various JavaScript implementations. For example, Microsoft's JScript uses > the `Function` constructor in place of `eval`. function foo() { @@ -129,10 +133,10 @@ This feature should **never** be used because it internally makes use of `eval`. bar(); Since `eval` is not getting called [directly](#core.eval) in this case, the string -passed to `setTimeout` will get executed in the *global scope*; thus, it will +passed to `setTimeout` will be executed in the *global scope*; thus, it will not use the local variable `foo` from the scope of `bar`. -It is further recommended to **not** use a string for passing arguments to the +It is further recommended to **not** use a string to pass arguments to the function that will get called by either of the timeout functions. function foo(a, b, c) {} @@ -151,7 +155,7 @@ function that will get called by either of the timeout functions. ### In Conclusion -**Never** should a string be used as the parameter of `setTimeout` or +A string should **never** be used as the parameter of `setTimeout` or `setInterval`. It is a clear sign of **really** bad code, when arguments need to be supplied to the function that gets called. An *anonymous function* should be passed that then takes care of the actual call. From 3dc251c1277739415afb0d48a108f373478ef35f Mon Sep 17 00:00:00 2001 From: "Michael C. Harris" Date: Sat, 2 Jun 2012 15:29:23 +1000 Subject: [PATCH 046/277] Clean up language in the object section. --- doc/en/object/forinloop.md | 18 +++++++------- doc/en/object/general.md | 16 ++++++------- doc/en/object/hasownproperty.md | 18 +++++++------- doc/en/object/prototype.md | 42 +++++++++++++++++---------------- 4 files changed, 48 insertions(+), 46 deletions(-) diff --git a/doc/en/object/forinloop.md b/doc/en/object/forinloop.md index cb776b36..3d366f8c 100644 --- a/doc/en/object/forinloop.md +++ b/doc/en/object/forinloop.md @@ -1,6 +1,6 @@ ## The `for in` Loop -Just like the `in` operator, the `for in` loop also traverses the prototype +Just like the `in` operator, the `for in` loop traverses the prototype chain when iterating over the properties of an object. > **Note:** The `for in` loop will **not** iterate over any properties that @@ -17,10 +17,10 @@ chain when iterating over the properties of an object. Since it is not possible to change the behavior of the `for in` loop itself, it is necessary to filter out the unwanted properties inside the loop body; -this is done by using the [`hasOwnProperty`](#object.hasownproperty) method of +this is done using the [`hasOwnProperty`](#object.hasownproperty) method of `Object.prototype`. -> **Note:** Since the `for in` always traverses the complete prototype chain, it +> **Note:** Since `for in` always traverses the complete prototype chain, it > will get slower with each additional layer of inheritance added to an object. ### Using `hasOwnProperty` for Filtering @@ -37,15 +37,15 @@ will **only** print out `moo`. When `hasOwnProperty` is left out, the code is prone to errors in cases where the native prototypes - e.g. `Object.prototype` - have been extended. -One widely used framework which does this is [Prototype][1]. When this -framework is included, `for in` loops that do not use `hasOwnProperty` are -guaranteed to break. +One widely used framework that extends `Object.prototype` is [Prototype][1]. +When this framework is included, `for in` loops that do not use +`hasOwnProperty` are guaranteed to break. ### In Conclusion -It is recommended to **always** use `hasOwnProperty`. Never should any -assumptions be made about the environment the code is running in, or whether the -native prototypes have been extended or not. +It is recommended to **always** use `hasOwnProperty`. Assumptions should never +be made about the environment the code is running in, or whether the native +prototypes have been extended or not. [1]: http://www.prototypejs.org/ diff --git a/doc/en/object/general.md b/doc/en/object/general.md index aefbfb90..d064d498 100644 --- a/doc/en/object/general.md +++ b/doc/en/object/general.md @@ -16,8 +16,8 @@ notation* on a number as a floating point literal. 2.toString(); // raises SyntaxError -There are a couple of workarounds which can be used in order make number -literals act as objects too. +There are a couple of workarounds that can be used to make number literals act +as objects too. 2..toString(); // the second point is correctly recognized 2 .toString(); // note the space left to the dot @@ -25,16 +25,16 @@ literals act as objects too. ### Objects as a Data Type -Objects in JavaScript can also be used as a [*Hashmap*][1]; they mainly consist +Objects in JavaScript can also be used as [*Hashmaps*][1]; they mainly consist of named properties mapping to values. Using an object literal - `{}` notation - it is possible to create a plain object. This new object [inherits](#object.prototype) from `Object.prototype` and -has no [own properties](#object.hasownproperty) defined on it. +does not have [own properties](#object.hasownproperty) defined. var foo = {}; // a new empty object - // a new object with a property called 'test' with value 12 + // a new object with a 'test' property with value 12 var bar = {test: 12}; ### Accessing Properties @@ -52,13 +52,13 @@ notation or the square bracket notation. foo.1234; // SyntaxError foo['1234']; // works -Both notations are identical in their workings, with the only difference being that -the square bracket notation allows for dynamic setting of properties, as well as +The notations work almost identically, with the only difference being that the +square bracket notation allows for dynamic setting of properties and the use of property names that would otherwise lead to a syntax error. ### Deleting Properties -The only way to actually remove a property from an object is to use the `delete` +The only way to remove a property from an object is to use the `delete` operator; setting the property to `undefined` or `null` only removes the *value* associated with the property, but not the *key*. diff --git a/doc/en/object/hasownproperty.md b/doc/en/object/hasownproperty.md index 6aa13d5c..0033b4ba 100644 --- a/doc/en/object/hasownproperty.md +++ b/doc/en/object/hasownproperty.md @@ -1,7 +1,7 @@ ## `hasOwnProperty` -In order to check whether a object has a property defined on *itself* and **not** -somewhere on its [prototype chain](#object.prototype), it is necessary to use the +To check whether an object has a property defined on *itself* and not somewhere +on its [prototype chain](#object.prototype), it is necessary to use the `hasOwnProperty` method which all objects inherit from `Object.prototype`. > **Note:** It is **not** enough to check whether a property is `undefined`. The @@ -23,14 +23,14 @@ does **not** traverse the prototype chain. Only `hasOwnProperty` will give the correct and expected result; this is essential when iterating over the properties of any object. There is **no** other -way to exclude properties that are not defined on the object *itself*, but +way to exclude properties that are not defined on the object itself, but somewhere on its prototype chain. ### `hasOwnProperty` as a Property -JavaScript does **not** protect the property name `hasOwnProperty`; thus, if the +JavaScript does not protect the property name `hasOwnProperty`; thus, if the possibility exists that an object might have a property with this name, it is -necessary to use an *external* `hasOwnProperty` in order to get correct results. +necessary to use an *external* `hasOwnProperty` to get correct results. var foo = { hasOwnProperty: function() { @@ -44,14 +44,14 @@ necessary to use an *external* `hasOwnProperty` in order to get correct results. // Use another Object's hasOwnProperty and call it with 'this' set to foo ({}).hasOwnProperty.call(foo, 'bar'); // true - // It's also possible use the hasOwnProperty property from the Object property for this purpose + // It's also possible to use the hasOwnProperty property from the Object property for this purpose Object.prototype.hasOwnProperty.call(obj, 'bar'); // true ### In Conclusion -When checking for the existence of a property on a object, `hasOwnProperty` is -the **only** method of doing so. It is also recommended to make `hasOwnProperty` -part of **every** [`for in` loop](#object.forinloop); this will avoid errors from +Using `hasOwnProperty` is the **only** reliable method to check for the +existence of a property on an object. It is recommended that `hasOwnProperty` +is used in **every** [`for in` loop](#object.forinloop) to avoid errors from extended native [prototypes](#object.prototype). diff --git a/doc/en/object/prototype.md b/doc/en/object/prototype.md index 0a3b6d0c..abb67c58 100644 --- a/doc/en/object/prototype.md +++ b/doc/en/object/prototype.md @@ -4,16 +4,16 @@ JavaScript does not feature a classical inheritance model; instead, it uses a *prototypal* one. While this is often considered to be one of JavaScript's weaknesses, the -prototypal inheritance model is in fact more powerful than the classic model. -It is, for example, fairly trivial to build a classic model on top of it, while the -other way around is a far more difficult task. +prototypal inheritance model is in fact more powerful than the classic model. +It is, for example, fairly trivial to build a classic model on top of a +prototypal model, while the other way around is a far more difficult task. -Due to the fact that JavaScript is basically the only widely used language that -features prototypal inheritance, it takes some time to adjust to the -differences between the two models. +JavaScript is the only widely used language that features prototypal +inheritance, so it can take time to adjust to the differences between the two +models. -The first major difference is that inheritance in JavaScript is done by using so -called *prototype chains*. +The first major difference is that inheritance in JavaScript uses *prototype +chains*. > **Note:** Simply using `Bar.prototype = Foo.prototype` will result in both objects > sharing the **same** prototype. Therefore, changes to either object's prototype @@ -47,7 +47,7 @@ called *prototype chains*. Object.prototype { toString: ... /* etc. */ } -In the above, the object `test` will inherit from both `Bar.prototype` and +In the code above, the object `test` will inherit from both `Bar.prototype` and `Foo.prototype`; hence, it will have access to the function `method` that was defined on `Foo`. It will also have access to the property `value` of the **one** `Foo` instance that is its prototype. It is important to note that `new @@ -64,7 +64,7 @@ its prototype; thus, all `Bar` instances will share the **same** `value` propert When accessing the properties of an object, JavaScript will traverse the prototype chain **upwards** until it finds a property with the requested name. -When it reaches the top of the chain - namely `Object.prototype` - and still +If it reaches the top of the chain - namely `Object.prototype` - and still hasn't found the specified property, it will return the value [undefined](#core.undefined) instead. @@ -82,12 +82,13 @@ creation of prototype chains. ### Performance -The lookup time for properties that are high up on the prototype chain can have a -negative impact on performance critical sections of code. Additionally, trying to -access non-existent properties will always traverse the full prototype chain. +The lookup time for properties that are high up on the prototype chain can have +a negative impact on performance, and this may be significant in code where +performance is critical. Additionally, trying to access non-existent properties +will always traverse the full prototype chain. Also, when [iterating](#object.forinloop) over the properties of an object -**every** property that is on the prototype chain will get enumerated. +**every** property that is on the prototype chain will be enumerated. ### Extension of Native Prototypes @@ -95,7 +96,7 @@ One mis-feature that is often used is to extend `Object.prototype` or one of the other built in prototypes. This technique is called [monkey patching][1] and breaks *encapsulation*. While -used by widely spread frameworks such as [Prototype][2], there is still no good +used by popular frameworks such as [Prototype][2], there is still no good reason for cluttering built-in types with additional *non-standard* functionality. The **only** good reason for extending a built-in prototype is to backport @@ -104,11 +105,12 @@ the features of newer JavaScript engines; for example, ### In Conclusion -It is a **must** to understand the prototypal inheritance model completely -before writing complex code which makes use of it. Also, watch the length of -the prototype chains and break them up if necessary to avoid possible -performance issues. Further, the native prototypes should **never** be extended -unless it is for the sake of compatibility with newer JavaScript features. +It is **essential** to understand the prototypal inheritance model before +writing complex code that makes use of it. Also, be aware of the length of the +prototype chains in your code and break them up if necessary to avoid possible +performance problems. Further, the native prototypes should **never** be +extended unless it is for the sake of compatibility with newer JavaScript +features. [1]: http://en.wikipedia.org/wiki/Monkey_patch [2]: http://prototypejs.org/ From 472df35b9ddb5efd0716b7cf4a512af114a0eb00 Mon Sep 17 00:00:00 2001 From: Dawid Spiechowicz Date: Wed, 13 Jun 2012 11:19:19 +0300 Subject: [PATCH 047/277] Typo fix --- doc/pl/function/general.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/pl/function/general.md b/doc/pl/function/general.md index e3f035b2..c960c9b5 100644 --- a/doc/pl/function/general.md +++ b/doc/pl/function/general.md @@ -5,7 +5,7 @@ być przekazywane jak każda inna wartość. Jednym z typowych zastosowań tej c jest przekazywanie *anonimowej funkcji* jako callback do innej, prawdopodobnie asynchronicznej funkcji. -### Deklaracja funckcji +### Deklaracja funkcji function foo() {} From 3ec1079f22ba9f2c9834283baa66afac4e66d6d1 Mon Sep 17 00:00:00 2001 From: Dawid Spiechowicz Date: Wed, 13 Jun 2012 12:55:25 +0300 Subject: [PATCH 048/277] remove not needed english part --- doc/pl/function/this.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/doc/pl/function/this.md b/doc/pl/function/this.md index 89a5a1e5..3fa2d477 100644 --- a/doc/pl/function/this.md +++ b/doc/pl/function/this.md @@ -4,17 +4,12 @@ JavaScript posiada inną koncepcję odnośnie tego na co wskazuje słowo kluczow `this`, niż większość innych języków programowania. Istnieje dokładnie **pięć** różnych sytuacji, w których wartość `this` jest przypisana w języku JavaScript. -JavaScript has a different concept of what the special name `this` refers to -than most other programming languages do. There are exactly **five** different -ways in which the value of `this` can be bound in the language. - ### Zasięg globalny this; Używanie `this` w globalnym zasięgu, zwróci po prostu referencję do obiektu *global*. - ### Wywołanie funkcji foo(); From 332dcf0a6b1f5e007e7e8fce7a88cb5f8d21bc6b Mon Sep 17 00:00:00 2001 From: Dawid Spiechowicz Date: Wed, 13 Jun 2012 13:39:44 +0300 Subject: [PATCH 049/277] typo fix --- doc/pl/function/closures.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/pl/function/closures.md b/doc/pl/function/closures.md index 8cb6fb79..2c72db1b 100644 --- a/doc/pl/function/closures.md +++ b/doc/pl/function/closures.md @@ -3,7 +3,7 @@ Jedną z najpotężniejszych funkcjonalności języka JavaScript są *domknięcia*. Oznacza to że zasięg **zawsze** posiada dostęp do zewnętrznego zasięgu, w którym został zdefiniowany. Ponieważ zasięg w JavaScript można definiować tylko poprzez -[funckję](#function.scopes), wszystkie funkcje domyślnie zachowują się jak domknięcia. +[funkcję](#function.scopes), wszystkie funkcje domyślnie zachowują się jak domknięcia. ### Emulowanie prywatnych zmiennych From bb2ccece392d4883c3c12e6e9ccb9c46b7d7d7d4 Mon Sep 17 00:00:00 2001 From: Dawid Spiechowicz Date: Wed, 13 Jun 2012 14:01:11 +0300 Subject: [PATCH 050/277] typo fix, remove unused english part --- doc/pl/function/constructors.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/doc/pl/function/constructors.md b/doc/pl/function/constructors.md index 4e0f502e..d9be52a0 100644 --- a/doc/pl/function/constructors.md +++ b/doc/pl/function/constructors.md @@ -22,7 +22,7 @@ fukcja domyślnie zwraca wartość `this` - nowy obiekt. var test = new Foo(); -Powyżej wywołanya została funkcja `Foo` jako konstruktor oraz ustawia +Powyżej wywołana została funkcja `Foo` jako konstruktor oraz ustawia nowo utworzonemu obiektowi właściwość `prototype` na `Foo.prototype`. W tym przypadku jawna deklaracja `return` w funkcji zwraca wartość @@ -53,7 +53,7 @@ obiektu. Mimo że powyższy kod może zadziałać w pewnych przypadkach, w związku z działaniem [`this`](#function.this) w języku JavaScript, to jako -wartość `this`zostanie wykorzystany **obiekt global**. +wartość `this` zostanie wykorzystany **obiekt global**. ### Fabryki @@ -113,9 +113,7 @@ nowy obiekt wewnątrz tej fabryki. Mimo że powyższy kod jest odporny na brak słowa kluczowego `new` i ułatwia korzystanie ze [zmiennych prywatnych](#function.closures), to posiada pewne wady. -While the above is robust against a missing `new` keyword and certainly makes -the use of [private variables](#function.closures) easier, it comes with some -downsides. + 1. Zużywa więcej pamięci, ponieważ tworzony obiekt **nie** współdzieli metod poprzez prototyp. 2. Aby móc dziedziczyć fabryka musi skopiować wszystkie metody z dziedziczonego From 7d66a4b621d1a734e1ba029a7e85b96c3f1bc542 Mon Sep 17 00:00:00 2001 From: Dawid Spiechowicz Date: Wed, 13 Jun 2012 15:19:14 +0300 Subject: [PATCH 051/277] typo fix --- doc/pl/types/equality.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/pl/types/equality.md b/doc/pl/types/equality.md index 48f4197a..c655a795 100644 --- a/doc/pl/types/equality.md +++ b/doc/pl/types/equality.md @@ -58,7 +58,7 @@ to zachowują się różnie, gdy jednym z operandów jest obiekt typu `Object`. var foo = {}; foo === foo; // true -Oba operatory porównują **toższmość** a **nie** równość, czyli będą porównywać czy +Oba operatory porównują **tożsamość** a **nie** równość, czyli będą porównywać czy jeden i drugi operand jest tą samą **instancją** obiektu (podobnie jak operator `is` w Pythonie i porównanie wskaźników w C). From 0b7ecf874f31fee0fba7694099b862f07ca281e3 Mon Sep 17 00:00:00 2001 From: Dawid Spiechowicz Date: Wed, 13 Jun 2012 20:24:24 +0300 Subject: [PATCH 052/277] typo fix --- doc/pl/intro/license.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/pl/intro/license.md b/doc/pl/intro/license.md index c9329aab..5b0e855d 100644 --- a/doc/pl/intro/license.md +++ b/doc/pl/intro/license.md @@ -1,7 +1,7 @@ ## Licencja JavaScript Garden jest publikowany w ramach [licencji MIT] [1] i kod źródłowy znajduje -się na serwerze [GitHub] [2]. Jeśli znajdziesz jakieś błędy lub literówek zgłoś proszę +się na serwerze [GitHub] [2]. Jeśli znajdziesz jakieś błędy lub literówki, zgłoś proszę [problem] [3] lub rozwiąż go i zgloś pull request ze swojego repozytorium. Możesz nas także znaleźć w pokoju [JavaScript] [4] na chacie Stack Overflow. From 41d1d7e2f6701a8e6267b72e48d51f1fd9bb8a95 Mon Sep 17 00:00:00 2001 From: Evan Goer Date: Wed, 13 Jun 2012 21:19:50 -0700 Subject: [PATCH 053/277] Update master --- doc/en/types/typeof.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/en/types/typeof.md b/doc/en/types/typeof.md index 00377db4..348f8c9a 100644 --- a/doc/en/types/typeof.md +++ b/doc/en/types/typeof.md @@ -2,7 +2,7 @@ The `typeof` operator (together with [`instanceof`](#types.instanceof)) is probably the biggest -design flaw of JavaScript, as it is near of being **completely broken**. +design flaw of JavaScript, as it is nearly **completely broken**. Although `instanceof` still has its limited uses, `typeof` really has only one practical use case, which does **not** happen to be checking the type of an From c7177a380758ccb9c0fcccf0ef0109704ada5cff Mon Sep 17 00:00:00 2001 From: Seong-Rak Choi Date: Fri, 20 Jul 2012 10:34:24 +0900 Subject: [PATCH 054/277] =?UTF-8?q?-=20fix=20an=20mistranslated=20word:=20?= =?UTF-8?q?'=EB=AF=B8=EB=AC=98=ED=95=9C'=20to=20'=EC=9E=A1=EC=95=84?= =?UTF-8?q?=EB=82=B4=EA=B8=B0=20=EC=96=B4=EB=A0=A4=EC=9A=B4'=20-=20wrap=20?= =?UTF-8?q?the=20`method`=20keyword=20with=20link?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/ko/other/timeouts.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ko/other/timeouts.md b/doc/ko/other/timeouts.md index fb0384ed..ba2f6356 100644 --- a/doc/ko/other/timeouts.md +++ b/doc/ko/other/timeouts.md @@ -111,7 +111,7 @@ Id가 1부터 1000 사이에 있는 timeout들을 제거했지만, 그 외의 foo(a, b, c); }, 1000) -> **Note:** `setTimeout(foo, 1000, a, b, c)`처럼 사용하는 것도 가능하지만, 이것도 권장하지 않는다. 메소드를 사용할 때 미묘한 에러가 날 수 있다. +> **Note:** `setTimeout(foo, 1000, a, b, c)`처럼 사용하는 것도 가능하지만, 이것도 권장하지 않는다. [메소드](#function.this)를 사용할 때 잡아내기 어려운 에러가 날 수 있다. ### 결론 From deb2f903ebafc995715078c7a21a2d12f4e512a1 Mon Sep 17 00:00:00 2001 From: dishuostec Date: Fri, 27 Jul 2012 10:00:13 +0800 Subject: [PATCH 055/277] Fixed typo --- doc/zh/types/equality.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/zh/types/equality.md b/doc/zh/types/equality.md index eef0e9da..02f5280c 100755 --- a/doc/zh/types/equality.md +++ b/doc/zh/types/equality.md @@ -18,7 +18,7 @@ JavaScript 是*弱类型*语言,这就意味着,等于操作符会为了比 null == undefined // true " \t\r\n" == 0 // true -上面的表格展示了强类型转换,这也是使用 `==` 被广泛认为是不好编程习惯的主要原因, +上面的表格展示了强制类型转换,这也是使用 `==` 被广泛认为是不好编程习惯的主要原因, 由于它的复杂转换规则,会导致难以跟踪的问题。 此外,强制类型转换也会带来性能消耗,比如一个字符串为了和一个数组进行比较,必须事先被强制转换为数字。 @@ -27,7 +27,7 @@ JavaScript 是*弱类型*语言,这就意味着,等于操作符会为了比 严格等于操作符由**三**个等号组成:`===` -不想普通的等于操作符,严格等于操作符**不会**进行强制类型转换。 +不像普通的等于操作符,严格等于操作符**不会**进行强制类型转换。 "" === "0" // false 0 === "" // false From 213a3db7c161aab8f8ec560768c8365ab8b183ee Mon Sep 17 00:00:00 2001 From: Dr_rOot Date: Thu, 2 Aug 2012 15:42:50 +0800 Subject: [PATCH 056/277] Corrected a typing error. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 本省 => 本身 --- doc/zh/types/instanceof.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/zh/types/instanceof.md b/doc/zh/types/instanceof.md index 191c43c4..e2783ef7 100755 --- a/doc/zh/types/instanceof.md +++ b/doc/zh/types/instanceof.md @@ -12,7 +12,7 @@ new Bar() instanceof Bar; // true new Bar() instanceof Foo; // true - // 如果仅仅设置 Bar.prototype 为函数 Foo 本省,而不是 Foo 构造函数的一个实例 + // 如果仅仅设置 Bar.prototype 为函数 Foo 本身,而不是 Foo 构造函数的一个实例 Bar.prototype = Foo; new Bar() instanceof Foo; // false From 6196e7802f522d160d63f702f54f1ef1f5814e68 Mon Sep 17 00:00:00 2001 From: Changwoo Park Date: Mon, 10 Sep 2012 15:35:35 +0900 Subject: [PATCH 057/277] [ko] Up to date --- doc/ko/array/general.md | 7 ++++--- doc/ko/other/timeouts.md | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/ko/array/general.md b/doc/ko/array/general.md index 0a396d2e..3f7ae206 100644 --- a/doc/ko/array/general.md +++ b/doc/ko/array/general.md @@ -1,6 +1,6 @@ ## Array Iteration과 프로퍼티 -JavaScript에서는 Array도 객체 Iterate를 할 때 [`for in`](#object.forinloop)을 사용해서 좋을 게 없다. 실제로 Array에 `for in`을 사용하지 말아야 할 근거가 매우 많다. +JavaScript에서는 Array도 객체지만 [`for in`](#object.forinloop)을 사용해서 좋을 게 없다. 실제로 Array에 `for in`을 사용하지 말아야 할 근거가 매우 많다. > **Note:** JavaScript의 Array는 *Associative Array*가 **아니다**. JavaScript [객체](#object.general)는 key/value만 Mapping할 뿐이다. Associative Array는 순서를 보장하지만, 객체는 보장하지 않는다. @@ -30,9 +30,10 @@ Array를 Iterate할 때에는 구식인 `for`를 사용하는 것이 가장 빠 foo; // [1, 2, 3] foo.length = 6; - foo; // [1, 2, 3] + foo.push(4); + foo; // [1, 2, 3, undefined, undefined, undefined, 4] -현재 크기보다 더 작은 값을 할당하면 Array를 자르지만, 현재 크기보다 더 큰 값을 할당한다고 해서 Array를 늘리지 않는다. +현재 크기보다 더 작은 값을 할당하면 Array를 자르고, 현재 크기보다 더 큰 값을 할당하면 늘어난다. ### 결론 diff --git a/doc/ko/other/timeouts.md b/doc/ko/other/timeouts.md index fb0384ed..2083137e 100644 --- a/doc/ko/other/timeouts.md +++ b/doc/ko/other/timeouts.md @@ -104,7 +104,7 @@ Id가 1부터 1000 사이에 있는 timeout들을 제거했지만, 그 외의 function foo(a, b, c) {} // 절대 사용하면 안 됨 - setTimeout('foo(1,2, 3)', 1000) + setTimeout('foo(1, 2, 3)', 1000) // 대신 익명 함수를 사용하는 게 좋다. setTimeout(function() { From f6d46411c0108529f816e60e6ac33d07437dfe3e Mon Sep 17 00:00:00 2001 From: Zurian Vitaliy Date: Mon, 1 Oct 2012 16:33:30 +0300 Subject: [PATCH 058/277] Minor syntax changes --- doc/en/object/general.md | 2 +- doc/es/object/general.md | 2 +- doc/fi/object/general.md | 2 +- doc/ja/object/general.md | 2 +- doc/ko/object/general.md | 2 +- doc/pl/object/general.md | 2 +- doc/ru/object/general.md | 2 +- doc/tr/object/general.md | 2 +- doc/zh/object/general.md | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/en/object/general.md b/doc/en/object/general.md index aefbfb90..12f9c939 100644 --- a/doc/en/object/general.md +++ b/doc/en/object/general.md @@ -3,7 +3,7 @@ Everything in JavaScript acts like an object, with the only two exceptions being [`null`](#core.undefined) and [`undefined`](#core.undefined). - false.toString() // 'false' + false.toString(); // 'false' [1, 2, 3].toString(); // '1,2,3' function Foo(){} diff --git a/doc/es/object/general.md b/doc/es/object/general.md index ccdd1cce..90bc39e0 100644 --- a/doc/es/object/general.md +++ b/doc/es/object/general.md @@ -3,7 +3,7 @@ Todo en JavaScript actúa como un objeto, con las dos únicas excepciones de [`null`](#core.undefined) y [`undefined`](#core.undefined). - false.toString() // 'false' + false.toString(); // 'false' [1, 2, 3].toString(); // '1,2,3' function Foo(){} diff --git a/doc/fi/object/general.md b/doc/fi/object/general.md index c169117f..d3cf8c8f 100644 --- a/doc/fi/object/general.md +++ b/doc/fi/object/general.md @@ -2,7 +2,7 @@ Kaikki muuttujat, kahta poikkeusta lukuunottamatta, käyttäytyvät JavaScriptissä oliomaisesti. Nämä poikkeukset ovat [`null`](#core.undefined) sekä [`undefined`](#core.undefined). - false.toString() // epätosi + false.toString(); // epätosi [1, 2, 3].toString(); // '1,2,3' function Foo(){} diff --git a/doc/ja/object/general.md b/doc/ja/object/general.md index 2838cf91..7dd037a2 100644 --- a/doc/ja/object/general.md +++ b/doc/ja/object/general.md @@ -3,7 +3,7 @@ JavaScriptの全ての要素は2つの例外を除いて、オブジェクトのように振る舞います。 その2つとは[`null`](#core.undefined)と[`undefined`](#core.undefined)です。 - false.toString() // 'false' + false.toString(); // 'false' [1, 2, 3].toString(); // '1,2,3' function Foo(){} diff --git a/doc/ko/object/general.md b/doc/ko/object/general.md index 51ae6f60..ed07b39f 100644 --- a/doc/ko/object/general.md +++ b/doc/ko/object/general.md @@ -2,7 +2,7 @@ JavaScript에서 [`null`](#core.undefined)과 [`undefined`](#core.undefined)를 제외한 모든 것은 객체다. - false.toString() // 'false' + false.toString(); // 'false' [1, 2, 3].toString(); // '1,2,3' function Foo(){} diff --git a/doc/pl/object/general.md b/doc/pl/object/general.md index 9512c293..11589d72 100644 --- a/doc/pl/object/general.md +++ b/doc/pl/object/general.md @@ -3,7 +3,7 @@ Wszystko w JavaScripcie zachowuje sie jak obiekt, z dwoma wyjątkami [`null`](#core.undefined) oraz [`undefined`](#core.undefined). - false.toString() // 'false' + false.toString(); // 'false' [1, 2, 3].toString(); // '1,2,3' function Foo(){} diff --git a/doc/ru/object/general.md b/doc/ru/object/general.md index d5b65e7a..d3a12795 100644 --- a/doc/ru/object/general.md +++ b/doc/ru/object/general.md @@ -2,7 +2,7 @@ В JavaScript всё является объектом, лишь за двумя исключениями — [`null`](#core.undefined) и [`undefined`](#core.undefined). - false.toString() // 'false' + false.toString(); // 'false' [1, 2, 3].toString(); // '1,2,3' function Foo(){} diff --git a/doc/tr/object/general.md b/doc/tr/object/general.md index 6107ca66..cd4eb2f9 100644 --- a/doc/tr/object/general.md +++ b/doc/tr/object/general.md @@ -4,7 +4,7 @@ JavaScript'te iki istisna dışında her şey bir nesne olarak davranır; bu istisnalar da [`null`](#core.undefined) ve [`undefined`](#core.undefined) 'dır. - false.toString() // 'false' + false.toString(); // 'false' [1, 2, 3].toString(); // '1,2,3' function Foo(){} diff --git a/doc/zh/object/general.md b/doc/zh/object/general.md index b75b0fea..fa0adf2b 100755 --- a/doc/zh/object/general.md +++ b/doc/zh/object/general.md @@ -2,7 +2,7 @@ JavaScript 中所有变量都是对象,除了两个例外 [`null`](#core.undefined) 和 [`undefined`](#core.undefined)。 - false.toString() // 'false' + false.toString(); // 'false' [1, 2, 3].toString(); // '1,2,3' function Foo(){} From 5d68a8d5d5534d37d871165622ee7558a9128b78 Mon Sep 17 00:00:00 2001 From: jifeon Date: Mon, 8 Oct 2012 01:58:09 +0400 Subject: [PATCH 059/277] Update doc/ru/object/general.md fixes for #63 and #148 --- doc/ru/object/general.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/ru/object/general.md b/doc/ru/object/general.md index d5b65e7a..e00adfb6 100644 --- a/doc/ru/object/general.md +++ b/doc/ru/object/general.md @@ -84,14 +84,14 @@ // валидный JavaScript и валидный JSON { - 'foo': 'oof', - 'bar': 'rab' + "foo": "oof", + "bar": "rab" } - // валидный JavaScript и НЕ валидный JSON + // валидный JavaScript и НЕвалидный JSON { - foo: 'oof', - bar: 'rab' + foo: "oof", + bar: "rab" } [1]: http://ru.wikipedia.org/wiki/%D0%A5%D0%B5%D1%88-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0 From fe2b2d27e54a84ea9dac1a6702825279926cd3d1 Mon Sep 17 00:00:00 2001 From: Georgeek Date: Tue, 20 Nov 2012 16:20:10 +0200 Subject: [PATCH 060/277] Translation was clarified acts! --- doc/ru/object/general.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ru/object/general.md b/doc/ru/object/general.md index 9c22c5f6..21cc5d01 100644 --- a/doc/ru/object/general.md +++ b/doc/ru/object/general.md @@ -1,6 +1,6 @@ ## Объекты и их свойства -В JavaScript всё является объектом, лишь за двумя исключениями — [`null`](#core.undefined) и [`undefined`](#core.undefined). +В JavaScript всё ведет себя, как объект, лишь за двумя исключениями — [`null`](#core.undefined) и [`undefined`](#core.undefined). false.toString(); // 'false' [1, 2, 3].toString(); // '1,2,3' From 46d0058aa6258a12306b0fdc84fbfabe155b6f7f Mon Sep 17 00:00:00 2001 From: "ByungDae, Sohn" Date: Wed, 21 Nov 2012 13:42:31 +0900 Subject: [PATCH 061/277] corrected mistranslation and full korean translation improved --- .project | 11 +++++ doc/ko/array/constructor.md | 10 ++--- doc/ko/array/general.md | 20 ++++----- doc/ko/core/delete.md | 16 +++---- doc/ko/core/eval.md | 8 ++-- doc/ko/core/semicolon.md | 12 +++--- doc/ko/core/undefined.md | 9 ++-- doc/ko/function/arguments.md | 27 ++++++------ doc/ko/function/closures.md | 30 ++++++------- doc/ko/function/constructors.md | 24 ++++++----- doc/ko/function/general.md | 28 ++++++------- doc/ko/function/scopes.md | 74 ++++++++++++++++----------------- doc/ko/function/this.md | 10 ++--- doc/ko/intro/index.md | 3 +- doc/ko/object/forinloop.md | 16 +++---- doc/ko/object/general.md | 23 +++++----- doc/ko/object/hasownproperty.md | 18 ++++---- doc/ko/object/prototype.md | 36 ++++++++-------- doc/ko/other/timeouts.md | 55 ++++++++++++------------ doc/ko/types/casting.md | 6 +-- doc/ko/types/equality.md | 26 ++++++------ doc/ko/types/instanceof.md | 10 ++--- doc/ko/types/typeof.md | 20 ++++----- 23 files changed, 253 insertions(+), 239 deletions(-) create mode 100644 .project diff --git a/.project b/.project new file mode 100644 index 00000000..42a345c2 --- /dev/null +++ b/.project @@ -0,0 +1,11 @@ + + + JavaScript-Garden + + + + + + + + diff --git a/doc/ko/array/constructor.md b/doc/ko/array/constructor.md index 471fd60d..0c60a842 100644 --- a/doc/ko/array/constructor.md +++ b/doc/ko/array/constructor.md @@ -1,6 +1,6 @@ -## `Array` 생성자 +## `배열` 생성자 -`Array` 생성자가 파라미터를 처리하는 방법은 모호하다. 그래서 항상 `[]` 노테이션으로 Array를 만들어야 한다. +배열을 만들때 `배열` 생성자에 파라미터를 넣어 만드는 방법은 헷갈릴수있다. 그래서 항상 각 괄호(`[]`) 노테이션을 이용해 배열을 만들 것을 권한다 [1, 2, 3]; // Result: [1, 2, 3] new Array(1, 2, 3); // Result: [1, 2, 3] @@ -9,16 +9,16 @@ new Array(3); // Result: [] new Array('3') // Result: ['3'] -`Array` 생성자에 인자로 숫자를 넘기면 `length`가 그 숫자인 텅 빈 `Array` 하나를 반환된다. 생성자는 **오직** `length` 프로퍼티에 그 숫자를 할당하기만 하고 `Array`는 실제로 초기화하지 않는다. +`배열` 생성자에 숫자를 인자로 넣으면 그 숫자 크기 만큼의 빈 `배열`을 반환한다. 즉 배열의 `length`는 그 숫자가 된다. 이때 생성자는 **단지** `length` 프로퍼티에 그 숫자를 할당하기만 하고 `배열`은 실제로 초기화 하지도 않는다. var arr = new Array(3); arr[1]; // undefined 1 in arr; // false, 이 인덱스는 초기화되지 않음. -Array의 length 프로퍼티에 숫자를 할당해주는 이 기능이 유용할 때도 있긴 있다. `for loop`을 사용하지 않고 스트링을 더할 때가 그렇다. +`for`문을 사용하지 않고 문자열을 더하는 경우에는 length 프로퍼티에 숫자를 할당해주는 기능이 유용할 때도 있다. new Array(count + 1).join(stringToRepeat); ### 결론 -`Array` 생성자는 가능하면 사용하지 말아야 한다. `[]` 노테이션이 더 알맞다. 더 간략하고 명확하기 때문에 보기도 좋다. +`배열` 생성자는 가능하면 사용하지 말고, 각 괄호 (`[]`) 노테이션이을 사용하자. 후자가 더 간략하고 명확할 뿐만 아니라 보기도 좋다. diff --git a/doc/ko/array/general.md b/doc/ko/array/general.md index 0a396d2e..1a665fa3 100644 --- a/doc/ko/array/general.md +++ b/doc/ko/array/general.md @@ -1,29 +1,29 @@ -## Array Iteration과 프로퍼티 +## 배열 순회와 프로퍼티 -JavaScript에서는 Array도 객체 Iterate를 할 때 [`for in`](#object.forinloop)을 사용해서 좋을 게 없다. 실제로 Array에 `for in`을 사용하지 말아야 할 근거가 매우 많다. +JavaScript에서는 배열(Array)도 객체(Object)지만 객체 순회(Iterate)를 할 때 [`for in`](#object.forinloop)을 사용해서 좋을 게 없다. 실제로 배열을 탐색할때 `for in`문 사용하지 말아야 할 이유가 매우 많다. -> **Note:** JavaScript의 Array는 *Associative Array*가 **아니다**. JavaScript [객체](#object.general)는 key/value만 Mapping할 뿐이다. Associative Array는 순서를 보장하지만, 객체는 보장하지 않는다. +> **Note:** JavaScript의 배열은 *연관 배열(Associative Array)*이 **아니다**. JavaScript는 오직 key/value를 맵핑한 [객체](#object.general)만 있을 뿐이다. 연관 배열은 순서를 보장해주지만 객체는 순서를 보장하지 않는다. `for in`은 프로토타입 체인에 있는 프로퍼티를 모두 훑는(enumerate) 데다가 객체 자신의 프로퍼티만 훑으려면 [`hasOwnProperty`](#object.hasownproperty)를 사용해야 하기 때문에 `for`보다 20배 느리다. -### Iteration +### 배열 순회 -Array를 Iterate할 때에는 구식인 `for`를 사용하는 것이 가장 빠르다. +배열을 순회 할때는 일반적인 `for`문을 사용하는 것이 가장 빠르다. 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 값을 캐시해야 한다는 것을 꼭 기억해야 한다. +이 예제에서 `l = list.length`로 배열의 length 값을 캐시해야 한다는 것을 꼭 기억해야 한다. -매 Iterate마다 Array에 있는 `length` 프로퍼티에 접근하는 것은 좀 부담스럽다. 최신 JavaScript 엔진은 이 일을 알아서 처리해주기도 하지만 코드가 늘 새 엔진에서 실행되도록 보장할 방법이 없다. +매번 반복할때마다 배열에 있는 `length` 프로퍼티에 접근하는 것은 좀 부담스럽다. 최신 JavaScript 엔진은 이 일을 알아서 처리해주기도 하지만 코드가 늘 새 엔진에서 실행되도록 보장할 방법이 없다. 실제로 캐시 하지 않으면 성능이 반으로 줄어든다. ### `length` 프로퍼티 -`length` 프로퍼티의 *getter*는 단순히 Array 안에 있는 엘리먼트의 개수를 반환하고 *setter*는 Array를 할당한 수만큼 잘라 버린다. +`length` 프로퍼티의 *getter*는 단순히 Array 안에 있는 엘리먼트의 개수를 반환하고 *setter*는 배열을 할당한 수만큼 잘라 버린다. var foo = [1, 2, 3, 4, 5, 6]; foo.length = 3; @@ -32,8 +32,8 @@ Array를 Iterate할 때에는 구식인 `for`를 사용하는 것이 가장 빠 foo.length = 6; foo; // [1, 2, 3] -현재 크기보다 더 작은 값을 할당하면 Array를 자르지만, 현재 크기보다 더 큰 값을 할당한다고 해서 Array를 늘리지 않는다. +현재 크기보다 더 작은 값을 할당하면 배열을 자르지만, 현재 크기보다 더 큰 값을 할당한다고 해서 배열을 늘리진 않는다. ### 결론 -최적의 성능을 위해서는 `for`를 사용하고 `length` 프로퍼티 값을 캐시해야 한다. Array에 `for in`을 사용하면 성능도 떨어지고 버그 나기도 쉽다. +최적의 성능을 위해서는 `for`문을 사용하고 `length` 프로퍼티 값을 캐시해야 한다. 배열에 `for in`을 사용하면 성능도 떨어지고 버그 나기도 쉽다. diff --git a/doc/ko/core/delete.md b/doc/ko/core/delete.md index 342c04e9..7f008b2c 100644 --- a/doc/ko/core/delete.md +++ b/doc/ko/core/delete.md @@ -1,10 +1,10 @@ -## `delete` +## `delete` 연산자 -간단히 말해서 global 변수, Function, 등은 `DontDelete` 속성이기 때문에 delete하지 못 한다. +간단히 말해서 전역 변수와 전역 함수 그리고 `DontDelete` 속성을 가진 자바스크립트 객체는 삭제할 수 없다. ### Global 코드와 Function 코드 -Global이나 Function Scope에 정의한 Fuction이나 변수는 모두 Activation 객체나 Global 객체의 프로퍼티다. 이 프로퍼티는 모두 `DontDelete` 속성을 가진다. Global이나 Function 코드에서 변수나 Function의 정의하면 항상 `DontDelete` 프로퍼티로 만들어진다. 그러니까 delete할 수 없다: +전역이나 함수 스코프에 정의한 함수나 변수는 모두 Activation 객체나 전역 객체의 프로퍼티다. 이 프로퍼티는 모두 `DontDelete` 속성을 가진다. 전역이나 함수 코드에 정의한 변수와 함수는 항상 `DontDelete` 프로퍼티로 만들어지기 때문에 삭제될 수 없다: // Global 변수: var a = 1; // DontDelete가 설정된다. @@ -21,9 +21,9 @@ Global이나 Function Scope에 정의한 Fuction이나 변수는 모두 Activati delete f; // false f; // 1 -### Explicit 프로퍼티 +### 명시적인(Explicit) 프로퍼티 -다음 예제에서 만드는 프로퍼티는 delete할 수 있다. 이런 걸 Explicit 프로퍼티라고 부른다: +다음 예제에서 만드는 프로퍼티는 delete할 수 있다. 이런 걸 명시적인(Explicit) 프로퍼티라고 부른다: // Explicit 프로퍼티를 만든다: var obj = {x: 1}; @@ -33,7 +33,7 @@ Global이나 Function Scope에 정의한 Fuction이나 변수는 모두 Activati obj.x; // undefined obj.y; // undefined -`obj.x`와 `obj.y`는 `DontDelete` 속성이 아니라서 delete할 수 있다. 그러나 다음과 같은 코드도 잘 동작하기 때문에 헷갈린다: +`obj.x`와 `obj.y`는 `DontDelete` 속성이 아니라서 delete할 수 있다. 하지만 다음과 같은 코드도 잘 동작하기 때문에 헷갈린다: // IE를 빼고 잘 동작한다: var GLOBAL_OBJECT = this; @@ -42,7 +42,7 @@ Global이나 Function Scope에 정의한 Fuction이나 변수는 모두 Activati delete GLOBAL_OBJECT.a; // true GLOBAL_OBJECT.a; // undefined -[`this`](#function.this)가 Global 객체를 가리키는 것을 이용해서 명시적으로 프로퍼티 `a`를 선언하면 삭제할 수 있다. 이것은 꼼수다. +[`this`](#function.this)가 전역 객체를 가리키는 것을 이용해서 명시적으로 프로퍼티 `a`를 선언하면 삭제할 수 있다. 이것은 꼼수다. IE (적어도 6-8)는 버그가 있어서 안 된다. @@ -73,4 +73,4 @@ Host 객체를 delete하면 어떻게 될지 알 수 없다. 표준에는 어떻 ### 결론 -`delete` 연산자는 엉뚱하게 동작할 때가 잦다. 명시적으로 정의한 일반 객체의 프로퍼티만 delete하는 것이 안전하다. +`delete` 연산자는 엉뚱하게 동작할 때가 많다. 명시적으로 정의한 일반 객체의 프로퍼티만 delete하는 것이 안전하다. diff --git a/doc/ko/core/eval.md b/doc/ko/core/eval.md index 80706598..528b1883 100644 --- a/doc/ko/core/eval.md +++ b/doc/ko/core/eval.md @@ -1,6 +1,6 @@ ## 왜 `eval`을 사용하면 안 될까? -`eval` 함수는 스트링으로 된 JavaScript 코드를 Local Scope에서 실행한다. +`eval` 함수는 JavaScript 문자열을 지역 스코프에서 실행한다. var foo = 1; function test() { @@ -11,7 +11,7 @@ test(); // 3 foo; // 1 -`eval`을 `eval`이라는 이름으로 **직접** 직행할 때에만 Local Scope에서 실행된다. +`eval`함수는 `eval`이라는 이름으로 **직접** 실행할 때에만 지역 스코프에서 실행된다. 그리고 `eval`이라는 이름에 걸맞게 악명또한 높다. var foo = 1; function test() { @@ -23,7 +23,7 @@ test(); // 2 foo; // 3 -어쨌든 `eval`은 사용하지 말아야 한다. eval을 사용하는 경우의 99.9%는 사실 eval이 필요 없다. +어쨌든 `eval`은 사용하지 말아야 한다. eval을 사용하는 99.9%는 사실 eval 없이도 만들수있다. ### 가짜 `eval` @@ -31,7 +31,7 @@ ### 보안 이슈 -`eval`은 보안 문제도 있다. 단순히 **모든** 코드를 실행하기 때문에 신뢰하지 못하는 코드가 **절대로** 포함되지 않도록 주의해야 한다. +`eval`은 어떤 코드라도 **무조건** 실행하기 때문에 보안 문제도 있다. 따라서 신뢰하지 못하거나 모르는 코드가 포함되어 있을 경우 **절대로** 사용해서는 안된다. ### 결론 diff --git a/doc/ko/core/semicolon.md b/doc/ko/core/semicolon.md index f58e1782..7a384caa 100644 --- a/doc/ko/core/semicolon.md +++ b/doc/ko/core/semicolon.md @@ -1,6 +1,6 @@ -## 쎄미콜론을 자동으로 삽입해준다. +## 자동으로 삽입되는 쎄미콜론 -JavaScript는 C와 문법이 비슷하지만, 꼭 코드에 쎄미콜론을 사용하도록 강제하지 않는다. 그래서 생략할 수 있다. +JavaScript는 C와 문법이 비슷하지만, 꼭 코드에 쎄미콜론을 사용하도록 강제하지는 않는다. 그래서 생략할 수 있다. 사실 JavaScript는 쎄미콜론이 꼭 있어야 하고 없으면 이해하지 못한다. 그래서 JavaScript 파서는 쎄미콜론이 없으면 **자동으로** 쎄미콜론을 추가한다. @@ -81,18 +81,18 @@ JavaScript는 C와 문법이 비슷하지만, 꼭 코드에 쎄미콜론을 사 파서는 완전히 다른 코드로 만들어 버린다. 이것은 **오류**다. -### Parenthesis +### 괄호 해석 -쎄미콜론 없이 괄호가 붙어 있으면 파서는 쎄미콜론을 넣지 않는다. +파서는 괄호에는 쎄미콜론을 넣지 않는다. log('testing!') (options.list || []).forEach(function(i) {}) -파서는 다음과 같이 코드를 바꾼다. +그래서 다음과 같이 한줄로 코드를 바꾼다. log('testing!')(options.list || []).forEach(function(i) {}) -`log` 함수가 함수를 반환할 가능성은 거의 없다. 아마도 `undefined is not a function`이라는 `TypeError`가 발생할 거다. +이렇게 한줄로 바뀌면 `log` 함수가 함수를 반환할 가능성이 거의 없으므로 `undefined is not a function`이라는 `TypeError`가 발생한다. ### 결론 diff --git a/doc/ko/core/undefined.md b/doc/ko/core/undefined.md index 65748e1e..2bacc83b 100644 --- a/doc/ko/core/undefined.md +++ b/doc/ko/core/undefined.md @@ -1,6 +1,6 @@ ## `undefined`와 `null` -JavaScript는 `nothing`을 두 가지로 표현할 수 있고 그중 `undefined`가 더 유용하다. +JavaScript는 `nothing`을 표현할때 `null`과 `undefined` 두 가지로 표현할 수 있고 그중 `undefined`가 더 유용하다. ### `undefined`도 변수 @@ -13,9 +13,8 @@ JavaScript는 `nothing`을 두 가지로 표현할 수 있고 그중 `undefined` `undefined` 값이 반환될 때: - global 변수 `undefined`에 접근할 때. - - 아직 초기화하지 않은 변수 - - `return` 구문이 없는 함수는 `undefined`를 반환함. - - `return` 구문이 없는 함수는 `undefined`를 반환함. + - 선언은 했지만 아직 초기화하지 않은 변수에 접근할 때. + - `return` 구문이 없는 함수는 암묵적으로 `undefined`를 반환함. - `return` 구문으로 아무것도 반환하지 않을 때. - 없는 프로퍼티를 찾을 때. - 함수 인자가 생략될 때. @@ -30,7 +29,7 @@ global 변수 `undefined`는 `undefined`라는 객체를 가리키는 것뿐이 그래서 `undefined`와 비교하려면 먼저 `undefined`의 값을 찾아와야 한다. -`undefined` 변수가 바뀔 때를 대비해서 `undefined`라는 변수를 인자로 받는 [anonymous wrapper](#function.scopes)로 감싸고 아무런 인자를 넘기지 않는 꼼수를 사용한다. +`undefined` 변수가 바뀔 때를 대비해서 `undefined`라는 변수를 인자로 받는 [anonymous wrapper](#function.scopes)로 감싸고 인자를 넘기지 않는 꼼수를 사용한다. var undefined = 123; (function(something, foo, undefined) { diff --git a/doc/ko/function/arguments.md b/doc/ko/function/arguments.md index cda8407c..dcc5e8a2 100644 --- a/doc/ko/function/arguments.md +++ b/doc/ko/function/arguments.md @@ -1,12 +1,12 @@ ## `arguments` 객체 -JavaScript의 모든 Function Scope에는 `arguments`라는 특별한 변수가 있다. 이 변수는 Function에 넘겨진 모든 인자에 대한 정보가 담겨 있다. +JavaScript의 모든 함수 스코프에는 `arguments`라는 특별한 변수가 있다. 이 변수는 함수에 넘겨진 모든 인자에 대한 정보가 담겨 있다. > **Note:** `arguments` 변수는 Function 안에서 다시 정의할 수 없다. `var` 구문이나 파라미터에 `arguments`라는 이름으로 변수를 정의해도 변수가 재정의되지 않는다. -`length` 프로퍼티도 있는 데다가 여러모로 Array와 비슷하게 생겼지만 Array.prototype을 상속받지 않았다. `arguments` 객체는 `Array`가 아니다. +`arguments` 객체는 `Array`가 아니다. 물론 `length` 프로퍼티도 있고 여러모로 Array와 비슷하게 생겼지만 Array.prototype을 상속받지는 않았다. -그래서 `arguments`에는 `push`, `pop`, `slice` 같은 표준 메소드가 없다. `for`로 하는 Iteration은 원래 잘되지만 `Array`의 메소드를 이용하려면 `arguments`를 Array로 변환해야 한다. +그래서 `arguments`에는 `push`, `pop`, `slice` 같은 표준 메소드가 없다. 일반 `for`문을 이용해 순회는 할수 있지만, `Array`의 메소드를 이용하려면 `arguments`를 Array로 변환해야 한다. ### Array로 변환하기 @@ -18,7 +18,7 @@ JavaScript의 모든 Function Scope에는 `arguments`라는 특별한 변수가 ### arguemnts 객체 넘기기 -어떤 Function에서 다른 Function로 arguments 객체를 넘길 때에는 다음과 같이 하는 것이 좋다. +어떤 함수에서 다른 함수로 arguments 객체를 넘길 때에는 다음과 같은 방법을 권한다. (역주: foo 함수는 bar 함수 한번 랩핑한 함수다. ) function foo() { bar.apply(null, arguments); @@ -27,7 +27,7 @@ JavaScript의 모든 Function Scope에는 `arguments`라는 특별한 변수가 // 내곡동에 땅이라도 산다. } -`call`과 `apply`를 함께 사용하여 unbound wrapper도 쉽게 만들 수 있다. +또 다른 방법으로는 함수를 랩핑하지 않고, 풀어서 `call`과 `apply`를 함께 사용하는 방법이 있다. (역주: 프로토타입에 있는 method를 호출하기 전에 Foo 객체 안에 있는 method로 한번더 필터링하는 효과가 있다. ) function Foo() {} @@ -35,7 +35,7 @@ JavaScript의 모든 Function Scope에는 `arguments`라는 특별한 변수가 console.log(this, a, b, c); }; - // "method"의 unbound 버전 + // "method"를 풀어 쓴(unbound) 버전 // 이 Function의 인자: this, arg1, arg2...argN Foo.method = function() { @@ -43,9 +43,9 @@ JavaScript의 모든 Function Scope에는 `arguments`라는 특별한 변수가 Function.call.apply(Foo.prototype.method, arguments); }; -### 파라미터와 arguments 객체 인덱스 +### 일반 파라미터와 arguments 객체의 인덱스 -파라미터와 `arguments` 객체의 프로퍼티는 모두 *getter*와 *setter*를 가진다. +일반 파라미터와 `arguments` 객체의 프로퍼티는 모두 *getter*와 *setter*를 가진다. 그래서 파라미터나 `arguments` 객체의 프로퍼티의 값을 바꾸면 둘 다 바뀐다. @@ -62,7 +62,7 @@ JavaScript의 모든 Function Scope에는 `arguments`라는 특별한 변수가 } foo(1, 2, 3); -### 성능에 대한 진실과 오해. +### 성능에 대한 오해와 진실. `arguments` 객체는 항상 만들어 지지만 예외도 있다. `arguments`라는 이름의 변수를 Function 안에 정의하거나 그 이름으로 파라미터를 만들면 `arguemnts` 객체는 만들어지지 않는다. 그렇지만, 이럴때는 어차피 안쓰겠다는 의미니까 상관 없다. @@ -73,8 +73,8 @@ JavaScript의 모든 Function Scope에는 `arguments`라는 특별한 변수가 그러나 예외도 있다. 최신 JavaScript 엔진에서 `arguments.callee`를 사용하면 성능이 확 떨어진다. function foo() { - arguments.callee; // 이 Function를 가리킨다. - arguments.callee.caller; // 이 Function를 호출한 Function를 가리킨다. + arguments.callee; // 이 함수를 가리킨다. + arguments.callee.caller; // 이 함수를 호출한 부모함수를 가리킨다. } function bigLoop() { @@ -83,9 +83,10 @@ JavaScript의 모든 Function Scope에는 `arguments`라는 특별한 변수가 } } -이 코드에서 Callee와 Caller를 알아야 하기 때문에 `foo`는 더는 [인라인][1]하지 않는다. 이렇게 쓰면 인라인이 주는 성능상 장점을 포기해야 하는데다가 Function이 호출되는 상황(calling context)에 의존하게 돼 버려서 Encapsulation도 해친다. +위 코드에서 'foo' 함수는 자기 자신과 자신을 호출한 함수를 알아야 하기 때문에 더이상 [인라인][1]되지 않는다. 이렇게 쓰면 인라인이 주는 성능상 장점을 포기해야 하는데다가 이 함수가 호출되는 상황(calling context)에 의존하게 돼 버려서 캡슐화(Encapsulation)도 해친다. +(역주: 보통 코드가 컴파일 될때 코드를 인라인 시키면서 최적화 하는데, 위와 같이 arguments.callee나 caller를 사용하게 되면 런타임시에 해당 함수가 결정되므로 인라인 최적화를 할수가 없다.) -`arguments.callee`와 그 프로퍼티들은 **절대** 사용하지 말아야 한다. +`arguments.callee`와 arguments.callee의 프로퍼티들은 **절대** 사용하지 말자!. > **ES5 Note:** strict 모드에서 `arguments.callee`는 deprecated됐기 때문에 사용하면 `TypeError`가 난다. diff --git a/doc/ko/function/closures.md b/doc/ko/function/closures.md index 49628231..4d7463a6 100644 --- a/doc/ko/function/closures.md +++ b/doc/ko/function/closures.md @@ -1,8 +1,8 @@ -## Closure와 Reference +## 클로져(Closure)와 참조(Reference) -*Closure*는 JavaScript의 특장점 중 하나다. Closure에서는 그 Closure를 만든 외부 Scope에 접근할 있다. JavaScript에서 Scope을 만들려면 [Function Scope](#function.scopes)을 사용하는 방법밖에 없기 때문에 Closure는 함수로 만든다. +*클로져*는 JavaScript의 특장점 중 하나다. 클로저를 만들면 클로저 스코프 안에서 클로저를 만든 외부 스코프(Scope)에 항상 접근할 있다. JavaScript에서 스코프는 [함수 스코프](#function.scopes)밖에 없기 때문에 기본적으로 모든 함수는 클로저가 될수있다. -### private 변수 +### private 변수 만들기 function Counter(start) { var count = start; @@ -21,22 +21,22 @@ foo.increment(); foo.get(); // 5 -`Counter`는 `increment` Closure와 `get` Closure 두 개를 반환한다. 이 두 Closure는 `Counter` Scope에 대한 **reference**를 유지하고 있기 때문에 그 Scope에 있는 count 변수에 계속 접근할 수 있다. +여기서 `Counter`는 `increment` 클로저와 `get` 클로저 두 개를 반환한다. 이 두 클로저는 `Counter` 함수 스코프에 대한 **참조**를 유지하고 있기 때문에 이 함수 스코프에 있는 count 변수에 계속 접근할 수 있다. -### Private 변수가 진짜 맞나? +### Private 변수의 동작 원리 -JavaScript에서 Scope을 어딘가에 할당하거나 저장해두는 것이 불가능하다. 그래서 Scope 밖에서는 count 변수에 직접 접근할 수 없다. 꼭 Scope 안에서 정의한 두 closure를 통해서만 접근할 수 있다. +JavaScript에서는 스코프(Scope)를 어딘가에 할당해두거나 참조할수 없기 때문에 스코프 밖에서는 count 변수에 직접 접근할 수 없다. 접근할수 있는 유일한 방법은 스코프 안에 정의한 두 클로저를 이용하는 방법밖에 없다. var foo = new Counter(4); foo.hack = function() { count = 1337; }; -이 코드의 count는 `Counter` Scope의 변수 count가 아니다. `foo.hack`은 그 Scope 안에 정의되지 않았기 때문에 이 `count`는 *Global* 변수를 사용하는 것이다. +위 코드에서 `foo.hack` 함수는 Counter 함수 안에서 정의되지 않았기 때문에 이 함수가 실행되더라도 `Counter` 함수 스코프 안에 있는 count 값은 변하지 않는다. 대신 foo.hack 함수의 `count`는 *Global* 스코프에 생성되거나 이미 만들어진 변수를 덮어쓴다. -### Loop에서 Closure 사용하기 +### 반복문에서 클로저 사용하기 -많은 사람은 Loop에서 Closure를 사용할 때 자주 index 변수를 잘못 사용한다. +사람들이 반복문에서 클로저를 사용할 때 자주 실수를 하는 부분이 있는데 바로 인덱스 변수를 복사할때 발생한다. for(var i = 0; i < 10; i++) { setTimeout(function() { @@ -46,13 +46,13 @@ JavaScript에서 Scope을 어딘가에 할당하거나 저장해두는 것이 이 코드는 `0`부터 `9`까지의 수를 출력하지 않고 `10`만 열 번 출력한다. -이 *Anonymous* Function은 변수 `i`에 대한 참조를 저장했다가 `console.log`가 호출되는 시점에 `i`의 값을 사용한다. `console.log`가 호출되는 시점은 `for loop`이 이미 끝난 상태라서 `i` 값은 10이다. +타이머에 설정된 *익명* 함수는 변수 `i`에 대한 참조를 들고 있다가 `console.log`가 호출되는 시점에 `i`의 값을 사용한다. `console.log`가 호출되는 시점에서 `for loop`는 이미 끝난 상태기 때문에 `i` 값은 10이 된다. 기대한 결과를 얻으려면 `i` 값을 복사해 두어야 한다. -### 이 Reference 문제 해결하기 +### 앞의 참조 문제 해결하기 -[Anonymous Wrapper](#function.scopes)로 index 값을 복사하는 것이 좋다. +반복문의 index 값을 복사하는 가장 좋은 방법은 익명함수로 랩핑[Anonymous Wrapper](#function.scopes)하는 방법이다. for(var i = 0; i < 10; i++) { (function(e) { @@ -62,11 +62,11 @@ JavaScript에서 Scope을 어딘가에 할당하거나 저장해두는 것이 })(i); } -이 Anonymous Function의 인자로 `i`를 넘기면 이 함수의 파라미터 e에 i의 **값**이 복사된다. +이 익명 함수에 `i`를 인자로 넘기면 이 함수의 파라미터 e에 i의 **값**이 복사되어 넘어갈 것이다. -이 `setTimeout`는 anonymous function 파라미터인 `e`에 대한 참조를 갖게 되고 `e`는 loop의 상태에 따라 변하지 않는다. +그리고 `setTimeout`는 익명 함수의 파라미터인 `e`에 대한 참조를 갖게 되고 `e`값은 복사되어 넘어왔으므로 loop의 상태에 따라 변하지 않는다. -함수를 반환하는 Anonymous Wrapper를 이용하는 방법도 있다. 다음 코드는 위 코드와 같다. +또다른 방법으로 랩핑한 익명 함수에서 출력 함수를 반환하는 방법도 있다. 아래 코드는 위 코드와 동일하게 동작한다. for(var i = 0; i < 10; i++) { setTimeout((function(e) { diff --git a/doc/ko/function/constructors.md b/doc/ko/function/constructors.md index cb71cdeb..1aa6de4a 100644 --- a/doc/ko/function/constructors.md +++ b/doc/ko/function/constructors.md @@ -1,10 +1,10 @@ ## 생성자 -JavaScript에서 생성자는 다른 언어들과 다르게 `new` 키워드로 호출되는 함수가 생성자다. +JavaScript의 생성자는 다른 언어들과 다르게 `new` 키워드로 호출되는 함수가 생성자가 된다. -어쨌든 생성자로 호출된 함수의 this는 막 만들어진 객체를 참조한다. **막 만든** 객체의 [prototype](#object.prototype)에는 생성자의 prototype이 할당된다. +생성자로 호출된 함수의 this 객체는 새로 생성된 객체를 가리키고, **새로 만든** 객체의 [prototype](#object.prototype)에는 생성자의 prototype이 할당된다. -생성자에 `return` 구문이 없으면 this가 가리키는 객체를 반환한다. +그리고 생성자에 명시적인 `return` 구문이 없으면 this가 가리키는 객체를 반환한다. function Foo() { this.bla = 1; @@ -16,9 +16,9 @@ JavaScript에서 생성자는 다른 언어들과 다르게 `new` 키워드로 var test = new Foo(); -`new` 키워드가 실행되는 시점에 `Foo`를 생성자로 호출하고 `Foo.prototype`을 새 객체의 prototype에 할당한다. +위 코드는 `new` 키워드가 실행되는 시점에 `Foo`를 생성자로 호출하고 `Foo.prototype`을 새 객체의 prototype에 할당한다. -생성자에 `return` 구문이 있고 literal이 아니라 `객체`를 반환하면 그 객체가 반환된다. +아래 코드와 같이 생성자에 명시적인 `return` 문이 있는 경우에는 반환하는 값이 객체인 경우에만 그 값을 반환한다. function Bar() { return 2; @@ -37,11 +37,12 @@ JavaScript에서 생성자는 다른 언어들과 다르게 `new` 키워드로 new 키워드가 없으면 그 함수는 객체를 반환하지 않는다. function Foo() { - this.bla = 1; // gets set on the global object + this.bla = 1; // 전역객체에 할당된다. } Foo(); // undefined -이 함수는 그때그때 다르게 동작하지만 보통 [`this`](#function.this)의 규칙에 따라 `this`의 값으로 *Global 객체*가 사용된다.:w +위 예제는 그때그때 다르게 동작한다. 그리고 [`this`](#function.this) 객체의 동작 원리에 따라서 Foo 함수안의 `this`의 값은 *Global 객체*를 가리키게된다. +(역주: 결국 new 키워드를 빼고, 코드를 작성할 경우 원치 않은 this 참조 오류가 발생할 수 있다.) ### 팩토리 @@ -62,11 +63,12 @@ new 키워드가 없으면 그 함수는 객체를 반환하지 않는다. new Bar(); Bar(); -new 키워드가 있으나 없으니 `Bar` 생성자는 똑같이 동작한다. [Closure](#function.closures)가 할당된 method 프로퍼티가 있는 객체를 만들어 반환한다. +new 키워드의 유무과 관계없이 `Bar` 생성자의 동작은 동일한다. 즉 [클로저](#function.closures)가 할당된 method 프로퍼티가 있는 새로운 객체를 만들어 반환한다. -`new Bar()`는 반환된 객체의 prototype 프로퍼티에 아무런 영향을 주지 않는다. 객체를 반환하지 않는 생성자로 만들어지는 경우에만 객체의 prototype이 생성자의 것으로 할당된다. +`new Bar()`로 호출되는 생성자는 반환되는 객체의 prototype 프로퍼티에 아무런 영향을 주지 않는다. 객체를 반환하지 않는 생성자로 만들어지는 경우에만 객체의 prototype이 생성자의 것으로 할당된다. -그러니까 이 예제에서 `new` 키워드의 유무는 아무 차이가 없다. +그러니까 이 예제에서 `new` 키워드의 유무는 아무런 차이가 없다. +(역주: 생성자에 객체를 만들어 명시적으로 반환하면 new 키워드에 관계없이 잘 동작하는 생성자를 만들수있다. 즉, new 키워드가 빠졌을때 발생하는 this 참조 오류를 방어해준다.) ### 팩토리로 객체 만들기 @@ -89,7 +91,7 @@ new 키워드가 있으나 없으니 `Bar` 생성자는 똑같이 동작한다. return obj; } -`new` 키워드가 없어도 괜찮고 [private 변수](#function.closures)를 사용하기도 쉽다. 그렇지만, 단점도 있다. +`new` 키워드가 없어도 잘 동작하고 [private 변수](#function.closures)를 사용하기도 쉽다. 그렇지만, 단점도 있다. 1. prototype으로 메소드를 공유하지 않으므로 메모리를 좀 더 사용한다. 2. 팩토리를 상속하려면 모든 메소드를 복사하거나 객체의 prototype에 객체를 할당해 주어야 한다. diff --git a/doc/ko/function/general.md b/doc/ko/function/general.md index 402a34ec..091fd105 100644 --- a/doc/ko/function/general.md +++ b/doc/ko/function/general.md @@ -1,37 +1,37 @@ -## Function Declarations과 Function Expressions +## 함수 선언과 함수 표현식 -JavaScript의 Function은 First Class Object라서 일반 객체처럼 취급될 수 있다. 그래서 익명 함수를 비동기 함수의 callback 같은 거로 넘길 수 있다. +JavaScript에서 함수는 First Class Object다. 즉, 함수 자체가 또 다른 함수의 인자될 수 있다는 말이다. 그래서 익명 함수를 비동기 함수의 콜백으로 넘기는 것도 이런 특징을 이용한 일반적인 사용법이다. -### `function` Declaration +### `함수` 선언 function foo() {} -코드를 실행하기 전에 이 함수는 [Hoist](#function.scopes)되기 때문에 해당 Scope 어디에서나 이 함수를 호출할 수 있다. 심지어 함수를 정의하기 전에 호출해도 된다. +위와 같이 선언한 함수는 프로그램이 실행하기 전에 먼저 [호이스트(Hoist)](#function.scopes) (스코프가 생성)되기 때문에 정의된 스코프(Scope) 안에서는 어디서든 이 함수를 사용할 수 있다. 심지어 함수를 정의하기 전에 호출해도 된다. - foo(); // 이 코드가 실행되기 전에 foo가 만들어져서 잘 호출된다. + foo(); // 이 코드가 실행되기 전에 foo가 만들어지므로 잘 동작한다. function foo() {} -### `function` Expression +### `함수` 표현식 var foo = function() {}; -`foo` 변수에 *익명* 함수를 할당하는 예를 보자. +위 예제는 `foo` 변수에 *익명* 함수를 할당한다. foo; // 'undefined' foo(); // TypeError가 난다. var foo = function() {}; -JavaScript가 Hoist하는 것은 `var`로 선언하는 부분뿐이기 때문에 코드가 실행하기 전에 `foo` 변수는 정의된다. +'var'문을 이용해 선언하는 경우, 코드가 실행되기 전에 'foo' 라는 이름의 변수를 스코프의 맨 위로 올리게 된다.(호이스트 된다) 이때 foo 값은 undefiend로 정의된다. -그러나 할당은 런타임에만 가능한 일이라 할당하는 코드가 실행될 때까지 `foo`변수는 기본 값인 [undefined](#core.undefined)다. +하지만 변수에 값을 할당하는 일은 런타임 상황에서 이루어지게 되므로 실제 코드가 실행되는 순간의 `foo`변수는 기본 값인 [undefined](#core.undefined)이 된다. -### Named Function Expression +### 이름있는 함수 표현식 -Named Function을 할당하는 경우는 조금 특이하다. +이름있는 함수를 할당할때도 특이한 경우가 있다. var foo = function bar() { - bar(); // 된다. + bar(); // 이 경우는 동작 하지만, } - bar(); // ReferenceError + bar(); // 이 경우는 참조에러를 발생시킨다. -함수 밖에서는 `bar`를 사용할 수 없지만, 함수 안에서는 사용할 수 있다. JavaScript가 [이름을 찾는 방법](#function.scopes)이 있는데 function Scope에서는 항상 그 함수의 이름을 사용할 수 있다. +foo 함수 스코프 밖에서는 foo 변수 외에는 다른 값이 없기 때문에 `bar`는 함수 밖에서 사용할 수 없지만 함수 안에서는 사용할 수 있다. [이와 같은 방법](#function.scopes)으로 자바스크립트에서 어떤 함수의 이름은 항상 그 함수의 지역 스코프 안에서 사용할수있다. \ No newline at end of file diff --git a/doc/ko/function/scopes.md b/doc/ko/function/scopes.md index ad40e0f3..7792ee65 100644 --- a/doc/ko/function/scopes.md +++ b/doc/ko/function/scopes.md @@ -1,6 +1,6 @@ -## Scope과 Namespace + ## 스코프와 네임스페이스 -JavaScript는 '{}' Block이 배배 꼬여 있어도 문법적으로는 잘 처리하지만, Block Scope은 지원하지 않는다. 그래서 JavaScript에서는 항상 *Function Scope*을 사용한다. +JavaScript는 '{}' Block이 배배 꼬여 있어도 문법적으로는 잘 처리하지만, Block Scope은 지원하지 않는다. 그래서 JavaScript에서는 항상 *함수 스코프*를 사용한다. function test() { // Scope for(var i = 0; i < 10; i++) { // Scope이 아님 @@ -11,11 +11,11 @@ JavaScript는 '{}' Block이 배배 꼬여 있어도 문법적으로는 잘 처 > **Note:** 할당할 때, 반환할 때, Function 인자에서 사용되는 것을 제외하면 `{...}`는 모두 객체 리터럴이 아니라 Block 구문으로 해석된다. 그래서 [세미콜론을 자동으로 넣어주면](#core.semicolon) 에러가 생길 수 있다. -그리고 JavaScript에는 Namepspace 개념이 없어서 *항상 공유하는* namepace가 딱 하나다. +그리고 JavaScript에는 Namepspace 개념이 없기 때문에 모든 값이 하나의 *전역* 스코프에 정의된다. -변수를 사용할 때마다 JavaScript는 아는 Scope을 상위 방향으로 찾는다. Global Scope에까지 해당 변수를 찾지 못하면 `ReferenceError`가 난다. +변수를 참조 할 때마다 JavaScript는 해당 변수를 찾을 때까지 상위 방향으로 스코프를 탐색한다. 변수 탐색하다가 전역 스코프에서도 찾지 못하면 `ReferenceError`를 발생시킨다. -### Global 변수 지옥. +### 전역 변수 문제. // script A foo = '42'; @@ -23,7 +23,7 @@ JavaScript는 '{}' Block이 배배 꼬여 있어도 문법적으로는 잘 처 // script B var foo = '42' -이 두 스크립트는 전혀 다르다. Script A는 *Global* Scope에 `foo`라는 변수를 정의하는 것이고 Script B는 *현* Scope에 변수 `foo`를 정의하는 것이다. +이 두 스크립트는 전혀 다르다. Script A는 *전역* 스코프에 `foo`라는 변수를 정의하는 것이고 Script B는 *현* 스코프에 변수 `foo`를 정의하는 것이다. 다시 말하지만, 이 둘은 전혀 다르고 `var`가 없을 때 특별한 의미가 있다. @@ -36,7 +36,7 @@ JavaScript는 '{}' Block이 배배 꼬여 있어도 문법적으로는 잘 처 test(); foo; // 21 -Function에서 `var` 구문을 빼버리면 Global Scope의 `foo`의 값을 바꿔버린다. '뭐 이게 뭐가 문제야'라고 생각될 수 있지만 수천 줄인 JavaScript 코드에서 `var`를 빼먹어서 생긴 버그를 해결하는 것은 정말 어렵다. +test 함수 안에 있는 'foo' 변수에 `var` 구문을 빼버리면 Global Scope의 `foo`의 값을 바꿔버린다. '뭐 이게 뭐가 문제야'라고 생각될 수 있지만 수천 줄인 JavaScript 코드에서 `var`를 빼먹어서 생긴 버그를 해결하는 것은 정말 어렵다. // Global Scope var items = [/* some list */]; @@ -51,19 +51,19 @@ Function에서 `var` 구문을 빼버리면 Global Scope의 `foo`의 값을 바 } } -subLoop이 Global 변수 `i`의 값을 변경해버리기 때문에 외부 Loop은 `subLoop`을 한번 호출하고 나면 종료된다. 두 번째 `for` Loop에 `var`를 사용하여 `i`를 정의하면 이 문제는 생기지 않는다. 외부 Scope의 변수를 사용하는 것이 아니라면 `var`를 꼭 넣어야 한다. +subLoop 함수는 전역 변수 `i`의 값을 변경해버리기 때문에 외부에 있는 for문은 `subLoop`을 한번 호출하고 나면 종료된다. 두 번째 `for`문에 `var`를 사용하여 `i`를 정의하면 이 문제는 생기지 않는다. 즉, 의도적으로 외부 스코프의 변수를 사용하는 것이 아니라면 `var`를 꼭 넣어야 한다. -### Local 변수 +### 지역 변수 -JavaScript에서 Local 변수는 [Function 파라미터](#function.general)와 `var`로 정의한 변수뿐이다. +JavaScript에서 지역 변수는 [함수의 파라미터](#function.general)와 `var`로 정의한 변수밖에 없다. - // Global Scope + // 전역 공간 var foo = 1; var bar = 2; var i = 2; function test(i) { - // test Function의 local Scope + // test 함수의 지역 공간 i = 5; var foo = 3; @@ -71,11 +71,11 @@ JavaScript에서 Local 변수는 [Function 파라미터](#function.general)와 ` } test(10); -`foo`, `i`는 `test` Function Scope에 있는 Local 변수라서 Global의 `foo`, `i` 값은 바뀌지 않는다. 하지만 `bar`는 Global 변수이기 때문에 Global의 `bar` 값이 변경된다. +`foo` 변수와 `i` 변수는 `test`함수 스코프에 있는 지역 변수라서 전역 공간에 있는 `foo`, `i` 값은 바뀌지 않는다. 하지만 `bar`는 전역 변수이기 때문에 전역 공간에 있는 `bar`의 값이 변경된다. -### Hoisting +### 호이스팅(Hoisting) -JavaScript는 선언문을 모두 **Hoist**한다. Hoist는 `var` 구문이나 `function`을 선언문을 해당 Scope의 가장 처음으로 옮기는 것을 말한다. +JavaScript는 선언문을 모두 **호이스트(Hoist)**한다. 호이스트란 `var` 구문이나 `function` 선언문을 해당 스코프의 맨 위로 옮기는 것을 말한다. bar(); var bar = function() {}; @@ -94,7 +94,7 @@ JavaScript는 선언문을 모두 **Hoist**한다. Hoist는 `var` 구문이나 ` } } -코드를 본격적으로 실행하기 전에 JavaScript는 `var` 구문과 `function` 선언문을 해당 Scope의 상위로 옮긴다. +코드를 본격적으로 실행하기 전에 JavaScript는 `var` 구문과 `function` 선언문을 해당 스코프의 맨위로 옮긴다. // var 구문이 여기로 옮겨짐. var bar, someValue; // default to 'undefined' @@ -114,23 +114,23 @@ JavaScript는 선언문을 모두 **Hoist**한다. Hoist는 `var` 구문이나 ` } bar(); // bar()가 아직 'undefined'이기 때문에 TypeError가 남 - someValue = 42; // Hoisting은 할당문까지 옮기지 않는다. + someValue = 42; // Hoisting은 할당문은 옮기지 않는다. bar = function() {}; test(); -Block Scope이 없으므로 Loop이나 if의 Block 안에 있는 `var` 구문들까지도 모두 Function Scope의 앞쪽으로 옮겨진다. 그래서 `if` Block의 결과는 좀 이상해진다. +블록 스코프(Block Scope)는 없으므로 for문과 if문 안에 있는 `var` 구문들까지도 모두 함수 스코프 앞쪽으로 옮겨진다. 그래서 `if` Block의 결과는 좀 이상해진다. -원래 코드에서 `if` Block은 *Global 변수* `goo`를 바꾸는 것처럼 보였지만 Hoisting 후에는 *local 변수*를 바꾼다. +원래 코드에서 `if` Block은 *전역 변수* `goo`를 바꾸는 것처럼 보였지만 호이스팅(Hoisting) 후에는 *지역 변수*를 바꾼다. -*Hoisting*을 모르면 다음과 같은 코드는 `ReferenceError`를 낼 것으로 생각할 것이다. +*호이스팅*을 모르면 다음과 같은 코드는 `ReferenceError`를 낼 것으로 생각할 것이다. // SomeImportantThing이 초기화됐는지 검사한다. if (!SomeImportantThing) { var SomeImportantThing = {}; } -`var` 구문은 *Global Scope* 상단으로 옮겨지기 때문에 이 코드는 잘 동작한다. +`var` 구문은 *전역 스코프*의 맨위로 옮겨지기 때문에 이 코드는 잘 동작한다. var SomeImportantThing; @@ -143,11 +143,11 @@ Block Scope이 없으므로 Loop이나 if의 Block 안에 있는 `var` 구문들 ### 이름 찾는 순서 -JavaScript의 모든 Scope은 *현 객체*를 가리키는 [`this`](#function.this)를 가지고 있다. *Global Scope*에도 this가 있다. +JavaScript의 모든 Scope은 *현 객체*를 가리키는 [`this`](#function.this)를 가지고 있다. *전역 스코프*에도 this가 있다. -Function Scope에는 [`arguments`](#function.arguments)라는 변수가 하나 더 있다. 이 변수는 Function에 넘겨진 인자들이 담겨 있다. +함수 스코프에는 [`arguments`](#function.arguments)라는 변수가 하나 더 있다. 이 변수는 함수에 인자로 넘겨진 값들이 담겨 있다. -예를 들어 Function Scope에서 `foo`라는 변수에 접근할 때 JavaScript는 다음과 같은 순서로 찾는다. +예를 들어 함수 스코프에서 `foo`라는 변수에 접근할 때 JavaScript는 다음과 같은 순서로 찾는다. 1. 해당 Scope에서 `var foo` 구문으로 선언된 것을 찾는다. 2. Function 파라미터에서 `foo`라는 것을 찾는다. @@ -156,29 +156,29 @@ Function Scope에는 [`arguments`](#function.arguments)라는 변수가 하나 > **Note:** `arguments`라는 파라미터가 있으면 Function의 기본 객체인 `arguments`가 생성되지 않는다. -### Namespace +### 네임스페이스 -JavaScript에서는 Global Namepspace 하나밖에 없어서 변수 이름이 중복되기 쉽다. 하지만 *Anonymous Wrappers*가 있어서 쉽게 피해갈 수 있다. +JavaScript에서는 전역 공간(Namepspace) 하나밖에 없어서 변수 이름이 중복되기 쉽다. 하지만 *이름없는 랩퍼(Anonymous Wrappers)*를 통해 쉽게 피해갈 수 있다. (function() { - // 일종의 Namepspace라고 할 수 있다. + // 일종의 네임스페이스라고 할 수 있다. window.foo = function() { - // 이 Closure는 Global Scope에 노출된다. + // 이 클로저는 전역 스코프에 노출된다. }; - })(); // Function를 정의하자마자 실행한다. + })(); // 함수를 정의하자마자 실행한다. -Unnamed Function은 [expressions](#function.general)이기 때문에 호출되려면 먼저 Evaluate돼야 한다. +이름없는 함수는 [표현식(expressions)](#function.general)이기 때문에 호출되려면 먼저 평가(Evaluate)돼야 한다. - ( // 소괄호 안에 있는 것을 먼저 Evaluate한다. + ( // 소괄호 안에 있는 것을 먼저 평가한다. function() {} - ) // 그리고 Function 객체를 반환한다. - () // Evaluation된 결과를 호출한다. + ) // 그리고 함수 객체를 반환한다. + () // 평가된 결과를 호출한다. -Function을 Evaluate하고 바로 호출하는 방법이 몇가지 더 있다. 문법은 다르지만 똑같다. +함수를 평가하고 바로 호출하는 방법이 몇가지 더 있다. 문법은 다르지만 똑같다. - // Fucntion을 Evaluate하자마자 호출하는 방법들... + // 함수를 평가하자마자 호출하는 방법들... !function(){}(); +function(){}(); (function(){}()); @@ -186,6 +186,6 @@ Function을 Evaluate하고 바로 호출하는 방법이 몇가지 더 있다. ### 결론 -코드를 캡슐화할 때는 늘 *Anonymous Wrapper*로 Namepspace를 만들어 사용해야 한다. 이 Wrapper는 이름이 중복되는 것을 막아 주고 더 쉽게 모듈화할 수 있도록 해준다. +코드를 캡슐화할 때는 항상 *이름없는 랩퍼(Anonymous Wrapper)*로 네임스페이스를 만들어 사용할 것을 추천한다. 이 래퍼(Wrapper)는 이름이 중복되는 것을 막아 주고 더 쉽게 모듈화할 수 있도록 해준다. -그리고 Global 변수를 사용하는 것은 악질적인 습관이다. 이유야 어쨌든 에러 나기 쉽고 관리하기도 어렵다. +그리고 전역 변수를 사용하는 것은 좋지 못한 습관이다. 이유야 어쨌든 에러 나기 쉽고 관리하기도 어렵다. diff --git a/doc/ko/function/this.md b/doc/ko/function/this.md index 116b1250..b6d57aa6 100644 --- a/doc/ko/function/this.md +++ b/doc/ko/function/this.md @@ -1,4 +1,4 @@ -## `this` +## `this`의 동작 원리 다른 프로그래밍 언어에서 `this`가 가리키는 것과 JavaScript에서 `this`가 가리키는 것과는 좀 다르다. `this`가 가리킬 수 있는 객체는 정확히 5종류나 된다. @@ -42,7 +42,7 @@ Global Scope에서도 this가 사용될 수 있고 이때에는 *Global* 객체 > **Note:** 객체 리터럴에서 this는 그 객체를 가리키지 않는다. 예를 들어 `var obj= {me:this}`에서 `me`가 `obj`를 가리키는 것이 아니라 위에 설명한 5가지 객체 중 하나를 가리킨다. -### 대표적인 결점 +### 대표적인 함정 `this`가 Global 객체를 가리키는 것도 잘못 설계된 부분 중 하나다. 괜찮아 보이지만 실제로는 전혀 사용하지 않는다. @@ -69,14 +69,14 @@ Global Scope에서도 this가 사용될 수 있고 이때에는 *Global* 객체 ### Method할당 하기 -메소드를 변수에 *할당*해 버리기 때문에 Function Aliasing은 JavaScript에서 안된다. +JavaScript의 또다른 함정은 바로 함수의 별칭을 만들수 없다는 점이다. 별칭을 만들기 위해 메소드를 변수에 넣으면 자바스크립트는 별칭을 만들지 않고 바로 *할당*해 버린다. var test = someObject.methodTest; test(); -`test`는 다른 함수를 호출하는 것과 다름없어서 `this`가 someObject를 가리키지 않는다. +첫번째 코드로 인해 이제 `test`는 다른 함수와 똑같이 동작한다. 그래서 test 함수 내부의 `this`도 더이상 someObject를 가리키지 않는다. (역주: test가 methodTest의 별칭이라면 methodTest 함수 내부의 this도 someObject를 똑같이 가리켜야 하지만 test의 this는 더이상 someObject가 아니다.) -처음에는 `this`를 늦게 바인딩하는 것이 나쁜 아이디어라고 생각할 수도 있지만, 이 점이 실제로 [prototypal inheritance](#object.prototype)를 가능케 해준다. +이렇게 `this`를 늦게 바인딩해서 나타나는 약점때문에 늦은 바인딩이 나쁜 거라고 생각할수도 있지만, 사실 이런 특징으로 인해 [프로토타입 상속(prototypal inheritance)](#object.prototype)도 가능해진다. function Foo() {} Foo.prototype.method = function() {}; diff --git a/doc/ko/intro/index.md b/doc/ko/intro/index.md index 16d2ed66..87b72473 100644 --- a/doc/ko/intro/index.md +++ b/doc/ko/intro/index.md @@ -14,9 +14,10 @@ JavaScript Garden은 단순히 JavaScript 언어 자체를 설명하려 만들 - [Andreas Blixt][6] (언어 교정) ## 번역 - - [박창우][] + - [박창우][손병대][] [박창우]: https://github.com/pismute +[손병대]: https://github.com/miconblog ## 호스팅 diff --git a/doc/ko/object/forinloop.md b/doc/ko/object/forinloop.md index 5a619c47..fd05cedb 100644 --- a/doc/ko/object/forinloop.md +++ b/doc/ko/object/forinloop.md @@ -1,10 +1,10 @@ ## `for in` Loop -`in` 연산자와 마찬가지로 `for in`도 객체의 프로퍼티뿐만 아니라 프로토타입 체인까지 Traverse 한다. +객체의 프로퍼티를 탐색할때 `in` 연산자와 마찬가지로 `for in` 문도 프로토타입 체인까지 탐색한다. -> **Note:** `for in`은 Array의 `length`처럼 `enumerable` 속성이 `false`인 프로퍼티는 Iterate 하지 않는다. +> **Note:** `for in`문은 배열의 `length`프로퍼티처럼 `enumerable` 속성이 `false`인 프로퍼티는 탐색하지 않는다. - // 원래는 Object.prototype을 바꾸면 안 된다. + // Object.prototype을 오염시킨다. Object.prototype.bar = 1; var foo = {moo: 2}; @@ -12,9 +12,9 @@ console.log(i); // bar와 moo 둘 다 출력한다. } -선택적으로 Iterate 하려면 `for in`은 바꿀 수 없으니까 Loop 바디에서 하는 수밖에 없다. `Object.prototype`의 [`hasOwnProperty`](#object.hasownproperty)메소드를 사용하면 객체의 프로퍼티만 골라낼 수 있다. +`for in`문에 정의된 기본 동작을 바꿀순 없기 때문에 루프 안에서 불필요한 프로퍼티를 필터링 해야한다. 그래서 `Object.prototype`의 [`hasOwnProperty`](#object.hasownproperty)메소드를 이용해 본래 객체의 프로퍼티만 골라낸다. -> **Note:** `for in`은 프로토타입 체인을 모두 Traverse 한다. 그래서 상속할 때마다 더 느려진다. +> **Note:** `for in`은 프로토타입 체인을 모두 탐색하기 때문에 상속할 때마다 더 느려진다. ### `hasOwnProperty`로 필터링 하기 @@ -25,12 +25,12 @@ } } -실무에 사용할 작정이라면 이렇게 써야 옳다. `hasOwnProperty` 때문에 **오직** `moo`만 출력된다. `hasOwnProperty`가 없으면 `Object.prototype`같은 네이티브 프로토타입이 확장될 때 에러 날 수 있다. +위와 같이 사용해야 올바른 사용법이다. `hasOwnProperty` 때문에 **오직** `moo`만 출력된다. `hasOwnProperty`가 없으면 이 코드는 `Object.prototype`으로 네이티브 객체가 확장될 때 에러가 발생할 수 있다. -네이티브 프로토타입을 확장하는 [Proptotype 라이브러리][1]을 사용하면 `hasOwnProperty`가 없는 `for in` Loop은 꼭 문제를 일으킨다. +따라서 [Proptotype 라이브러리][1]처럼 네이티브 객체를 프로토타입으로 확장한 프레임워크를 사용할 경우 `for in` 문에 `hasOwnProperty`를 사용하지 않을 경우 문제가 발생할 수 있다. ### 결론 -`hasOwnProperty`는 항상 사용해야 한다. 실제로 코드가 동작할 환경에서 네이티브 프로토타입의 확장 여부에 대해 어떠한 가정도 하지 말아야 한다. +`hasOwnProperty`를 항상 사용하길 권한다. 실제 코드가 동작하는 환경에서는 절대로 네이티브 객체가 프로토타입으로 확장됐다 혹은 확장되지 않았다를 가정하면 안된다. [1]: http://www.prototypejs.org/ diff --git a/doc/ko/object/general.md b/doc/ko/object/general.md index 51ae6f60..0e7ae1c6 100644 --- a/doc/ko/object/general.md +++ b/doc/ko/object/general.md @@ -1,6 +1,6 @@ ## 객체와 프로퍼티 -JavaScript에서 [`null`](#core.undefined)과 [`undefined`](#core.undefined)를 제외한 모든 것은 객체다. +JavaScript에서 [`null`](#core.undefined)과 [`undefined`](#core.undefined)를 제외한 모든 것들은 객체처럼 동작한다. false.toString() // 'false' [1, 2, 3].toString(); // '1,2,3' @@ -9,11 +9,11 @@ JavaScript에서 [`null`](#core.undefined)과 [`undefined`](#core.undefined)를 Foo.bar = 1; Foo.bar; // 1 -숫자 리터럴은 객체가 아니라는 오해가 있는데 단지 JavaScript 파서의 문제일 뿐이다. JavaScript 파서는 숫자에 *Dot Notation*이 들어가면 오류라고 생각한다. +숫자 리터럴은 객체처럼 사용되지 못할꺼라는 오해가 있는데 이것은 단지 JavaScript 파서의 문제일 뿐이다. JavaScript 파서는 숫자에 *Dot Notation*이 들어가면 오류라고 생각한다. 2.toString(); // SyntaxError가 난다. -하지만, 숫자를 객체로 인식하는 꼼수가 몇 가지 있다. +하지만, 숫자를 객체처럼 사용할수 있는 꼼수가 몇 가지 있다. 2..toString(); // 두 번째 점은 잘 된다. 2 .toString(); // 왼쪽 공백이 있으면 잘 된다. @@ -21,7 +21,7 @@ JavaScript에서 [`null`](#core.undefined)과 [`undefined`](#core.undefined)를 ### Object 타입 -JavaScript 객체는 name/value 쌍으로 된 프로퍼티로 구성되기 때문에 [*Hashmap*][1]으로도 사용할 수 있다. +JavaScript 객체는 name/value 쌍으로 된 프로퍼티로 구성되기 때문에 [*Hashmap*][1]처럼 사용될 수도 있다. 객체 리터럴인 Object Notation으로 객체를 만들면 `Object.prototype`을 상속받고 [프로퍼티를 하나도 가지지 않은](#object.hasownproperty) 객체가 만들어진다. @@ -30,9 +30,9 @@ JavaScript 객체는 name/value 쌍으로 된 프로퍼티로 구성되기 때 // 값이 12인 'test' 프로퍼티가 있는 객체를 만든다. var bar = {test: 12}; -### 프로퍼티 +### 프로퍼티 접근 -객체의 프로퍼티는 Dot Notation이나 Square Bracket Notation으로 접근할 수 있다. +객체의 프로퍼티는 객체이름 다음에 점을 찍어(Dot Notation) 접근하거나 각괄호를 이용해(Square Bracket Notation) 접근할 수 있다. var foo = {name: 'Kitten'} foo.name; // kitten @@ -44,12 +44,11 @@ JavaScript 객체는 name/value 쌍으로 된 프로퍼티로 구성되기 때 foo.1234; // SyntaxError foo['1234']; // works - -'[]'은 프로퍼티를 동적으로 할당할 수 있고 변수 이름 규칙에도 구애받지 않는다. 그렇지만, 두 가지 방법은 근본적으로 서로 똑같다. +두 방식 모두 거의 동일하게 동작한다. 다만 차이가 있다면 각괄호 방식은 프로퍼티 이름을 동적으로 할당해서 값에 접근 할수 있지만 점을 이용한 방식은 구문 오류를 발생시킨다. ### 프로퍼티 삭제 -객체의 프로퍼티는 `delete`로만 삭제할 수 있다. 프로퍼티에 `undefined`나 `null`을 할당하는 것은 프로퍼티를 삭제하는 것이 아니라 프로퍼티에 할당된 *value*만 지우고 *key*는 그대로 두는 것이다. +객체의 프로퍼티를 삭제하려면 `delete`를 사용해야만 한다. 프로퍼티에 `undefined`나 `null`을 할당하는 것은 프로퍼티를 삭제하는 것이 아니라 프로퍼티에 할당된 *value*만 지우고 *key*는 그대로 두는 것이다. var obj = { bar: 1, @@ -67,7 +66,7 @@ JavaScript 객체는 name/value 쌍으로 된 프로퍼티로 구성되기 때 } -`baz`만 제거했기 때문에 `bar undefined`와 `foo null`은 출력되고 `baz`와 관련된 것은 출력되지 않는다. +위 코드의 출력 결과는 `baz`만 제거했기 때문에 `bar undefined`와 `foo null`은 출력되고 `baz`와 관련된 것은 출력되지 않는다. ### Notation of Keys @@ -76,8 +75,8 @@ JavaScript 객체는 name/value 쌍으로 된 프로퍼티로 구성되기 때 delete: 'I am a keyword, so me too' // SyntaxError가 난다. }; -프로퍼티의 key에 문자열이나 스트링을 사용할 수 있다. 이 부분도 JavaScript 파서의 설계 오류다. ECMAScript 5 이전에는 `SystaxError`가 났었다. +프로퍼티는 따옴표 없는 문자열(plain characters)과 따옴표로 감싼 문자열(strings)을 모두 Key 값으로 사용할 수 있다. 하지만 위와 같은 코드는 JavaScript 파서의 잘못된 설계 때문에 구버전(ECMAScript 5 이전 버전)에서는 `SystaxError`가 발생할 것이다. -이 에러는 `delete`가 키워드이기 때문에 발생하는 것이다. key를 스트링 리터럴로 정의하면 JavaScript 엔진은 언제나 잘 해석한다. +위 코드에서 문제가 되는 `delete` 키워드를 따옴표로 감싸면 구버전의 JavaScript 엔진에서도 제대로 해석될 것이다. [1]: http://en.wikipedia.org/wiki/Hashmap diff --git a/doc/ko/object/hasownproperty.md b/doc/ko/object/hasownproperty.md index b53ad583..fa36645e 100644 --- a/doc/ko/object/hasownproperty.md +++ b/doc/ko/object/hasownproperty.md @@ -1,12 +1,12 @@ ## `hasOwnProperty` -어떤 프로퍼티가 해당 객체 자신의 것인지 아니면 [프로토타입 체인](#object.prototype)에 있는 것인지 확인하려면 `Object.prototype`을 상속받은 `hasOwnProperty` 메소드를 사용해야 한다. +어떤 객체의 프로퍼티가 자기 자신의 프로퍼티인지 아니면 [프로토타입 체인](#object.prototype)에 있는 것인지 확인하려면 `hasOwnProperty` 메소드를 사용한다. 그리고 이 메소드는 `Object.prototype`으로 부터 상속받아 모든 객체가 가지고 있다. -> **Note:** 이 메소드로는 프로퍼티의 값이 `undefined`인지 확인할 수 없다. 프로퍼티가 존재해도 그 값은 `undefined`일 수 있다. +> **Note:** hasOwnProperty 메소드로는 어떤 프로퍼티가 존재하는지 확인하는 용도로는 사용할수 있지만, 그 값이 `undefined`일 수 있기 때문에 어떤 프로퍼티의 값이 `undefined`인지 확인하는 용도로 사용하긴 어렵다. -프로토타입 체인을 Traverse 하지 않으려면 `hasOwnProperty`를 사용하는 방법밖에 없다. +`hasOwnProperty`메소드는 프로토타입 체인을 탐색하지 않고, 프로퍼티를 다룰수있는 유일한 방법이다. - // Object.prototype을 더럽힌다. + // Object.prototype을 오염시킨다. Object.prototype.bar = 1; var foo = {goo: undefined}; @@ -16,11 +16,11 @@ foo.hasOwnProperty('bar'); // false foo.hasOwnProperty('goo'); // true -프로퍼티의 존재 여부를 확인하는 방법은 `hasOwnProperty` 메소드 뿐이다. 이 메소드는 프로토타입 체인의 프로퍼티말고 해당 객체의 프로퍼티만 Iterate할 때 유용하다. 객체 자체의 프로퍼티와 프로토타입 체인 어딘가에 있는 프로퍼티를 골라 주는 다른 방법은 없다. +`hasOwnProperty` 메소드는 어떤 프로퍼티가 자기 자신의 프로퍼티인지 아닌지 정확하게 알려주기 때문에 객체의 프로퍼티를 순회할때 꼭 필요하다. 그리고 프로토타입 체인 어딘가에 정의된 프로퍼티만을 제외하는 방법은 없다. -### `hasOwnProperty`도 프로퍼티 +### `hasOwnProperty` 메소드도 프로퍼티다 -JavaScript는 `hasOwnProperty` 프로퍼티도 보호해주지 않는다. 그래서 객체에 `hasOwnProperty` 프로퍼티가 있으면 다른 객체의 `hasOwnProperty` 메소드를 빌려 사용해야 한다. +JavaScript는 `hasOwnProperty`라는 이름으로 프로퍼티를 덮어 쓸수도 있다. 그래서 객체 안에 같은 이름으로 정의된 `hasOwnProperty`가 있을 경우, 본래 `hasOwnProperty`의 값을 정확하게 얻고 싶다면 다른 객체의 `hasOwnProperty` 메소드를 빌려써야 한다. var foo = { hasOwnProperty: function() { @@ -34,10 +34,10 @@ JavaScript는 `hasOwnProperty` 프로퍼티도 보호해주지 않는다. 그래 // 다른 객체의 hasOwnProperty를 사용하여 foo 객체의 프로퍼티 유무를 확인한다. ({}).hasOwnProperty.call(foo, 'bar'); // true - // Object에 원래 있는 hasOwnProperty를 사용해도 된다. + // Object에 있는 hasOwnProperty를 사용해도 된다. Object.prototype.hasOwnProperty.call(obj, 'bar'); // true ### 결론 -객체에 프로퍼티가 있는지 `hasOwnProperty`로만 확인할 수 있다. [`for in` loop](#object.forinloop)은 항상 `hasOwnProperty`와 함께 사용해야 한다. 네이티브 객체의 [프로토타입](#object.prototype)을 확장하는 사태가 일어나도 안전하게 지켜줄 것이다. +어떤 객체에 원하는 프로퍼티가 있는지 확인하는 가장 확실한 방법은 `hasOwnProperty`를 사용하는 것이다. [`for in` loop](#object.forinloop)에서 네이티브 객체에서 확장된 프로퍼티를 제외하고 순회하려면 `hasOwnProperty`와 함께 사용하길 권한다. diff --git a/doc/ko/object/prototype.md b/doc/ko/object/prototype.md index e2d591cc..9e8ffb2a 100644 --- a/doc/ko/object/prototype.md +++ b/doc/ko/object/prototype.md @@ -2,13 +2,13 @@ Javascript는 클래스 스타일의 상속 모델을 사용하지 않고 *프로토타입* 스타일의 상속 모델을 사용한다. -'이 점이 JavaScript의 약점이다.'라고 말하는 사람들도 있지만 실제로는 prototypal inheritance 모델이 훨씬 더 강력하다. 왜냐하면, 프로토타입 모델에서 클래스 모델을 흉내 내기는 매우 쉽지만, 반대로 클래스 모델에서 프로토타입 모델을 흉내 내기란 너무 어렵다. +'이 점이 JavaScript의 약점이다.'라고 말하는 사람들도 있지만 실제로는 prototypal inheritance 모델이 훨씬 더 강력하다. 그 이유는 프로토타입 모델에서 클래스 모델을 흉내 내기는 매우 쉽지만, 반대로 클래스 모델에서 프로토타입 모델을 흉내 내기란 매우 어렵기 때문이다. -실제로 Prototypal Inheritance 모델을 채용한 언어 중에서 JavaScript만큼 널리 사용되는 언어는 없었기 때문에 너무 늦게 두 모델의 차이점이 정리된 감이 있다. +실제로 Prototypal Inheritance 모델을 채용한 언어 중에서 JavaScript만큼 널리 사용된 언어가 없었기 때문에 두 모델의 차이점이 다소 늦게 정리된 감이 있다. -JavaScript는 *프로토타입 체인*이라는 것으로 상속을 구현한다. +먼저 가장 큰 차이점은 *프로토타입 체인*이라는 것을 이용해 상속을 구현한다는 점이다. -> **Note:** 간단히 말해서 `Bar.prototype = Foo.prototype`은 두 객체가 **하나의 프로토타입**을 공유하는 것이다. 그래서 한 객체의 프로토타입을 변경하면 그 프로토타입 객체를 사용하는 다른 객체에도 영향을 끼친다. 대부분은 나쁜 결과로 이어진다. +> **Note:** 간단히 말해서 `Bar.prototype = Foo.prototype`은 두 객체가 **하나의 프로토타입**을 공유하는 것이다. 그래서 한 객체의 프로토타입을 변경하면 그 프로토타입 객체를 사용하는 다른 객체도 영향을 받는다. 따라서 대부분의 경우 프로토타입을 변경하지는 않는다. function Foo() { this.value = 42; @@ -23,7 +23,7 @@ JavaScript는 *프로토타입 체인*이라는 것으로 상속을 구현한다 Bar.prototype = new Foo(); Bar.prototype.foo = 'Hello World'; - // Bar function을 생성자로 만들고 + // Bar 함수를 생성자로 만들고 Bar.prototype.constructor = Bar; var test = new Bar() // bar 인스턴스를 만든다. @@ -37,42 +37,42 @@ JavaScript는 *프로토타입 체인*이라는 것으로 상속을 구현한다 Object.prototype { toString: ... /* etc. */ } -`Bar.prototype`과 `Foo.prototype`을 둘 다 상속받았기 때문에 `test` 객체는 Foo에 정의한 `method` 함수에 접근할 수 있다. 프로토타입 체인에 있는 `Foo` 인스턴스의 `value` 프로퍼티도 사용할 수 있다. `new Bar()`를 해도 `Foo` 인스턴스는 새로 만들어지지 않고 Bar의 prototype에 있는 것을 재사용한다. 그래서 모든 Bar 인스턴스의 `value` 프로퍼티에 들어 있는 객체는 전부 **같은 객체다**. +위 코드에서 `test` 객체는 `Bar.prototype`과 `Foo.prototype`을 둘 다 상속받았기 때문에 Foo에 정의한 `method` 함수에 접근할 수 있다. 그리고 프로토타입 체인에 있는 `Foo` 인스턴스의 `value` 프로퍼티도 사용할 수 있다. `new Bar()`를 해도 `Foo` 인스턴스는 새로 만들어지지 않고 Bar의 prototype에 있는 것을 재사용한다. 그래서 모든 Bar 인스턴스는 **같은** `value` 프로퍼티를 공유한다. -> **Note:** `Bar.prototype = Foo`라고 하는 것은 `Foo`의 prototype을 가리키는 것이 아니라 Foo라는 Function의 prototype을 가리키는 것이다. 그래서 프로토타입 체인에 `Foo.prototype` 대신 `Function.prototype`이 들어서는 것이기 때문에 `method` 프로퍼티는 못 찾는다. +> **Note:** `Bar.prototype = Foo`라고 하는 것은 `Foo`의 prototype을 가리키는 것이 아니라 Foo라는 Function의 prototype을 가리키는 것이다. 그래서 프로토타입 체인에 `Foo.prototype` 대신 `Function.prototype`이 들어가 있기 때문에 `method` 프로퍼티는 찾지 못한다. -### 프로토타입 찾기 +### 프로토타입 탐색 -객체의 프로퍼티에 접근을 시도하면 JavaScript는 해당 이름의 프로퍼티를 찾을 때까지 위쪽으로 프로토타입 체인을 뒤진다. +객체의 프로퍼티에 접근하려고 하면 JavaScript는 해당 이름의 프로퍼티를 찾을 때까지 프로토타입 체인을 거슬러 올라가면서 탐색하게 된다. -체인의 끝까지 찾았는데도(보통은 `Object.prototype`임) 발견하지 못하면 [undefined](#core.undefined)를 반환한다. +프로토타입 체인을 끝까지 탐색했음에도(보통은 `Object.prototype`임) 불구하고 원하는 프로퍼티를 찾지 못하면 [undefined](#core.undefined)를 반환한다. ### prototype 프로퍼티 -prototype 프로퍼티는 프로토타입 체인을 만드는 데 사용하고 어떤 거라도 할당할 수 있지만, primitive 값을 할당하면 무시된다. +prototype 프로퍼티는 프로토타입 체인을 만드는 데 사용하고 어떤 값이든 할당할 수 있지만, primitive 값을 할당되면 무시한다. function Foo() {} Foo.prototype = 1; // 무시됨 -객체를 할당하면 프로토타입 체인이 동적으로 잘 만들어진다. +반면에 위 예제처럼 객체를 할당하면 프로토타입 체인이 동적으로 잘 만들어진다. ### 성능 -성능이 중요한 부분에서는 프로토타입 체인을 따라 프로퍼티를 찾는 것이 부담일 수 있다. 게다가 없는 프로퍼티에 접근하면 항상 프로토타입 체인 전체를 뒤진다. +프로토타입 체인을 탐색하는 시간이 오래걸릴수록 성능에 부정적인 영향을 줄수있다. 특히 성능이 중요한 코드에서 프로퍼티 탐색시간은 치명적인 문제가 될수있다. 가령, 없는 프로퍼티에 접근하려고 하면 항상 프로토타입 체인 전체를 탐색하게 된다. -객체를 [Iterate](#object.forinloop)하면 프로토타입 체인에 있는 **모든** 프로퍼티가 나열된다. +뿐만아니라 객체를 [순회(Iterate)](#object.forinloop)할때도 프로토타입 체인에 있는 **모든** 프로퍼티를 탐색하게 된다. ### 네이티브 프로토타입의 확장 -JavaScript에서는 `Object.prototype`같이 네이티브 객체들의 프로토타입도 확장할 수 있지만, 이것도 잘못 설계됐다. +종종 `Object.prototype`을 이용해 내장 객체를 확장하는 경우가 있는데, 이것도 역시 잘못 설계된 것중에 하나다. -이것을 [Monkey Patching][1]라고 부르는데 *캡슐화*를 망친다. 굉장히 많이 사용하는 [Prototype][2]도 굳이 기본 타입에 표준도 아닌 것들을 추가하는 이유를 아직 설명하지 못하고 있다. +위와 같이 확장하는 것을 [Monkey Patching][1]라고 부르는데 *캡슐화*를 망친다. 물론 [Prototype][2]같은 유명한 프레임워크들도 이런 확장을 사용하지만, 기본 타입에 표준도 아닌 기능들을 너저분하게 추가하는 이유를 여전히 설명하지 못하고 있다. -기본 타입을 확장하는 것이 좋을 때도 있다. [`Array.forEach`][3]같이 새 JavaScript 엔진에 추가된 기능을 위한 backport를 만들 때는 유용하다. +기본 타입을 확장해야하는 유일한 이유는 [`Array.forEach`][3]같이 새로운 JavaScript 엔진에 추가된 기능을 대비해 미리 만들어 놓는 경우 말고는 없다. ### 결론 -Prototypal Inheritance 모델을 사용하는 코드를 작성하기 전에는 이 모델을 완벽하게 이해해야 한다. 프로토타입 체인과 관련된 성능 문제로 고생하지 않으려면 프로토타입 체인의 길이에 주의하고 너무 길지 않게 적당히 끊어줘야 한다. JavaScript의 새 기능에 대한 호환성을 유지하려는 경우를 제외하고 절대로 네이티브 프로토타입을 확장하면 안 된다. +프로토타입을 이용해 복잡한 코드를 작성하기 전에 반드시 프로토타입 상속 (Prototypal Inheritance) 모델을 완벽하게 이해하고 있어야 한다. 뿐만아니라 프로토타입 체인과 관련된 성능 문제로 고생하지 않으려면 프로토타입 체인이 너무 길지 않도록 항상 주의하고 적당히 끊어줘야 한다. 마지막으로 새로운 JavaScript 기능에 대한 호환성 유지 목적이 아니라면 절대로 네이티브 프로토타입을 확장하지마라. [1]: http://en.wikipedia.org/wiki/Monkey_patch [2]: http://prototypejs.org/ diff --git a/doc/ko/other/timeouts.md b/doc/ko/other/timeouts.md index fb0384ed..2e72036b 100644 --- a/doc/ko/other/timeouts.md +++ b/doc/ko/other/timeouts.md @@ -1,22 +1,22 @@ ### `setTimeout`과 `setInterval` -JavaScript는 비동기이기 때문에 `setTimeout`과 `setInterval` 로 함수의 실행 순서를 조절할 수 있다. +JavaScript는 `setTimeout`과 `setInterval`함수를 이용해 비동기로 함수를 실행시킬수있다. > **Note:** Timeout은 ECMAScript 표준이 아니라 [DOM][1]때문에 구현됐다. function foo() {} var id = setTimeout(foo, 1000); // 0보다 큰 수를 반환한다. -`setTimeout`을 호출하면 timeout의 ID를 반환하고 **대충** 1,000밀리 초 후에 `foo`를 실행시킨다. `foo`는 **딱 한 번만** 실행한다. +`setTimeout`을 호출하면 타이머의 ID를 반환하고 **대략** 1,000밀리 초 후에 `foo`를 실행시킨다. `foo`는 **딱 한 번만** 실행한다. -JavaScript 엔진의 단위 시간(timer resolution)에 따라서 코드를 실행시키고 단일 쓰레드인 JavaScript를 특정 코드가 블록 시켜 버릴 수도 있기 때문에 `setTimeout`으로 코드가 실행돼야 할 시간을 정해줘도 **정확하게 그 시간에 실행되지 않는다.**. +JS엔진은 타이머에 설정한 시간(timer resolution)에 따라서 코드를 실행하지만 단일 쓰레드이기 때문에 특정 코드는 실행이 지연 될수도 있다. 따라서 `setTimeout`으로 코드가 실행돼야 할 시간을 정해줘도 **정확하게 그 시간에 실행되지 않을수도 있다.**. -첫 번째 인자로 넘긴 함수가 실행될 때 컨텍스트인 [`this`](#function.this)는 *Global* 객체를 가리킨다. +첫 번째 인자로 넘긴 함수는 전역 객체가 실행시킨다. 따라서 인자로 넘겨진 함수 내부의 [`this`](#function.this)는 *전역* 객체를 가리키게 된다. function Foo() { this.value = 42; this.method = function() { - // this는 Global 객체를 가리키기 때문에 + // this는 전역 객체를 가리키기 때문에 console.log(this.value); // undefined를 출력한다. }; setTimeout(this.method, 500); @@ -25,24 +25,25 @@ JavaScript 엔진의 단위 시간(timer resolution)에 따라서 코드를 실 > **Note:** `setTimeout`의 첫 번째 파라미터에 **함수** 객체를 넘겨야 하는 데 `setTimeout(foo(), 1000)`처럼 함수의 실행 결과를 넘기는 실수를 저지를 때가 잦다. 이럴 때 `setTimeout`은 그냥 `undefined`를 반환할 뿐이지 에러를 발생시키지 않는다. -### `setInterval`은 계속 함수 호출을 쌓는다(Stacking). +### 함수 호출을 쌓는(Stacking) `setInterval`함수. -`setTimeout`은 딱 한 번 함수를 호출하지만 `setInterval`은 이름처럼 **지정한 시간마다** 함수를 실행해 준다. 이 `setInterval`은 별로다. +`setTimeout`은 딱 한 번 함수를 호출하지만 `setInterval`은 이름처럼 **지정한 시간마다** 함수를 실행시켜준다. 하지만 이 함수의 사용은 좀 생각해봐야한다. -만약 실행하는 코드가 일정시간 동안 블럭되도 `setInterval`은 계속 함수를 호출시키려 든다. 특히 주기가 짧으면 밀리기 쉬워서 함수 호출은 계속 쌓일 수 있다. +`setInterval`은 실행하는 코드가 일정시간 동안 블럭되도 계속해서 함수를 호출하기 때문에 주기가 짧은 경우 함수 호출이 쉽게 쌓여버린다. function foo(){ // 1초 동안 블럭함. } setInterval(foo, 1000); -`foo`는 단순히 호출될 때마다 1초 동안 블럭하는 함수다. +위 코드에서 `foo`함수는 호출될 때마다 1초씩 실행을 지연시킨다. -`foo`가 블럭해도 `setInterval`은 계속 함수 호출을 쌓는다. `foo`의 첫 번째 호출이 끝나도 *10번* 이상의 함수 호출이 쌓여 대기하고 있다. +하지만 `foo`함수가 블럭되더라도 `setInterval`함수는 계속해서 함수 호출을 쌓기 때문에 `foo`함수 호출이 끝나면 *10번* 이상의 함수 호출이 쌓여서 대기하고 있을수도 있다. +(역주: 따라서 함수 호출이 쌓이게 되면 원래 기대했던 실행 주기를 보장받지 못한다.) -### 오래 걸리는 코드 다루기 +### 블럭되는 코드 해결법 -`setTimeout` 으로 함수 자신을 호출하는 방법으로 해결하기가 가장 쉽다. +앞에 문제를 해결하는 가장 쉽고 일반적인 방법은 `setTimeout` 함수에서 자기 자신을 다시 호출하는 방법이다. function foo(){ // something that blocks for 1 second @@ -50,40 +51,40 @@ JavaScript 엔진의 단위 시간(timer resolution)에 따라서 코드를 실 } foo(); -함수 호출이 쌓이지도 않을 뿐만 아니라 `setTimeout` 호출을 해당 함수 안에서 관리하고 `foo` 함수에서 계속 실행할지 말지 조절할 수도 있다. +이 방법은 함수 호출이 쌓이지도 않을 뿐만 아니라 `setTimeout` 호출을 해당 함수 안에서 관리하기 때문에 `foo` 함수에서 계속 실행할지 말지도 조절할 수 있다. -### Timeout 없애기 +### 타이머 없애기 -`clearTimeout`과 `clearInterval` 함수로 setTimeout과 setInterval로 등록한 timeout과 interval을 삭제할 수 있다. `set` 함수들이 반환한 id를 저장했다가 `clear` 함수를 호출하여 삭제한다. +`clearTimeout`과 `clearInterval` 함수로 setTimeout과 setInterval로 등록한 timeout과 interval을 삭제할 수 있다. `set` 함수들이 반환한 id를 저장했다가 `clear` 함수를 호출해서 삭제한다. var id = setTimeout(foo, 1000); clearTimeout(id); -### timeout을 전부 없애기 +### 모든 타이머 없애기 -등록한 timeout과 interval을 한꺼번에 제거하는 메소드는 없다. 구현해서 사용해야 한다. +등록한 timeout과 interval을 한꺼번에 제거하는 내장 함수는 없다. 따라서 좀 무식하지만 직접 구현해야 한다. - // clear "all" timeouts + // "모든" 타이머 지우기 for(var i = 1; i < 1000; i++) { clearTimeout(i); } -Id가 1부터 1000 사이에 있는 timeout들을 제거했지만, 그 외의 것은 아직 남아있다. 또 다른 방법이 있다. `setTimeout`은 항상 호출될 때마다 전보다 1만큼 큰 수를 ID로 반환한다. 이 점을 이용해 1부터 가장최근 ID까지 모두 삭제할 수 있다. +위와 같은 방법은 숫자가 미치지 못하는 타이머는 여전히 남아있을수 있다는 단점이 있다. 또 다른 해결 방법은 타이머가 반환하는 값이 항상 전보다 1만큼 큰 수를 반환한다는 점을 착안한 방법이다. - // clear "all" timeouts + // "모든" 타이머 지우기 var biggestTimeoutId = window.setTimeout(function(){}, 1), i; for(i = 1; i <= biggestTimeoutId; i++) { clearTimeout(i); } -이 방법은 모든 주요 브라우저에서 문제없이 잘 동작한다. 하지만 ID가 항상 순차적이어야 한다고 표준에 명시된 것이 아니다. 그러므로 timeout ID를 모두 저장했다가 삭제하는 것이 가장 안전하다. 그러면 전부 깨끗하게 제거할 수 있다. +이 방법은 모든 주요 브라우저에서 문제없이 잘 동작하지만 ID가 항상 순차적이어야 한다고 표준에 명시된 것이 아니다. 그러므로 timeout ID를 모두 저장했다가 삭제하는 것이 가장 안전하다. 그러면 전부 깨끗하게 제거할 수 있다. -### 숨겨진 `eval` +### 보이지 않게 사용되는 `eval`함수 -`setTimeout`과 `setInterval`의 첫 파라미터에 스트링도 넘길 수 있다. 그렇지만, 내부적으로 `eval`을 사용하는 것이기 때문에 절대 사용하지 말아야 한다. +`setTimeout`과 `setInterval`의 첫 파라미터로 문자열을 넘길 수 있다. 하지만 내부적으로 `eval`을 사용하는 것이기 때문에 절대 사용해서는 안된다. -> **Note:** timeout 함수는 ECMAScript 표준이 아녀서 첫 인자가 스트링 타입일 때에는 JavaScript 구현체마다 다르게 동작한다. 예를 들어, Microsoft의 JScript는 `eval`이 아니라 `Function` 생성자를 사용한다. +> **Note:** timeout 함수는 ECMAScript 표준이 아니기 때문에 문자열로 넘어오는 첫번째 인자에 대한 해석은 구현체마다 다르다. 예를 들어, Microsoft의 JScript는 `eval`이 아니라 `Function` 생성자를 사용한다. function foo() { // 이게 호출됨 @@ -97,7 +98,7 @@ Id가 1부터 1000 사이에 있는 timeout들을 제거했지만, 그 외의 } bar(); -이 경우 `eval`이 [그냥(directly)](#core.eval) 호출되는 것이 아니다. `setTimeout`에 넘겨진 스트링은 *Global* Scope에서 실행되기 때문에 `bar`의 Local 함수 `foo`가 실행되는 것이 아니라 *Global* Scope의 `foo`가 실행된다. +이 경우 `eval`이 [그냥(directly)](#core.eval) 호출되는 것이 아니다. `setTimeout`에 인자로 넘어간 문자열은 *전역* 스코프에서 실행되기 때문에 `bar`함수 영역에 있는 지역 변수 `foo`가 실행되는 것이 아니라 *전역* 스코프에 있는 `foo`가 실행된다. 함수에 파라미터를 넘겨야 하면 스트링을 사용하지 말아야 한다. @@ -115,8 +116,8 @@ Id가 1부터 1000 사이에 있는 timeout들을 제거했지만, 그 외의 ### 결론 -`setTimeout`과 `setInterval`의 파라미터로 스트링은 절대 사용하지 말아야 한다. 핸들러 함수에 인자를 넘겨야 하는 경우도 **분명히** 탈 난다. *익명 함수*을 사용해서 호출해야 한다. +`setTimeout`과 `setInterval`함수에 문자열 인자를 절대 사용해서는 안된다. 핸들러 함수에 인자를 넘기는 코드도 **절대** 좋은 코드가 아니다. *익명 함수*을 사용해서 호출해야 한다. -그리고 `setInterval`은 해당 핸들러가 블럭되든 말든 상관하지 않기 때문에 사용하면 안 된다. +그리고 `setInterval`은 해당 핸들러가 블럭되든 말든 상관하지 않기 때문에 되도록이면 쓰지말자. [1]: http://en.wikipedia.org/wiki/Document_Object_Model "Document Object Model" diff --git a/doc/ko/types/casting.md b/doc/ko/types/casting.md index eb89f546..7a6e28ea 100644 --- a/doc/ko/types/casting.md +++ b/doc/ko/types/casting.md @@ -1,4 +1,4 @@ -## Type Casting +## 타입 캐스팅 JavaScript는 Weak Typing 언어이기 때문에 필요할 때마다 알아서 타입을 변환한다. @@ -15,9 +15,9 @@ JavaScript는 Weak Typing 언어이기 때문에 필요할 때마다 알아서 10 == 010; 10 == '-10'; -> **ES5 Note:** `0`으로 시작하는 숫자 리터럴은 8진수다. 하지만, ECMAScript 5의 strict 모드에서는 더는 8진수로 해석하지 않는다. +> **ES5 Note:** `0`으로 시작하는 숫자 리터럴은 8진수다. 하지만, ECMAScript 5의 strict 모드에서는 8진수로 더이상 해석하지 않는다. -이런 문제들은 [strict equal operator](#types.equality)로 **미리 방지해야** 한다. 이 operator로 JavaScript의 많은 결점을 보완할 수 있지만, 아직도 weak typing 시스템 때문에 생기는 문제가 많다. +위와 같은 문제들은 ***반드시** [삼중 등호 연산자](#types.equality)를 이용해 해결하길 권한다. 물론 삼중 등호로 많은 결점을 보완할 수 있지만, 여전히 weak typing 시스템 때문에 생기는 많은 문제가 남아있다. ### 기본 타입 생성자 diff --git a/doc/ko/types/equality.md b/doc/ko/types/equality.md index 970b2c14..a9daccb5 100644 --- a/doc/ko/types/equality.md +++ b/doc/ko/types/equality.md @@ -1,12 +1,12 @@ ## 객체 비교하기 -JavaScript에서 객체를 비교하는 방법은 두 가지다. +JavaScript에서 객체를 비교하는 방법은 두 가지가 있다. -### Equality Operator +### 이중 등호 연산자 -`==`가 Equality Operator이다. +이중 등호 연산자는 `==`을 말한다. -JavaScript는 Weak Typing을 따르기 때문에 equality operator가 비교할 때 두 객체의 자료형을 **강제로** 변환한다. +JavaScript는 Weak Typing을 따르기 때문에 이중 등호를 이용해 비교할 때 두 객체의 자료형을 **강제로** 변환한다. "" == "0" // false 0 == "" // true @@ -18,15 +18,15 @@ JavaScript는 Weak Typing을 따르기 때문에 equality operator가 비교할 null == undefined // true " \t\r\n" == 0 // true -이 표는 왜 Equality Operator를 사용하면 안 되는지를 보여준다. 이 복잡한 변환 규칙은 실제로 골치 아픈 버그를 만들어 낸다. +이 표는 이중 등호를 사용하면 왜 안되는지를 보여준다. 이 복잡한 변환 규칙은 실제로 골치 아픈 버그를 만들어 낸다. -게다가 강제로 타입을 변환하는 것은 성능 문제도 일으킨다. 예를 들어 스트링과 숫자를 비교하려면 반드시 숫자로 변환해야 한다. +게다가 강제로 타입을 변환하게 되면 성능에도 영향을 준다. 예를 들어 문자와 숫자를 비교하려면 반드시 먼저 문자를 숫자로 변환해야 한다. -### Strict Equality Operator +### 삼중 등호 연산자 -Strict Equality Operator는 `===`이다. +삼중 등호 연산자는 `===`을 말한다. -강제로 타입을 변환하지 않는 것을 제외하고는 Equality Operator와 똑같다. +삼중 등호는 강제로 타입을 변환하지 않는다는 사실을 제외하면 이중 등호와 동일하다. "" === "0" // false 0 === "" // false @@ -38,11 +38,11 @@ Strict Equality Operator는 `===`이다. null === undefined // false " \t\r\n" === 0 // false -이 결과가 훨씬 명확하고 문제를 빨리 발견할 수 있게 해준다. 이 Operator를 사용하면 코드가 좀 더 튼튼하고 비교하는 두 객체의 타입이 다르면 성능도 빠르다. +위 결과가 훨씬 더 명확하고 문제가 쉽게 드러난다. 삼중 등호를 사용하면 코드를 좀 더 튼튼하게 만들수 있고, 비교하는 두 객체의 타입이 다르면 더 좋은 성능을 얻을 수도 있다. ### 객체 비교하기 -`==`와 `===`는 둘 다 **Equality** Operator지만 비교하는 객체 중 적어도 한 개가 Object 타입일 때에는 다르게 동작한다. +이중 등호와(`==`)와 삼중 등호(`===`)는 둘 다 **값을 비교하는** 연산이지만 피연산자중에 Object 타입이 하나라도 있으면 다르게 동작한다. {} === {}; // false new String('foo') === 'foo'; // false @@ -50,8 +50,8 @@ Strict Equality Operator는 `===`이다. var foo = {}; foo === foo; // true -두 Operator 모두 **같은 객체(identity)**인지 비교하는 것이지 객체의 값이 같은지 비교하는 것이 아니다. C에서 포인터를 비교하거나 Python의 is처럼 같은 인스턴스인지 비교하는 것이다. +두 연산자 모두 두 객체의 값이 같은지를 비교하지 않고, 두 객체가 **같은 객체(identity)**인지를 비교한다. C에서 포인터를 비교하거나 Python의 is처럼 같은 인스턴스인지 비교하는 것이다. ### 결론 -반드시 **Strict Equality Operator**를 사용해야 한다. 비교하기 위해서 꼭 타입 변환이 필요하면 언어의 복잡한 변환 규칙에 맡기지 말고 꼭 명시적으로 변환하고 나서 비교해야 한다. +**삼중 등호 연산자**를 사용할 것을 강력하게 권한다. 비교하기 위해서 타입 변환이 필요하면 언어의 복잡한 변환 규칙에 맡기지 말고 꼭 명시적으로 변환한 후에 비교해야 한다. diff --git a/doc/ko/types/instanceof.md b/doc/ko/types/instanceof.md index 560f4435..621f8121 100644 --- a/doc/ko/types/instanceof.md +++ b/doc/ko/types/instanceof.md @@ -1,8 +1,8 @@ -## `instanceof` +## `instanceof` 연산자 -`instanceof`는 두 객체의 생성자를 비교하는 것이고 직접 만든 타입의 객체를 비교할 때 유용하다. 기본 타입만 생각하면 이 연산자는 [typeof](#types.typeof)처럼 거의 쓸모 없다. +`instanceof`연산자는 두 피연산자의 생성자를 비교할때 사용하고 직접 만든 객체를 비교할 때 매우 유용하다. 내장 타입에 쓰는 경우에는 [typeof](#types.typeof)처럼 거의 쓸모가 없다. -### 직접 만든 타입의 객체를 `intanceof`로 비교하기 +### 커스텀 객체를 `intanceof`로 비교하기 function Foo() {} function Bar() {} @@ -11,12 +11,12 @@ new Bar() instanceof Bar; // true new Bar() instanceof Foo; // true - // Bar.prototype에 function 객체인 Foo를 할당하면 + // Bar.prototype에 함수 객체인 Foo를 할당하면 // Bar의 인스턴스는 Foo의 인스턴스가 아니다. Bar.prototype = Foo; new Bar() instanceof Foo; // false -### 기본 타입 객체를 `intanceof`로 비교하기 +### 기본 내장 객체 타입을 `intanceof`로 비교하기 new String('foo') instanceof String; // true new String('foo') instanceof Object; // true diff --git a/doc/ko/types/typeof.md b/doc/ko/types/typeof.md index fb7c6576..a2db9595 100644 --- a/doc/ko/types/typeof.md +++ b/doc/ko/types/typeof.md @@ -1,10 +1,10 @@ -## `typeof` +## `typeof` 연산자 -`typeof`도 [`instanceof`](#types.instanceof)와 함께 JavaScript에서 치명적으로 잘못 설계된 부분이다. 이건 정말 아무짝에 쓸모없다. +`typeof` 연산자도 [`instanceof`](#types.instanceof) 연산자와 함께 JavaScript에서 치명적으로 잘못 설계된 부분이다. 이건 정말이지 아무짝에도 쓸모가 없다. -`instanceof`는 그래도 쓸 데가 좀 있었는데 `typeof`는 딱 한 군데에만 써먹을 수 있다. 객체의 타입을 검사할 일이 없다. +`instanceof` 연산자는 그래도 여전히 쓸만한 데가 좀 있는데 `typeof` 연산자는 객체의 타입을 검사하는 것 외에는 쓸만한데가 없고, 이마저도 거의 쓸일이 없다. -> **Note:** `typeof`는 함수처럼 `typeof(obj)`로 사용할 수 있다. 하지만, 이것은 함수를 호출하는 것이 아니라 단순히 `()`안의 값이 반환되고 `typeof`가 적용되는 것이다. `typeof`라는 함수는 **없다**. +> **Note:** `typeof` 연산자는 함수처럼 `typeof(obj)`로 사용할수 있지만 함수 호출은 아니다. 괄호 안의 값은 `typeof`의 피연산자로 적용되고 그 결과가 반환된다. `typeof`라는 함수는 **없다**. ### JavaScript 타입 표 @@ -26,13 +26,13 @@ {} Object object new Object() Object object -이 표에서 *Type*은 `typeof`가 반환하는 값이다. 표에서 본 것처럼 이 값은 계속 쓸모없다. +위 표에서 *Type*은 `typeof`가 반환하는 값이다. 위 표에서처럼 일치되는 값이 거의 없다. -Class는 객체 내부에 있는 `[[Class]]` 프로퍼티의 값이다. +위 표에서 *Class*는 객체 내부에 있는 `[[Class]]` 프로퍼티의 값을 말한다. > **표준**에는 `[[Class]]`의 값은 `Arguments`, `Array`, `Boolean`, `Date`, `Error`, `Function`, `JSON`, `Math`, `Number`, `Object`, `RegExp`, `String`중 하나라고 나와있다. -`[[Class]]`의 값을 가져다 쓰려면 `Object.prototype`의 `toString` 메소드를 사용해야 한다. +`[[Class]]` 프로퍼티의 값을 가져다 쓰려면 `Object.prototype`의 `toString` 메소드를 사용한다. ### 객체의 클래스 @@ -54,10 +54,10 @@ Class는 객체 내부에 있는 `[[Class]]` 프로퍼티의 값이다. typeof foo !== 'undefined' -이것은 `foo`가 정의됐는지 아닌지를 확인해준다. 정의되지 않은 변수에 접근하면 `ReferenceError` 나는데 이것을 방지할 수 있다. `typeof`가 유용한 건 이때뿐이다. +위 코드는 `foo`가 정의됐는지 아닌지를 확인해준다. 정의되지 않은 변수에 접근하면 `ReferenceError` 나는데 이것을 방지할 수 있다. `typeof`가 유용한 건 이때뿐이다. ### 결론 -객체의 타입을 검사하려면 `Object.prototype.toString`를 사용해야 한다. 다른 방법은 신뢰할 수 없다. 위 표에서 보여준 것처럼 typeof가 반환하는 값은 표준에 나와 있지 않기 때문에 구현마다 다르다. +객체의 타입을 검사하려면 `Object.prototype.toString`를 사용해야 한다. 다른 방법은 신뢰할 수 없다. 위 표에서 보여준 것처럼 typeof가 반환하는 값은 표준에 나와 있지 않기 때문에 구현방법도 제각각이다. -변수가 정의됐는지 확인할 때는 빼고 **목숨을 걸고** `typeof`를 사용하지 못하게 해야 한다. +변수가 정의됐는지 확인할 때를 제외하고 **가급적** `typeof`는 피해야한다. \ No newline at end of file From 48e7a5f49eeac32fa0a54f96b7c9616216b22e6b Mon Sep 17 00:00:00 2001 From: ruben Date: Wed, 21 Nov 2012 10:15:46 +0100 Subject: [PATCH 062/277] fixed a typo --- doc/es/array/general.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/es/array/general.md b/doc/es/array/general.md index 944590b0..3de582bb 100644 --- a/doc/es/array/general.md +++ b/doc/es/array/general.md @@ -31,7 +31,7 @@ para realizar la búsqueda en cada interación del bucle. Y mientras que los úl motores de JavaScript **pueden** aplicar optimizaciones en este caso, no hay manera de saber si el ćodigo se ejecutará en uno de estos nuevos motores nuevos o no. -De hecho, dejando de lado el alamacenamiento en caché puede resultar que el bucle +De hecho, dejando de lado el almacenamiento en caché puede resultar que el bucle inicie sólo la **mitad de rápido** que con la longitud de la caché. ### La propiedad `length` From 5f34e58254739b46e13ab46dc75159c9e1b5b135 Mon Sep 17 00:00:00 2001 From: "ByungDae, Sohn" Date: Wed, 26 Dec 2012 11:14:29 +0900 Subject: [PATCH 063/277] improve transration --- doc/ko/function/arguments.md | 2 +- doc/ko/intro/index.md | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/ko/function/arguments.md b/doc/ko/function/arguments.md index dcc5e8a2..5ea383cb 100644 --- a/doc/ko/function/arguments.md +++ b/doc/ko/function/arguments.md @@ -64,7 +64,7 @@ JavaScript의 모든 함수 스코프에는 `arguments`라는 특별한 변수 ### 성능에 대한 오해와 진실. -`arguments` 객체는 항상 만들어 지지만 예외도 있다. `arguments`라는 이름의 변수를 Function 안에 정의하거나 그 이름으로 파라미터를 만들면 `arguemnts` 객체는 만들어지지 않는다. 그렇지만, 이럴때는 어차피 안쓰겠다는 의미니까 상관 없다. +`arguments` 객체는 항상 만들어지지만 두가지 예외사항이 있다. `arguments`라는 이름으로 변수를 함수 안에 정의하거나 arguments 객체로 넘겨받는 인자중 하나라도 정식 인자로 받아서 사용하면 `arguemnts` 객체는 만들어지지 않는다. 하지만 뭐 이런 경우들은 어차피 arguments 객체를 안쓰겠다는 의미니까 상관 없다. 그리고 *getter*와 *setter*는 항상 생성되기 때문에 getter/setter를 사용하는 것은 성능에 별 영향을 끼치지 않는다. 예제처럼 단순한 코드가 아니라 `arguments` 객체를 다방면으로 활용하는 실제 코드에서도 마찬가지다. diff --git a/doc/ko/intro/index.md b/doc/ko/intro/index.md index 87b72473..2fe16ea7 100644 --- a/doc/ko/intro/index.md +++ b/doc/ko/intro/index.md @@ -14,7 +14,8 @@ JavaScript Garden은 단순히 JavaScript 언어 자체를 설명하려 만들 - [Andreas Blixt][6] (언어 교정) ## 번역 - - [박창우][손병대][] + - [박창우][] + - [손병대][] [박창우]: https://github.com/pismute [손병대]: https://github.com/miconblog From 9c4235052673113663baf58969f9acc98611cf48 Mon Sep 17 00:00:00 2001 From: "ByungDae, Sohn" Date: Wed, 26 Dec 2012 11:37:15 +0900 Subject: [PATCH 064/277] improve translation --- doc/ko/function/arguments.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ko/function/arguments.md b/doc/ko/function/arguments.md index 5ea383cb..097bec13 100644 --- a/doc/ko/function/arguments.md +++ b/doc/ko/function/arguments.md @@ -64,7 +64,7 @@ JavaScript의 모든 함수 스코프에는 `arguments`라는 특별한 변수 ### 성능에 대한 오해와 진실. -`arguments` 객체는 항상 만들어지지만 두가지 예외사항이 있다. `arguments`라는 이름으로 변수를 함수 안에 정의하거나 arguments 객체로 넘겨받는 인자중 하나라도 정식 인자로 받아서 사용하면 `arguemnts` 객체는 만들어지지 않는다. 하지만 뭐 이런 경우들은 어차피 arguments 객체를 안쓰겠다는 의미니까 상관 없다. +`arguments` 객체는 항상 만들어지지만 두가지 예외사항이 있다. `arguments`라는 이름으로 변수를 함수 안에 정의하거나 arguments 객체로 넘겨받는 인자중 하나라도 정식 인자로 받아서 사용하면 `arguemnts` 객체는 만들어지지 않는다. 사실 arguments 객체를 쓰든 쓰지않든 중요한건 아니므로 신경쓰지 않아도 된다. 그리고 *getter*와 *setter*는 항상 생성되기 때문에 getter/setter를 사용하는 것은 성능에 별 영향을 끼치지 않는다. 예제처럼 단순한 코드가 아니라 `arguments` 객체를 다방면으로 활용하는 실제 코드에서도 마찬가지다. From 1f2bc63402dbfbc1e2804f72ffb7b1a6824d6947 Mon Sep 17 00:00:00 2001 From: PiNotEqual3 Date: Tue, 22 Jan 2013 10:10:25 +0100 Subject: [PATCH 065/277] Update doc/de/intro/index.md German Intro --- doc/de/intro/index.md | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/doc/de/intro/index.md b/doc/de/intro/index.md index 94250e2f..566e3235 100644 --- a/doc/de/intro/index.md +++ b/doc/de/intro/index.md @@ -1,4 +1,43 @@ ## Einführung -Demnächst. +**JavaScript Garden** ist eine wachsende Sammlung von Erklärungen der verzwicktesten Teile von JavaScript. Es gibt +Hinweise um häufige Fehler, Performance Probleme und schlechten Stil zu vermeiden. +JavaScript Garden ist **keine** Anleitung um JavaScript zu lernen. Ein grundlegendes Verständnis der Sprache wird +wärmstens empfohlen. Eine gute [Einführung][1] findet sich zum Beispiel im Mozilla Developer Network. + +## Die Autoren + +Dieses Dokument wurde von zwei liebenswerten [Stack Overflow][2] Benutzern geschrieben: [Ivo Wetzel][3] +(Text) and [Zhang Yi Jiang][4] (Design). + +## Beitragende + + - [Caio Romão][5] (Rechtschreibung) + - [Andreas Blixt][6] (Sprachanpassungen) + +## Hosting + +JavaScript Garden wird von GitHub bereitgestellt, aber es wird auch von [Cramer Development][7] unterstützt durch +einen Mirror auf [JavaScriptGarden.info][8]. + +## Lizenz + +JavaScript Garden wurde unter der [MIT Lizenz][9] veröffentlich und wird von [GitHub][10] veröffentlicht. Wenn du +Fehler findest mach bitte ein [Ticket][11] auf oder einen pull request ins repository. Du kannst uns auch im +[JavaScript Raum][12] des Stack Overflow Chats finden. + +Mehr demnächst. + +[1]: https://developer.mozilla.org/en/JavaScript/Guide +[2]: http://stackoverflow.com/ +[3]: http://stackoverflow.com/users/170224/ivo-wetzel +[4]: http://stackoverflow.com/users/313758/yi-jiang +[5]: https://github.com/caio +[6]: https://github.com/blixt +[7]: http://cramerdev.com/ +[8]: http://javascriptgarden.info/ +[9]: https://github.com/BonsaiDen/JavaScript-Garden/blob/next/LICENSE +[10]: https://github.com/BonsaiDen/JavaScript-Garden +[11]: https://github.com/BonsaiDen/JavaScript-Garden/issues +[12]: http://chat.[stackoverflow.com/rooms/17/javascript From 1546101896aab6a09303fcecbdf18d72726e6b58 Mon Sep 17 00:00:00 2001 From: Bruno Coelho Date: Thu, 24 Jan 2013 09:22:13 -0300 Subject: [PATCH 066/277] Passing the wrong object to hasOwnProperty method. --- doc/en/object/hasownproperty.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/en/object/hasownproperty.md b/doc/en/object/hasownproperty.md index 0033b4ba..03e3feea 100644 --- a/doc/en/object/hasownproperty.md +++ b/doc/en/object/hasownproperty.md @@ -5,26 +5,26 @@ on its [prototype chain](#object.prototype), it is necessary to use the `hasOwnProperty` method which all objects inherit from `Object.prototype`. > **Note:** It is **not** enough to check whether a property is `undefined`. The -> property might very well exist, but its value just happens to be set to +> property might very well exist, but its value just happens to be set to > `undefined`. -`hasOwnProperty` is the only thing in JavaScript which deals with properties and +`hasOwnProperty` is the only thing in JavaScript which deals with properties and does **not** traverse the prototype chain. // Poisoning Object.prototype - Object.prototype.bar = 1; + Object.prototype.bar = 1; var foo = {goo: undefined}; - + foo.bar; // 1 'bar' in foo; // true foo.hasOwnProperty('bar'); // false foo.hasOwnProperty('goo'); // true -Only `hasOwnProperty` will give the correct and expected result; this is -essential when iterating over the properties of any object. There is **no** other -way to exclude properties that are not defined on the object itself, but -somewhere on its prototype chain. +Only `hasOwnProperty` will give the correct and expected result; this is +essential when iterating over the properties of any object. There is **no** other +way to exclude properties that are not defined on the object itself, but +somewhere on its prototype chain. ### `hasOwnProperty` as a Property @@ -45,7 +45,7 @@ necessary to use an *external* `hasOwnProperty` to get correct results. ({}).hasOwnProperty.call(foo, 'bar'); // true // It's also possible to use the hasOwnProperty property from the Object property for this purpose - Object.prototype.hasOwnProperty.call(obj, 'bar'); // true + Object.prototype.hasOwnProperty.call(foo, 'bar'); // true ### In Conclusion From 4a94b223de56462297fa6e018f64ad13bf3abd86 Mon Sep 17 00:00:00 2001 From: Bruno Coelho Date: Fri, 25 Jan 2013 14:08:19 -0300 Subject: [PATCH 067/277] Cosmetic. --- doc/en/object/prototype.md | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/doc/en/object/prototype.md b/doc/en/object/prototype.md index abb67c58..cb053526 100644 --- a/doc/en/object/prototype.md +++ b/doc/en/object/prototype.md @@ -1,23 +1,23 @@ ## The Prototype -JavaScript does not feature a classical inheritance model; instead, it uses a -*prototypal* one. +JavaScript does not feature a classical inheritance model; instead, it uses a +*prototypal* one. -While this is often considered to be one of JavaScript's weaknesses, the +While this is often considered to be one of JavaScript's weaknesses, the prototypal inheritance model is in fact more powerful than the classic model. It is, for example, fairly trivial to build a classic model on top of a prototypal model, while the other way around is a far more difficult task. JavaScript is the only widely used language that features prototypal inheritance, so it can take time to adjust to the differences between the two -models. +models. The first major difference is that inheritance in JavaScript uses *prototype chains*. > **Note:** Simply using `Bar.prototype = Foo.prototype` will result in both objects -> sharing the **same** prototype. Therefore, changes to either object's prototype -> will affect the prototype of the other as well, which in most cases is not the +> sharing the **same** prototype. Therefore, changes to either object's prototype +> will affect the prototype of the other as well, which in most cases is not the > desired effect. function Foo() { @@ -36,11 +36,11 @@ chains*. // Make sure to list Bar as the actual constructor Bar.prototype.constructor = Bar; - var test = new Bar() // create a new bar instance + var test = new Bar(); // create a new bar instance // The resulting prototype chain test [instance of Bar] - Bar.prototype [instance of Foo] + Bar.prototype [instance of Foo] { foo: 'Hello World' } Foo.prototype { method: ... } @@ -48,14 +48,14 @@ chains*. { toString: ... /* etc. */ } In the code above, the object `test` will inherit from both `Bar.prototype` and -`Foo.prototype`; hence, it will have access to the function `method` that was +`Foo.prototype`; hence, it will have access to the function `method` that was defined on `Foo`. It will also have access to the property `value` of the **one** `Foo` instance that is its prototype. It is important to note that `new -Bar()` does **not** create a new `Foo` instance, but reuses the one assigned to +Bar()` does **not** create a new `Foo` instance, but reuses the one assigned to its prototype; thus, all `Bar` instances will share the **same** `value` property. -> **Note:** Do **not** use `Bar.prototype = Foo`, since it will not point to -> the prototype of `Foo` but rather to the function object `Foo`. So the +> **Note:** Do **not** use `Bar.prototype = Foo`, since it will not point to +> the prototype of `Foo` but rather to the function object `Foo`. So the > prototype chain will go over `Function.prototype` and not `Foo.prototype`; > therefore, `method` will not be on the prototype chain. @@ -71,7 +71,7 @@ hasn't found the specified property, it will return the value ### The Prototype Property While the prototype property is used by the language to build the prototype -chains, it is still possible to assign **any** given value to it. However, +chains, it is still possible to assign **any** given value to it. However, primitives will simply get ignored when assigned as a prototype. function Foo() {} @@ -85,9 +85,9 @@ creation of prototype chains. The lookup time for properties that are high up on the prototype chain can have a negative impact on performance, and this may be significant in code where performance is critical. Additionally, trying to access non-existent properties -will always traverse the full prototype chain. +will always traverse the full prototype chain. -Also, when [iterating](#object.forinloop) over the properties of an object +Also, when [iterating](#object.forinloop) over the properties of an object **every** property that is on the prototype chain will be enumerated. ### Extension of Native Prototypes @@ -95,12 +95,12 @@ Also, when [iterating](#object.forinloop) over the properties of an object One mis-feature that is often used is to extend `Object.prototype` or one of the other built in prototypes. -This technique is called [monkey patching][1] and breaks *encapsulation*. While -used by popular frameworks such as [Prototype][2], there is still no good +This technique is called [monkey patching][1] and breaks *encapsulation*. While +used by popular frameworks such as [Prototype][2], there is still no good reason for cluttering built-in types with additional *non-standard* functionality. -The **only** good reason for extending a built-in prototype is to backport -the features of newer JavaScript engines; for example, +The **only** good reason for extending a built-in prototype is to backport +the features of newer JavaScript engines; for example, [`Array.forEach`][3]. ### In Conclusion From 33a89e7857b5b82413af588ac6708117aef3dc4c Mon Sep 17 00:00:00 2001 From: howardchi Date: Wed, 13 Mar 2013 20:08:28 +0800 Subject: [PATCH 068/277] translate to Tranditioin Chinese --- doc/zh(Trandition)/array/constructor.md | 28 +++ doc/zh(Trandition)/array/general.md | 46 ++++ doc/zh(Trandition)/core/delete.md | 85 +++++++ doc/zh(Trandition)/core/eval.md | 42 ++++ doc/zh(Trandition)/core/semicolon.md | 103 +++++++++ doc/zh(Trandition)/core/undefined.md | 70 ++++++ doc/zh(Trandition)/function/arguments.md | 118 ++++++++++ doc/zh(Trandition)/function/closures.md | 98 ++++++++ doc/zh(Trandition)/function/constructors.md | 128 +++++++++++ doc/zh(Trandition)/function/general.md | 48 ++++ doc/zh(Trandition)/function/scopes.md | 233 ++++++++++++++++++++ doc/zh(Trandition)/function/this.md | 111 ++++++++++ doc/zh(Trandition)/index.json | 69 ++++++ doc/zh(Trandition)/intro/index.md | 47 ++++ doc/zh(Trandition)/object/forinloop.md | 51 +++++ doc/zh(Trandition)/object/general.md | 99 +++++++++ doc/zh(Trandition)/object/hasownproperty.md | 57 +++++ doc/zh(Trandition)/object/prototype.md | 118 ++++++++++ doc/zh(Trandition)/other/timeouts.md | 167 ++++++++++++++ doc/zh(Trandition)/types/casting.md | 70 ++++++ doc/zh(Trandition)/types/equality.md | 71 ++++++ doc/zh(Trandition)/types/instanceof.md | 38 ++++ doc/zh(Trandition)/types/typeof.md | 86 ++++++++ 23 files changed, 1983 insertions(+) create mode 100644 doc/zh(Trandition)/array/constructor.md create mode 100644 doc/zh(Trandition)/array/general.md create mode 100644 doc/zh(Trandition)/core/delete.md create mode 100644 doc/zh(Trandition)/core/eval.md create mode 100644 doc/zh(Trandition)/core/semicolon.md create mode 100644 doc/zh(Trandition)/core/undefined.md create mode 100644 doc/zh(Trandition)/function/arguments.md create mode 100644 doc/zh(Trandition)/function/closures.md create mode 100644 doc/zh(Trandition)/function/constructors.md create mode 100644 doc/zh(Trandition)/function/general.md create mode 100644 doc/zh(Trandition)/function/scopes.md create mode 100644 doc/zh(Trandition)/function/this.md create mode 100644 doc/zh(Trandition)/index.json create mode 100644 doc/zh(Trandition)/intro/index.md create mode 100644 doc/zh(Trandition)/object/forinloop.md create mode 100644 doc/zh(Trandition)/object/general.md create mode 100644 doc/zh(Trandition)/object/hasownproperty.md create mode 100644 doc/zh(Trandition)/object/prototype.md create mode 100644 doc/zh(Trandition)/other/timeouts.md create mode 100644 doc/zh(Trandition)/types/casting.md create mode 100644 doc/zh(Trandition)/types/equality.md create mode 100644 doc/zh(Trandition)/types/instanceof.md create mode 100644 doc/zh(Trandition)/types/typeof.md diff --git a/doc/zh(Trandition)/array/constructor.md b/doc/zh(Trandition)/array/constructor.md new file mode 100644 index 00000000..7e768014 --- /dev/null +++ b/doc/zh(Trandition)/array/constructor.md @@ -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` 的建構函式需要避免,建議使用字面語法。因為他們比較簡短、也更增加閱讀性 diff --git a/doc/zh(Trandition)/array/general.md b/doc/zh(Trandition)/array/general.md new file mode 100644 index 00000000..f4bd9252 --- /dev/null +++ b/doc/zh(Trandition)/array/general.md @@ -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` 迴圈則是會讓程式中有更多的錯誤和性能問題。 + diff --git a/doc/zh(Trandition)/core/delete.md b/doc/zh(Trandition)/core/delete.md new file mode 100644 index 00000000..067fcfdb --- /dev/null +++ b/doc/zh(Trandition)/core/delete.md @@ -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. diff --git a/doc/zh(Trandition)/core/eval.md b/doc/zh(Trandition)/core/eval.md new file mode 100644 index 00000000..e1b14292 --- /dev/null +++ b/doc/zh(Trandition)/core/eval.md @@ -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`。 + diff --git a/doc/zh(Trandition)/core/semicolon.md b/doc/zh(Trandition)/core/semicolon.md new file mode 100644 index 00000000..02a3ac35 --- /dev/null +++ b/doc/zh(Trandition)/core/semicolon.md @@ -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...`的表達式中也是如此,不應省略大括號。 +這個習慣可以不僅僅是讓你的程式更一致,也可以避免編譯器因為改變程式而出錯。 + diff --git a/doc/zh(Trandition)/core/undefined.md b/doc/zh(Trandition)/core/undefined.md new file mode 100644 index 00000000..51101912 --- /dev/null +++ b/doc/zh(Trandition)/core/undefined.md @@ -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`. + + diff --git a/doc/zh(Trandition)/function/arguments.md b/doc/zh(Trandition)/function/arguments.md new file mode 100644 index 00000000..2394177d --- /dev/null +++ b/doc/zh(Trandition)/function/arguments.md @@ -0,0 +1,118 @@ +## The `arguments` Object + +Every function scope in JavaScript can access the special variable `arguments`. +This variable holds a list of all the arguments that were passed to the function. + +> **Note:** In case `arguments` has already been defined inside the function's +> scope either via a `var` statement or being the name of a formal parameter, +> the `arguments` object will not be created. + +The `arguments` object is **not** an `Array`. While it has some of the +semantics of an array - namely the `length` property - it does not inherit from +`Array.prototype` and is in fact an `Object`. + +Due to this, it is **not** possible to use standard array methods like `push`, +`pop` or `slice` on `arguments`. While iteration with a plain `for` loop works +just fine, it is necessary to convert it to a real `Array` in order to use the +standard `Array` methods on it. + +### Converting to an Array + +The code below will return a new `Array` containing all the elements of the +`arguments` object. + + Array.prototype.slice.call(arguments); + +Because this conversion is **slow**, it is **not recommended** to use it in +performance-critical sections of code. + +### Passing Arguments + +The following is the recommended way of passing arguments from one function to +another. + + function foo() { + bar.apply(null, arguments); + } + function bar(a, b, c) { + // do stuff here + } + +Another trick is to use both `call` and `apply` together to create fast, unbound +wrappers. + + function Foo() {} + + Foo.prototype.method = function(a, b, c) { + console.log(this, a, b, c); + }; + + // Create an unbound version of "method" + // It takes the parameters: this, arg1, arg2...argN + Foo.method = function() { + + // Result: Foo.prototype.method.call(this, arg1, arg2... argN) + Function.call.apply(Foo.prototype.method, arguments); + }; + + +### Formal Parameters and Arguments Indices + +The `arguments` object creates *getter* and *setter* functions for both its +properties, as well as the function's formal parameters. + +As a result, changing the value of a formal parameter will also change the value +of the corresponding property on the `arguments` object, and the other way around. + + function foo(a, b, c) { + arguments[0] = 2; + a; // 2 + + b = 4; + arguments[1]; // 4 + + var d = c; + d = 9; + c; // 3 + } + foo(1, 2, 3); + +### Performance Myths and Truths + +The only time the `arguments` object is not created is where it is declared as +a name inside of a function or one of its formal parameters. It does not matter +whether it is used or not. + +Both *getters* and *setters* are **always** created; thus, using it has nearly +no performance impact at all, especially not in real world code where there is +more than a simple access to the `arguments` object's properties. + +> **ES5 Note:** These *getters* and *setters* are not created in strict mode. + +However, there is one case which will drastically reduce the performance in +modern JavaScript engines. That case is the use of `arguments.callee`. + + function foo() { + arguments.callee; // do something with this function object + arguments.callee.caller; // and the calling function object + } + + function bigLoop() { + for(var i = 0; i < 100000; i++) { + foo(); // Would normally be inlined... + } + } + +In the above code, `foo` can no longer be a subject to [inlining][1] since it +needs to know about both itself and its caller. This not only defeats possible +performance gains that would arise from inlining, but it also breaks encapsulation +because the function may now be dependent on a specific calling context. + +Making use of `arguments.callee` or any of its properties is **highly discouraged**. + +> **ES5 Note:** In strict mode, `arguments.callee` will throw a `TypeError` since +> its use has been deprecated. + +[1]: http://en.wikipedia.org/wiki/Inlining + + diff --git a/doc/zh(Trandition)/function/closures.md b/doc/zh(Trandition)/function/closures.md new file mode 100644 index 00000000..76f2d078 --- /dev/null +++ b/doc/zh(Trandition)/function/closures.md @@ -0,0 +1,98 @@ +## Closures and References + +One of JavaScript's most powerful features is the availability of *closures*. +With closures, scopes **always** keep access to the outer scope, in which they +were defined. Since the only scoping that JavaScript has is +[function scope](#function.scopes), all functions, by default, act as closures. + +### Emulating private variables + + function Counter(start) { + var count = start; + return { + increment: function() { + count++; + }, + + get: function() { + return count; + } + } + } + + var foo = Counter(4); + foo.increment(); + foo.get(); // 5 + +Here, `Counter` returns **two** closures: the function `increment` as well as +the function `get`. Both of these functions keep a **reference** to the scope of +`Counter` and, therefore, always keep access to the `count` variable that was +defined in that scope. + +### Why Private Variables Work + +Since it is not possible to reference or assign scopes in JavaScript, there is +**no** way of accessing the variable `count` from the outside. The only way to +interact with it is via the two closures. + + var foo = new Counter(4); + foo.hack = function() { + count = 1337; + }; + +The above code will **not** change the variable `count` in the scope of `Counter`, +since `foo.hack` was not defined in **that** scope. It will instead create - or +override - the *global* variable `count`. + +### Closures Inside Loops + +One often made mistake is to use closures inside of loops, as if they were +copying the value of the loop's index variable. + + for(var i = 0; i < 10; i++) { + setTimeout(function() { + console.log(i); + }, 1000); + } + +The above will **not** output the numbers `0` through `9`, but will simply print +the number `10` ten times. + +The *anonymous* function keeps a **reference** to `i`. At the time +`console.log` gets called, the `for loop` has already finished, and the value of +`i` as been set to `10`. + +In order to get the desired behavior, it is necessary to create a **copy** of +the value of `i`. + +### Avoiding the Reference Problem + +In order to copy the value of the loop's index variable, it is best to use an +[anonymous wrapper](#function.scopes). + + for(var i = 0; i < 10; i++) { + (function(e) { + setTimeout(function() { + console.log(e); + }, 1000); + })(i); + } + +The anonymous outer function gets called immediately with `i` as its first +argument and will receive a copy of the **value** of `i` as its parameter `e`. + +The anonymous function that gets passed to `setTimeout` now has a reference to +`e`, whose value does **not** get changed by the loop. + +There is another possible way of achieving this, which is to return a function +from the anonymous wrapper that will then have the same behavior as the code +above. + + for(var i = 0; i < 10; i++) { + setTimeout((function(e) { + return function() { + console.log(e); + } + })(i), 1000) + } + diff --git a/doc/zh(Trandition)/function/constructors.md b/doc/zh(Trandition)/function/constructors.md new file mode 100644 index 00000000..bf9771dc --- /dev/null +++ b/doc/zh(Trandition)/function/constructors.md @@ -0,0 +1,128 @@ +## Constructors + +Constructors in JavaScript are yet again different from many other languages. Any +function call that is preceded by the `new` keyword acts as a constructor. + +Inside the constructor - the called function - the value of `this` refers to a +newly created object. The [prototype](#object.prototype) of this **new** +object is set to the `prototype` of the function object that was invoked as the +constructor. + +If the function that was called has no explicit `return` statement, then it +implicitly returns the value of `this` - the new object. + + function Foo() { + this.bla = 1; + } + + Foo.prototype.test = function() { + console.log(this.bla); + }; + + var test = new Foo(); + +The above calls `Foo` as constructor and sets the `prototype` of the newly +created object to `Foo.prototype`. + +In case of an explicit `return` statement, the function returns the value +specified by that statement, but **only** if the return value is an `Object`. + + function Bar() { + return 2; + } + new Bar(); // a new object + + function Test() { + this.value = 2; + + return { + foo: 1 + }; + } + new Test(); // the returned object + +When the `new` keyword is omitted, the function will **not** return a new object. + + function Foo() { + this.bla = 1; // gets set on the global object + } + Foo(); // undefined + +While the above example might still appear to work in some cases, due to the +workings of [`this`](#function.this) in JavaScript, it will use the +*global object* as the value of `this`. + +### Factories + +In order to be able to omit the `new` keyword, the constructor function has to +explicitly return a value. + + function Bar() { + var value = 1; + return { + method: function() { + return value; + } + } + } + Bar.prototype = { + foo: function() {} + }; + + new Bar(); + Bar(); + +Both calls to `Bar` return the same thing, a newly create object that +has a property called `method`, which is a +[Closure](#function.closures). + +It should also be noted that the call `new Bar()` does **not** affect the +prototype of the returned object. While the prototype will be set on the newly +created object, `Bar` never returns that new object. + +In the above example, there is no functional difference between using and +not using the `new` keyword. + + +### Creating New Objects via Factories + +It is often recommended to **not** use `new` because forgetting its use may +lead to bugs. + +In order to create a new object, one should rather use a factory and construct a +new object inside of that factory. + + function Foo() { + var obj = {}; + obj.value = 'blub'; + + var private = 2; + obj.someMethod = function(value) { + this.value = value; + } + + obj.getPrivate = function() { + return private; + } + return obj; + } + +While the above is robust against a missing `new` keyword and certainly makes +the use of [private variables](#function.closures) easier, it comes with some +downsides. + + 1. It uses more memory since the created objects do **not** share the methods + on a prototype. + 2. In order to inherit, the factory needs to copy all the methods from another + object or put that object on the prototype of the new object. + 3. Dropping the prototype chain just because of a left out `new` keyword + is contrary to the spirit of the language. + +### In Conclusion + +While omitting the `new` keyword might lead to bugs, it is certainly **not** a +reason to drop the use of prototypes altogether. In the end it comes down to +which solution is better suited for the needs of the application. It is +especially important to choose a specific style of object creation and use it +**consistently**. + diff --git a/doc/zh(Trandition)/function/general.md b/doc/zh(Trandition)/function/general.md new file mode 100644 index 00000000..b2788e46 --- /dev/null +++ b/doc/zh(Trandition)/function/general.md @@ -0,0 +1,48 @@ +## Function Declarations and Expressions + +Functions in JavaScript are first class objects. That means they can be +passed around like any other value. One common use of this feature is to pass +an *anonymous function* as a callback to another, possibly an asynchronous function. + +### The `function` Declaration + + function foo() {} + +The above function gets [hoisted](#function.scopes) before the execution of the +program starts; thus, it is available *everywhere* in the scope it was +*defined*, even if called before the actual definition in the source. + + foo(); // Works because foo was created before this code runs + function foo() {} + +### The `function` Expression + + var foo = function() {}; + +This example assigns the unnamed and *anonymous* function to the variable `foo`. + + foo; // 'undefined' + foo(); // this raises a TypeError + var foo = function() {}; + +Due to the fact that `var` is a declaration that hoists the variable name `foo` +before the actual execution of the code starts, `foo` is already defined when +the script gets executed. + +But since assignments only happen at runtime, the value of `foo` will default +to [undefined](#core.undefined) before the corresponding code is executed. + +### Named Function Expression + +Another special case is the assignment of named functions. + + var foo = function bar() { + bar(); // Works + } + bar(); // ReferenceError + +Here, `bar` is not available in the outer scope, since the function only gets +assigned to `foo`; however, inside of `bar`, it is available. This is due to +how [name resolution](#function.scopes) in JavaScript works, the name of the +function is *always* made available in the local scope of the function itself. + diff --git a/doc/zh(Trandition)/function/scopes.md b/doc/zh(Trandition)/function/scopes.md new file mode 100644 index 00000000..879e1e8a --- /dev/null +++ b/doc/zh(Trandition)/function/scopes.md @@ -0,0 +1,233 @@ +## Scopes and Namespaces + +Although JavaScript deals fine with the syntax of two matching curly +braces for blocks, it does **not** support block scope; hence, all that is left +in the language is *function scope*. + + function test() { // a scope + for(var i = 0; i < 10; i++) { // not a scope + // count + } + console.log(i); // 10 + } + +> **Note:** When not used in an assignment, return statement or as a function +> argument, the `{...}` notation will get interpreted as a block statement and +> **not** as an object literal. This, in conjunction with +> [automatic insertion of semicolons](#core.semicolon), can lead to subtle errors. + +There are also no distinct namespaces in JavaScript, which means that everything +gets defined in one *globally shared* namespace. + +Each time a variable is referenced, JavaScript will traverse upwards through all +the scopes until it finds it. In the case that it reaches the global scope and +still has not found the requested name, it will raise a `ReferenceError`. + +### The Bane of Global Variables + + // script A + foo = '42'; + + // script B + var foo = '42' + +The above two scripts do **not** have the same effect. Script A defines a +variable called `foo` in the *global* scope, and script B defines a `foo` in the +*current* scope. + +Again, that is **not** at all the *same effect*: not using `var` can have major +implications. + + // global scope + var foo = 42; + function test() { + // local scope + foo = 21; + } + test(); + foo; // 21 + +Leaving out the `var` statement inside the function `test` will override the +value of `foo`. While this might not seem like a big deal at first, having +thousands of lines of JavaScript and not using `var` will introduce horrible, +hard-to-track-down bugs. + + // global scope + var items = [/* some list */]; + for(var i = 0; i < 10; i++) { + subLoop(); + } + + function subLoop() { + // scope of subLoop + for(i = 0; i < 10; i++) { // missing var statement + // do amazing stuff! + } + } + +The outer loop will terminate after the first call to `subLoop`, since `subLoop` +overwrites the global value of `i`. Using a `var` for the second `for` loop would +have easily avoided this error. The `var` statement should **never** be left out +unless the *desired effect* is to affect the outer scope. + +### Local Variables + +The only source for local variables in JavaScript are +[function](#function.general) parameters and variables declared via the +`var` statement. + + // global scope + var foo = 1; + var bar = 2; + var i = 2; + + function test(i) { + // local scope of the function test + i = 5; + + var foo = 3; + bar = 4; + } + test(10); + +While `foo` and `i` are local variables inside the scope of the function `test`, +the assignment of `bar` will override the global variable with the same name. + +### Hoisting + +JavaScript **hoists** declarations. This means that both `var` statements and +`function` declarations will be moved to the top of their enclosing scope. + + bar(); + var bar = function() {}; + var someValue = 42; + + test(); + function test(data) { + if (false) { + goo = 1; + + } else { + var goo = 2; + } + for(var i = 0; i < 100; i++) { + var e = data[i]; + } + } + +The above code gets transformed before execution starts. JavaScript moves +the `var` statements, as well as `function` declarations, to the top of the +nearest surrounding scope. + + // var statements got moved here + var bar, someValue; // default to 'undefined' + + // the function declaration got moved up too + function test(data) { + var goo, i, e; // missing block scope moves these here + if (false) { + goo = 1; + + } else { + goo = 2; + } + for(i = 0; i < 100; i++) { + e = data[i]; + } + } + + bar(); // fails with a TypeError since bar is still 'undefined' + someValue = 42; // assignments are not affected by hoisting + bar = function() {}; + + test(); + +Missing block scoping will not only move `var` statements out of loops and +their bodies, it will also make the results of certain `if` constructs +non-intuitive. + +In the original code, although the `if` statement seemed to modify the *global +variable* `goo`, it actually modifies the *local variable* - after hoisting +has been applied. + +Without knowledge of *hoisting*, one might suspect the code below would raise a +`ReferenceError`. + + // check whether SomeImportantThing has been initialized + if (!SomeImportantThing) { + var SomeImportantThing = {}; + } + +But of course, this works due to the fact that the `var` statement is being +moved to the top of the *global scope*. + + var SomeImportantThing; + + // other code might initialize SomeImportantThing here, or not + + // make sure it's there + if (!SomeImportantThing) { + SomeImportantThing = {}; + } + +### Name Resolution Order + +All scopes in JavaScript, including the *global scope*, have the special name +[`this`](#function.this), defined in them, which refers to the *current object*. + +Function scopes also have the name [`arguments`](#function.arguments), defined in +them, which contains the arguments that were passed to the function. + +For example, when trying to access a variable named `foo` inside the scope of a +function, JavaScript will look up the name in the following order: + + 1. In case there is a `var foo` statement in the current scope, use that. + 2. If one of the function parameters is named `foo`, use that. + 3. If the function itself is called `foo`, use that. + 4. Go to the next outer scope, and start with **#1** again. + +> **Note:** Having a parameter called `arguments` will **prevent** the creation +> of the default `arguments` object. + +### Namespaces + +A common problem associated with having only one global namespace is the +likelihood of running into problems where variable names clash. In JavaScript, +this problem can easily be avoided with the help of *anonymous wrappers*. + + (function() { + // a self contained "namespace" + + window.foo = function() { + // an exposed closure + }; + + })(); // execute the function immediately + + +Unnamed functions are considered [expressions](#function.general); so in order to +being callable, they must first be evaluated. + + ( // evaluate the function inside the parentheses + function() {} + ) // and return the function object + () // call the result of the evaluation + +There are other ways to evaluate and directly call the function expression +which, while different in syntax, behave the same way. + + // A few other styles for directly invoking the + !function(){}() + +function(){}() + (function(){}()); + // and so on... + +### In Conclusion + +It is recommended to always use an *anonymous wrapper* to encapsulate code in +its own namespace. This does not only protect code against name clashes, but it +also allows for better modularization of programs. + +Additionally, the use of global variables is considered **bad practice**. **Any** +use of them indicates badly written code that is prone to errors and hard to maintain. + diff --git a/doc/zh(Trandition)/function/this.md b/doc/zh(Trandition)/function/this.md new file mode 100644 index 00000000..48070d2e --- /dev/null +++ b/doc/zh(Trandition)/function/this.md @@ -0,0 +1,111 @@ +## How `this` Works + +JavaScript has a different concept of what the special name `this` refers to +than most other programming languages. There are exactly **five** different +ways in which the value of `this` can be bound in the language. + +### The Global Scope + + this; + +When using `this` in global scope, it will simply refer to the *global* object. + + +### Calling a Function + + foo(); + +Here, `this` will again refer to the *global* object. + +> **ES5 Note:** In strict mode, the global case **no longer** exists. +> `this` will instead have the value of `undefined` in that case. + +### Calling a Method + + test.foo(); + +In this example, `this` will refer to `test`. + +### Calling a Constructor + + new foo(); + +A function call that is preceded by the `new` keyword acts as +a [constructor](#function.constructors). Inside the function, `this` will refer +to a *newly created* `Object`. + +### Explicit Setting of `this` + + function foo(a, b, c) {} + + var bar = {}; + foo.apply(bar, [1, 2, 3]); // array will expand to the below + foo.call(bar, 1, 2, 3); // results in a = 1, b = 2, c = 3 + +When using the `call` or `apply` methods of `Function.prototype`, the value of +`this` inside the called function gets **explicitly set** to the first argument +of the corresponding function call. + +As a result, in the above example the *method case* does **not** apply, and `this` +inside of `foo` will be set to `bar`. + +> **Note:** `this` **cannot** be used to refer to the object inside of an `Object` +> literal. So `var obj = {me: this}` will **not** result in `me` referring to +> `obj`, since `this` only gets bound by one of the five listed cases. + +### Common Pitfalls + +While most of these cases make sense, the first can be considered another +mis-design of the language because it **never** has any practical use. + + Foo.method = function() { + function test() { + // this is set to the global object + } + test(); + } + +A common misconception is that `this` inside of `test` refers to `Foo`; while in +fact, it **does not**. + +In order to gain access to `Foo` from within `test`, it is necessary to create a +local variable inside of `method` that refers to `Foo`. + + Foo.method = function() { + var that = this; + function test() { + // Use that instead of this here + } + test(); + } + +`that` is just a normal variable name, but it is commonly used for the reference to an +outer `this`. In combination with [closures](#function.closures), it can also +be used to pass `this` values around. + +### Assigning Methods + +Another thing that does **not** work in JavaScript is function aliasing, which is +**assigning** a method to a variable. + + var test = someObject.methodTest; + test(); + +Due to the first case, `test` now acts like a plain function call; therefore, +`this` inside it will no longer refer to `someObject`. + +While the late binding of `this` might seem like a bad idea at first, in +fact, it is what makes [prototypal inheritance](#object.prototype) work. + + function Foo() {} + Foo.prototype.method = function() {}; + + function Bar() {} + Bar.prototype = Foo.prototype; + + new Bar().method(); + +When `method` gets called on an instance of `Bar`, `this` will now refer to that +very instance. + + diff --git a/doc/zh(Trandition)/index.json b/doc/zh(Trandition)/index.json new file mode 100644 index 00000000..bffcbf2c --- /dev/null +++ b/doc/zh(Trandition)/index.json @@ -0,0 +1,69 @@ +{ + "title": "JavaScript Garden", + "langTitle": "JavaScript Garden in English", + "description": "A Guide to JavaScript's Quirks and Flaws.", + "sections": [ + { + "title": "Intro", + "dir": "intro", + "articles": [] + }, + { + "title": "Objects", + "dir": "object", + "articles": [ + "general", + "prototype", + "hasownproperty", + "forinloop" + ] + }, + { + "title": "Functions", + "dir": "function", + "articles": [ + "general", + "this", + "closures", + "arguments", + "constructors", + "scopes" + ] + }, + { + "title": "Arrays", + "dir": "array", + "articles": [ + "general", + "constructor" + ] + }, + { + "title": "Types", + "dir": "types", + "articles": [ + "equality", + "typeof", + "instanceof", + "casting" + ] + }, + { + "title": "Core", + "dir": "core", + "articles": [ + "eval", + "undefined", + "semicolon", + "delete" + ] + }, + { + "title": "Other", + "dir": "other", + "articles": [ + "timeouts" + ] + } + ] +} diff --git a/doc/zh(Trandition)/intro/index.md b/doc/zh(Trandition)/intro/index.md new file mode 100644 index 00000000..134bca80 --- /dev/null +++ b/doc/zh(Trandition)/intro/index.md @@ -0,0 +1,47 @@ +## Intro + +**JavaScript Garden** is a growing collection of documentation about the most +quirky parts of the JavaScript programming language. It gives advice to +avoid common mistakes and subtle bugs, as well as performance issues and bad +practices, that non-expert JavaScript programmers may encounter on their +endeavours into the depths of the language. + +JavaScript Garden does **not** aim to teach you JavaScript. Former knowledge +of the language is strongly recommended in order to understand the topics covered +in this guide. In order to learn the basics of the language, please head over to +the excellent [guide][1] on the Mozilla Developer Network. + +## The Authors + +This guide is the work of two lovely [Stack Overflow][2] users, [Ivo Wetzel][3] +(Writing) and [Zhang Yi Jiang][4] (Design). + +## Contributors + + - [Caio Romão][5] (Spelling corrections) + - [Andreas Blixt][6] (Language corrections) + +## Hosting + +JavaScript Garden is hosted on GitHub, but [Cramer Development][7] supports us +with a mirror at [JavaScriptGarden.info][8]. + +## License + +JavaScript Garden is published under the [MIT license][9] and hosted on +[GitHub][10]. If you find errors or typos please [file an issue][11] or a pull +request on the repository. You can also find us in the [JavaScript room][12] on +Stack Overflow chat. + +[1]: https://developer.mozilla.org/en/JavaScript/Guide +[2]: http://stackoverflow.com/ +[3]: http://stackoverflow.com/users/170224/ivo-wetzel +[4]: http://stackoverflow.com/users/313758/yi-jiang +[5]: https://github.com/caio +[6]: https://github.com/blixt +[7]: http://cramerdev.com/ +[8]: http://javascriptgarden.info/ +[9]: https://github.com/BonsaiDen/JavaScript-Garden/blob/next/LICENSE +[10]: https://github.com/BonsaiDen/JavaScript-Garden +[11]: https://github.com/BonsaiDen/JavaScript-Garden/issues +[12]: http://chat.stackoverflow.com/rooms/17/javascript diff --git a/doc/zh(Trandition)/object/forinloop.md b/doc/zh(Trandition)/object/forinloop.md new file mode 100644 index 00000000..3d366f8c --- /dev/null +++ b/doc/zh(Trandition)/object/forinloop.md @@ -0,0 +1,51 @@ +## The `for in` Loop + +Just like the `in` operator, the `for in` loop traverses the prototype +chain when iterating over the properties of an object. + +> **Note:** The `for in` loop will **not** iterate over any properties that +> have their `enumerable` attribute set to `false`; for example, the `length` +> property of an array. + + // Poisoning Object.prototype + Object.prototype.bar = 1; + + var foo = {moo: 2}; + for(var i in foo) { + console.log(i); // prints both bar and moo + } + +Since it is not possible to change the behavior of the `for in` loop itself, it +is necessary to filter out the unwanted properties inside the loop body; +this is done using the [`hasOwnProperty`](#object.hasownproperty) method of +`Object.prototype`. + +> **Note:** Since `for in` always traverses the complete prototype chain, it +> will get slower with each additional layer of inheritance added to an object. + +### Using `hasOwnProperty` for Filtering + + // still the foo from above + for(var i in foo) { + if (foo.hasOwnProperty(i)) { + console.log(i); + } + } + +This version is the only correct one to use. Due to the use of `hasOwnProperty`, it +will **only** print out `moo`. When `hasOwnProperty` is left out, the code is +prone to errors in cases where the native prototypes - e.g. `Object.prototype` - +have been extended. + +One widely used framework that extends `Object.prototype` is [Prototype][1]. +When this framework is included, `for in` loops that do not use +`hasOwnProperty` are guaranteed to break. + +### In Conclusion + +It is recommended to **always** use `hasOwnProperty`. Assumptions should never +be made about the environment the code is running in, or whether the native +prototypes have been extended or not. + +[1]: http://www.prototypejs.org/ + diff --git a/doc/zh(Trandition)/object/general.md b/doc/zh(Trandition)/object/general.md new file mode 100644 index 00000000..9300b18e --- /dev/null +++ b/doc/zh(Trandition)/object/general.md @@ -0,0 +1,99 @@ +## Object Usage and Properties + +Everything in JavaScript acts like an object, with the only two exceptions being +[`null`](#core.undefined) and [`undefined`](#core.undefined). + + false.toString(); // 'false' + [1, 2, 3].toString(); // '1,2,3' + + function Foo(){} + Foo.bar = 1; + Foo.bar; // 1 + +A common misconception is that number literals cannot be used as +objects. That is because a flaw in JavaScript's parser tries to parse the *dot +notation* on a number as a floating point literal. + + 2.toString(); // raises SyntaxError + +There are a couple of workarounds that can be used to make number literals act +as objects too. + + 2..toString(); // the second point is correctly recognized + 2 .toString(); // note the space left to the dot + (2).toString(); // 2 is evaluated first + +### Objects as a Data Type + +Objects in JavaScript can also be used as [*Hashmaps*][1]; they mainly consist +of named properties mapping to values. + +Using an object literal - `{}` notation - it is possible to create a +plain object. This new object [inherits](#object.prototype) from `Object.prototype` and +does not have [own properties](#object.hasownproperty) defined. + + var foo = {}; // a new empty object + + // a new object with a 'test' property with value 12 + var bar = {test: 12}; + +### Accessing Properties + +The properties of an object can be accessed in two ways, via either the dot +notation or the square bracket notation. + + var foo = {name: 'kitten'} + foo.name; // kitten + foo['name']; // kitten + + var get = 'name'; + foo[get]; // kitten + + foo.1234; // SyntaxError + foo['1234']; // works + +The notations work almost identically, with the only difference being that the +square bracket notation allows for dynamic setting of properties and +the use of property names that would otherwise lead to a syntax error. + +### Deleting Properties + +The only way to remove a property from an object is to use the `delete` +operator; setting the property to `undefined` or `null` only removes the +*value* associated with the property, but not the *key*. + + var obj = { + bar: 1, + foo: 2, + baz: 3 + }; + obj.bar = undefined; + obj.foo = null; + delete obj.baz; + + for(var i in obj) { + if (obj.hasOwnProperty(i)) { + console.log(i, '' + obj[i]); + } + } + +The above outputs both `bar undefined` and `foo null` - only `baz` was +removed and is therefore missing from the output. + +### Notation of Keys + + var test = { + 'case': 'I am a keyword, so I must be notated as a string', + delete: 'I am a keyword, so me too' // raises SyntaxError + }; + +Object properties can be both notated as plain characters and as strings. Due to +another mis-design in JavaScript's parser, the above will throw +a `SyntaxError` prior to ECMAScript 5. + +This error arises from the fact that `delete` is a *keyword*; therefore, it must be +notated as a *string literal* to ensure that it will be correctly interpreted by +older JavaScript engines. + +[1]: http://en.wikipedia.org/wiki/Hashmap + diff --git a/doc/zh(Trandition)/object/hasownproperty.md b/doc/zh(Trandition)/object/hasownproperty.md new file mode 100644 index 00000000..0033b4ba --- /dev/null +++ b/doc/zh(Trandition)/object/hasownproperty.md @@ -0,0 +1,57 @@ +## `hasOwnProperty` + +To check whether an object has a property defined on *itself* and not somewhere +on its [prototype chain](#object.prototype), it is necessary to use the +`hasOwnProperty` method which all objects inherit from `Object.prototype`. + +> **Note:** It is **not** enough to check whether a property is `undefined`. The +> property might very well exist, but its value just happens to be set to +> `undefined`. + +`hasOwnProperty` is the only thing in JavaScript which deals with properties and +does **not** traverse the prototype chain. + + // Poisoning Object.prototype + Object.prototype.bar = 1; + var foo = {goo: undefined}; + + foo.bar; // 1 + 'bar' in foo; // true + + foo.hasOwnProperty('bar'); // false + foo.hasOwnProperty('goo'); // true + +Only `hasOwnProperty` will give the correct and expected result; this is +essential when iterating over the properties of any object. There is **no** other +way to exclude properties that are not defined on the object itself, but +somewhere on its prototype chain. + +### `hasOwnProperty` as a Property + +JavaScript does not protect the property name `hasOwnProperty`; thus, if the +possibility exists that an object might have a property with this name, it is +necessary to use an *external* `hasOwnProperty` to get correct results. + + var foo = { + hasOwnProperty: function() { + return false; + }, + bar: 'Here be dragons' + }; + + foo.hasOwnProperty('bar'); // always returns false + + // Use another Object's hasOwnProperty and call it with 'this' set to foo + ({}).hasOwnProperty.call(foo, 'bar'); // true + + // It's also possible to use the hasOwnProperty property from the Object property for this purpose + Object.prototype.hasOwnProperty.call(obj, 'bar'); // true + + +### In Conclusion + +Using `hasOwnProperty` is the **only** reliable method to check for the +existence of a property on an object. It is recommended that `hasOwnProperty` +is used in **every** [`for in` loop](#object.forinloop) to avoid errors from +extended native [prototypes](#object.prototype). + diff --git a/doc/zh(Trandition)/object/prototype.md b/doc/zh(Trandition)/object/prototype.md new file mode 100644 index 00000000..abb67c58 --- /dev/null +++ b/doc/zh(Trandition)/object/prototype.md @@ -0,0 +1,118 @@ +## The Prototype + +JavaScript does not feature a classical inheritance model; instead, it uses a +*prototypal* one. + +While this is often considered to be one of JavaScript's weaknesses, the +prototypal inheritance model is in fact more powerful than the classic model. +It is, for example, fairly trivial to build a classic model on top of a +prototypal model, while the other way around is a far more difficult task. + +JavaScript is the only widely used language that features prototypal +inheritance, so it can take time to adjust to the differences between the two +models. + +The first major difference is that inheritance in JavaScript uses *prototype +chains*. + +> **Note:** Simply using `Bar.prototype = Foo.prototype` will result in both objects +> sharing the **same** prototype. Therefore, changes to either object's prototype +> will affect the prototype of the other as well, which in most cases is not the +> desired effect. + + function Foo() { + this.value = 42; + } + Foo.prototype = { + method: function() {} + }; + + function Bar() {} + + // Set Bar's prototype to a new instance of Foo + Bar.prototype = new Foo(); + Bar.prototype.foo = 'Hello World'; + + // Make sure to list Bar as the actual constructor + Bar.prototype.constructor = Bar; + + var test = new Bar() // create a new bar instance + + // The resulting prototype chain + test [instance of Bar] + Bar.prototype [instance of Foo] + { foo: 'Hello World' } + Foo.prototype + { method: ... } + Object.prototype + { toString: ... /* etc. */ } + +In the code above, the object `test` will inherit from both `Bar.prototype` and +`Foo.prototype`; hence, it will have access to the function `method` that was +defined on `Foo`. It will also have access to the property `value` of the +**one** `Foo` instance that is its prototype. It is important to note that `new +Bar()` does **not** create a new `Foo` instance, but reuses the one assigned to +its prototype; thus, all `Bar` instances will share the **same** `value` property. + +> **Note:** Do **not** use `Bar.prototype = Foo`, since it will not point to +> the prototype of `Foo` but rather to the function object `Foo`. So the +> prototype chain will go over `Function.prototype` and not `Foo.prototype`; +> therefore, `method` will not be on the prototype chain. + +### Property Lookup + +When accessing the properties of an object, JavaScript will traverse the +prototype chain **upwards** until it finds a property with the requested name. + +If it reaches the top of the chain - namely `Object.prototype` - and still +hasn't found the specified property, it will return the value +[undefined](#core.undefined) instead. + +### The Prototype Property + +While the prototype property is used by the language to build the prototype +chains, it is still possible to assign **any** given value to it. However, +primitives will simply get ignored when assigned as a prototype. + + function Foo() {} + Foo.prototype = 1; // no effect + +Assigning objects, as shown in the example above, will work, and allows for dynamic +creation of prototype chains. + +### Performance + +The lookup time for properties that are high up on the prototype chain can have +a negative impact on performance, and this may be significant in code where +performance is critical. Additionally, trying to access non-existent properties +will always traverse the full prototype chain. + +Also, when [iterating](#object.forinloop) over the properties of an object +**every** property that is on the prototype chain will be enumerated. + +### Extension of Native Prototypes + +One mis-feature that is often used is to extend `Object.prototype` or one of the +other built in prototypes. + +This technique is called [monkey patching][1] and breaks *encapsulation*. While +used by popular frameworks such as [Prototype][2], there is still no good +reason for cluttering built-in types with additional *non-standard* functionality. + +The **only** good reason for extending a built-in prototype is to backport +the features of newer JavaScript engines; for example, +[`Array.forEach`][3]. + +### In Conclusion + +It is **essential** to understand the prototypal inheritance model before +writing complex code that makes use of it. Also, be aware of the length of the +prototype chains in your code and break them up if necessary to avoid possible +performance problems. Further, the native prototypes should **never** be +extended unless it is for the sake of compatibility with newer JavaScript +features. + +[1]: http://en.wikipedia.org/wiki/Monkey_patch +[2]: http://prototypejs.org/ +[3]: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach + diff --git a/doc/zh(Trandition)/other/timeouts.md b/doc/zh(Trandition)/other/timeouts.md new file mode 100644 index 00000000..578fad5f --- /dev/null +++ b/doc/zh(Trandition)/other/timeouts.md @@ -0,0 +1,167 @@ +### `setTimeout` and `setInterval` + +Since JavaScript is asynchronous, it is possible to schedule the execution of a +function using the `setTimeout` and `setInterval` functions. + +> **Note:** Timeouts are **not** part of the ECMAScript Standard. They are +> implemented as part of the [DOM][1]. + + function foo() {} + var id = setTimeout(foo, 1000); // returns a Number > 0 + +When `setTimeout` is called, it returns the ID of the timeout and schedule +`foo` to run **approximately** one thousand milliseconds in the future. +`foo` will then be executed **once**. + +Depending on the timer resolution of the JavaScript engine running the code, as +well as the fact that JavaScript is single threaded and other code that gets +executed might block the thread, it is by **no means** a safe bet that one will +get the exact delay specified in the `setTimeout` call. + +The function that was passed as the first parameter will get called by the +*global object*, which means that [`this`](#function.this) inside the called function +refers to the global object. + + function Foo() { + this.value = 42; + this.method = function() { + // this refers to the global object + console.log(this.value); // will log undefined + }; + setTimeout(this.method, 500); + } + new Foo(); + + +> **Note:** As `setTimeout` takes a **function object** as its first parameter, an +> common mistake is to use `setTimeout(foo(), 1000)`, which will use the +> **return value** of the call `foo` and **not** `foo`. This is, most of the time, +> a silent error, since when the function returns `undefined` `setTimeout` will +> **not** raise any error. + +### Stacking Calls with `setInterval` + +While `setTimeout` only runs the function once, `setInterval` - as the name +suggests - will execute the function **every** `X` milliseconds, but its use is +discouraged. + +When code that is being executed blocks the timeout call, `setInterval` will +still issue more calls to the specified function. This can, especially with small +intervals, result in function calls stacking up. + + function foo(){ + // something that blocks for 1 second + } + setInterval(foo, 1000); + +In the above code, `foo` will get called once and will then block for one second. + +While `foo` blocks the code, `setInterval` will still schedule further calls to +it. Now, when `foo` has finished, there will already be **ten** further calls to +it waiting for execution. + +### Dealing with Possible Blocking Code + +The easiest solution, as well as most controllable solution, is to use `setTimeout` within +the function itself. + + function foo(){ + // something that blocks for 1 second + setTimeout(foo, 1000); + } + foo(); + +Not only does this encapsulate the `setTimeout` call, but it also prevents the +stacking of calls and gives additional control. `foo` itself can now decide +whether it wants to run again or not. + +### Manually Clearing Timeouts + +Clearing timeouts and intervals works by passing the respective ID to +`clearTimeout` or `clearInterval`, depending on which `set` function was used +in the first place. + + var id = setTimeout(foo, 1000); + clearTimeout(id); + +### Clearing All Timeouts + +As there is no built-in method for clearing all timeouts and/or intervals, +it is necessary to use brute force in order to achieve this functionality. + + // clear "all" timeouts + for(var i = 1; i < 1000; i++) { + clearTimeout(i); + } + +But there might still be timeouts that are unaffected by this arbitrary number. +Another way of doing this is to consider that the ID given to a timeout is +incremented by one every time you call `setTimeout`. + + // clear "all" timeouts + var biggestTimeoutId = window.setTimeout(function(){}, 1), + i; + for(i = 1; i <= biggestTimeoutId; i++) { + clearTimeout(i); + } + +Even though this works on all major browsers today, it isn't specified that +the IDs should be ordered that way and it may change. Therefore, it is instead +recommended to keep track of all the timeout IDs, so they can be cleared +specifically. + +### Hidden Use of `eval` + +`setTimeout` and `setInterval` can also take a string as their first parameter. +This feature should **never** be used because it internally makes use of `eval`. + +> **Note:** Since the timeout functions are **not** specified by the ECMAScript +> standard, the exact workings when a string is passed to them might differ in +> various JavaScript implementations. For example, Microsoft's JScript uses +> the `Function` constructor in place of `eval`. + + function foo() { + // will get called + } + + function bar() { + function foo() { + // never gets called + } + setTimeout('foo()', 1000); + } + bar(); + +Since `eval` is not getting called [directly](#core.eval) in this case, the string +passed to `setTimeout` will be executed in the *global scope*; thus, it will +not use the local variable `foo` from the scope of `bar`. + +It is further recommended to **not** use a string to pass arguments to the +function that will get called by either of the timeout functions. + + function foo(a, b, c) {} + + // NEVER use this + setTimeout('foo(1, 2, 3)', 1000) + + // Instead use an anonymous function + setTimeout(function() { + foo(a, b, c); + }, 1000) + +> **Note:** While it is also possible to use the syntax +> `setTimeout(foo, 1000, a, b, c)`, it is not recommended, as its use may lead +> to subtle errors when used with [methods](#function.this). + +### In Conclusion + +A string should **never** be used as the parameter of `setTimeout` or +`setInterval`. It is a clear sign of **really** bad code, when arguments need +to be supplied to the function that gets called. An *anonymous function* should +be passed that then takes care of the actual call. + +Furthermore, the use of `setInterval` should be avoided because its scheduler is not +blocked by executing JavaScript. + +[1]: http://en.wikipedia.org/wiki/Document_Object_Model "Document Object Model" + diff --git a/doc/zh(Trandition)/types/casting.md b/doc/zh(Trandition)/types/casting.md new file mode 100644 index 00000000..0dcbc92b --- /dev/null +++ b/doc/zh(Trandition)/types/casting.md @@ -0,0 +1,70 @@ +## Type Casting + +JavaScript is a *weakly typed* language, so it will apply *type coercion* +**wherever** possible. + + // These are true + new Number(10) == 10; // Number.toString() is converted + // back to a number + + 10 == '10'; // Strings gets converted to Number + 10 == '+10 '; // More string madness + 10 == '010'; // And more + isNaN(null) == false; // null converts to 0 + // which of course is not NaN + + // These are false + 10 == 010; + 10 == '-10'; + +> **ES5 Note:** Number literals that start with a `0` are interpreted as octal +> (Base 8). Octal support for these has been **removed** in ECMAScript 5 strict +> mode. + +To avoid the issues above, use of the [strict equal operator](#types.equality) +is **highly** recommended. Although this avoids a lot of common pitfalls, there +are still many further issues that arise from JavaScript's weak typing system. + +### Constructors of Built-In Types + +The constructors of the built in types like `Number` and `String` behave +differently when being used with the `new` keyword and without it. + + new Number(10) === 10; // False, Object and Number + Number(10) === 10; // True, Number and Number + new Number(10) + 0 === 10; // True, due to implicit conversion + +Using a built-in type like `Number` as a constructor will create a new `Number` +object, but leaving out the `new` keyword will make the `Number` function behave +like a converter. + +In addition, passing literals or non-object values will result in even more +type coercion. + +The best option is to cast to one of the three possible types **explicitly**. + +### Casting to a String + + '' + 10 === '10'; // true + +By prepending an empty string, a value can easily be cast to a string. + +### Casting to a Number + + +'10' === 10; // true + +Using the **unary** plus operator, it is possible to cast to a number. + +### Casting to a Boolean + +By using the **not** operator twice, a value can be converted a boolean. + + !!'foo'; // true + !!''; // false + !!'0'; // true + !!'1'; // true + !!'-1' // true + !!{}; // true + !!true; // true + + diff --git a/doc/zh(Trandition)/types/equality.md b/doc/zh(Trandition)/types/equality.md new file mode 100644 index 00000000..e47752a4 --- /dev/null +++ b/doc/zh(Trandition)/types/equality.md @@ -0,0 +1,71 @@ +## Equality and Comparisons + +JavaScript has two different ways of comparing the values of objects for equality. + +### The Equality Operator + +The equality operator consists of two equal signs: `==` + +JavaScript features *weak typing*. This means that the equality operator +**coerces** types in order to compare them. + + "" == "0" // false + 0 == "" // true + 0 == "0" // true + false == "false" // false + false == "0" // true + false == undefined // false + false == null // false + null == undefined // true + " \t\r\n" == 0 // true + +The above table shows the results of the type coercion, and it is the main reason +why the use of `==` is widely regarded as bad practice. It introduces +hard-to-track-down bugs due to its complicated conversion rules. + +Additionally, there is also a performance impact when type coercion is in play; +for example, a string has to be converted to a number before it can be compared +to another number. + +### The Strict Equality Operator + +The strict equality operator consists of **three** equal signs: `===`. + +It works like the normal equality operator, except that strict equality +operator does **not** perform type coercion between its operands. + + "" === "0" // false + 0 === "" // false + 0 === "0" // false + false === "false" // false + false === "0" // false + false === undefined // false + false === null // false + null === undefined // false + " \t\r\n" === 0 // false + +The above results are a lot clearer and allow for early breakage of code. This +hardens code to a certain degree and also gives performance improvements in case +the operands are of different types. + +### Comparing Objects + +While both `==` and `===` are called **equality** operators, they behave +differently when at least one of their operands is an `Object`. + + {} === {}; // false + new String('foo') === 'foo'; // false + new Number(10) === 10; // false + var foo = {}; + foo === foo; // true + +Here, both operators compare for **identity** and **not** equality; that is, they +will compare for the same **instance** of the object, much like `is` in Python +and pointer comparison in C. + +### In Conclusion + +It is highly recommended to only use the **strict equality** operator. In cases +where types need to be coerced, it should be done [explicitly](#types.casting) +and not left to the language's complicated coercion rules. + diff --git a/doc/zh(Trandition)/types/instanceof.md b/doc/zh(Trandition)/types/instanceof.md new file mode 100644 index 00000000..2fe41064 --- /dev/null +++ b/doc/zh(Trandition)/types/instanceof.md @@ -0,0 +1,38 @@ +## The `instanceof` Operator + +The `instanceof` operator compares the constructors of its two operands. It is +only useful when comparing custom made objects. Used on built-in types, it is +nearly as useless as the [typeof operator](#types.typeof). + +### Comparing Custom Objects + + function Foo() {} + function Bar() {} + Bar.prototype = new Foo(); + + new Bar() instanceof Bar; // true + new Bar() instanceof Foo; // true + + // This just sets Bar.prototype to the function object Foo, + // but not to an actual instance of Foo + Bar.prototype = Foo; + new Bar() instanceof Foo; // false + +### Using `instanceof` with Native Types + + new String('foo') instanceof String; // true + new String('foo') instanceof Object; // true + + 'foo' instanceof String; // false + 'foo' instanceof Object; // false + +One important thing to note here is that `instanceof` does not work on objects +that originate from different JavaScript contexts (e.g. different documents +in a web browser), since their constructors will not be the exact same object. + +### In Conclusion + +The `instanceof` operator should **only** be used when dealing with custom made +objects that originate from the same JavaScript context. Just like the +[`typeof`](#types.typeof) operator, every other use of it should be **avoided**. + diff --git a/doc/zh(Trandition)/types/typeof.md b/doc/zh(Trandition)/types/typeof.md new file mode 100644 index 00000000..637ea2bc --- /dev/null +++ b/doc/zh(Trandition)/types/typeof.md @@ -0,0 +1,86 @@ +## The `typeof` Operator + +The `typeof` operator (together with +[`instanceof`](#types.instanceof)) is probably the biggest +design flaw of JavaScript, as it is almost **completely broken**. + +Although `instanceof` still has limited uses, `typeof` really has only one +practical use case, which does **not** happen to be checking the type of an +object. + +> **Note:** While `typeof` can also be called with a function like syntax, i.e. +> `typeof(obj)`, this is not a function call. The parentheses behave as normal +> and the return value will be used as the operand of the `typeof` operator. +> There is **no** `typeof` function. + +### The JavaScript Type Table + + Value Class Type + ------------------------------------- + "foo" String string + new String("foo") String object + 1.2 Number number + new Number(1.2) Number object + true Boolean boolean + new Boolean(true) Boolean object + new Date() Date object + new Error() Error object + [1,2,3] Array object + new Array(1, 2, 3) Array object + new Function("") Function function + /abc/g RegExp object (function in Nitro/V8) + new RegExp("meow") RegExp object (function in Nitro/V8) + {} Object object + new Object() Object object + +In the above table, *Type* refers to the value that the `typeof` operator returns. +As can be clearly seen, this value is anything but consistent. + +The *Class* refers to the value of the internal `[[Class]]` property of an object. + +> **From the Specification:** The value of `[[Class]]` can be one of the +> following strings. `Arguments`, `Array`, `Boolean`, `Date`, `Error`, +> `Function`, `JSON`, `Math`, `Number`, `Object`, `RegExp`, `String`. + +In order to retrieve the value of `[[Class]]`, one has to make use of the +`toString` method of `Object.prototype`. + +### The Class of an Object + +The specification gives exactly one way of accessing the `[[Class]]` value, +with the use of `Object.prototype.toString`. + + function is(type, obj) { + var clas = Object.prototype.toString.call(obj).slice(8, -1); + return obj !== undefined && obj !== null && clas === type; + } + + is('String', 'test'); // true + is('String', new String('test')); // true + +In the above example, `Object.prototype.toString` gets called with the value of +[this](#function.this) being set to the object whose `[[Class]]` value should be +retrieved. + +> **ES5 Note:** For convenience the return value of `Object.prototype.toString` +> for both `null` and `undefined` was **changed** from `Object` to `Null` and +> `Undefined` in ECMAScript 5. + +### Testing for Undefined Variables + + typeof foo !== 'undefined' + +The above will check whether `foo` was actually declared or not; just +referencing it would result in a `ReferenceError`. This is the only thing +`typeof` is actually useful for. + +### In Conclusion + +In order to check the type of an object, it is highly recommended to use +`Object.prototype.toString` because this is the only reliable way of doing so. +As shown in the above type table, some return values of `typeof` are not defined +in the specification; thus, they can differ between implementations. + +Unless checking whether a variable is defined, `typeof` should be avoided. + + From 151456f3bed2db1a99d7e197f3cecdb946acd519 Mon Sep 17 00:00:00 2001 From: howardchi Date: Wed, 13 Mar 2013 22:09:32 +0800 Subject: [PATCH 069/277] finished the part in Array & some in function section --- .gitignore | 1 + doc/zh(Trandition)/core/undefined.md | 70 - doc/zh(Trandition)/function/arguments.md | 118 - .../array/constructor.md | 0 .../array/general.md | 0 doc/{zh(Trandition) => zh-TW}/core/delete.md | 0 doc/{zh(Trandition) => zh-TW}/core/eval.md | 0 .../core/semicolon.md | 0 doc/zh-TW/core/undefined.md | 55 + doc/zh-TW/function/arguments.md | 103 + .../function/closures.md | 0 .../function/constructors.md | 0 .../function/general.md | 0 .../function/scopes.md | 0 .../function/this.md | 0 doc/{zh(Trandition) => zh-TW}/index.json | 0 doc/{zh(Trandition) => zh-TW}/intro/index.md | 0 .../object/forinloop.md | 0 .../object/general.md | 0 .../object/hasownproperty.md | 0 .../object/prototype.md | 0 .../other/timeouts.md | 0 .../types/casting.md | 0 .../types/equality.md | 0 .../types/instanceof.md | 0 doc/{zh(Trandition) => zh-TW}/types/typeof.md | 0 site/zh-TW/index.html | 1913 +++++++++++++++++ 27 files changed, 2072 insertions(+), 188 deletions(-) delete mode 100644 doc/zh(Trandition)/core/undefined.md delete mode 100644 doc/zh(Trandition)/function/arguments.md rename doc/{zh(Trandition) => zh-TW}/array/constructor.md (100%) rename doc/{zh(Trandition) => zh-TW}/array/general.md (100%) rename doc/{zh(Trandition) => zh-TW}/core/delete.md (100%) rename doc/{zh(Trandition) => zh-TW}/core/eval.md (100%) rename doc/{zh(Trandition) => zh-TW}/core/semicolon.md (100%) create mode 100644 doc/zh-TW/core/undefined.md create mode 100644 doc/zh-TW/function/arguments.md rename doc/{zh(Trandition) => zh-TW}/function/closures.md (100%) rename doc/{zh(Trandition) => zh-TW}/function/constructors.md (100%) rename doc/{zh(Trandition) => zh-TW}/function/general.md (100%) rename doc/{zh(Trandition) => zh-TW}/function/scopes.md (100%) rename doc/{zh(Trandition) => zh-TW}/function/this.md (100%) rename doc/{zh(Trandition) => zh-TW}/index.json (100%) rename doc/{zh(Trandition) => zh-TW}/intro/index.md (100%) rename doc/{zh(Trandition) => zh-TW}/object/forinloop.md (100%) rename doc/{zh(Trandition) => zh-TW}/object/general.md (100%) rename doc/{zh(Trandition) => zh-TW}/object/hasownproperty.md (100%) rename doc/{zh(Trandition) => zh-TW}/object/prototype.md (100%) rename doc/{zh(Trandition) => zh-TW}/other/timeouts.md (100%) rename doc/{zh(Trandition) => zh-TW}/types/casting.md (100%) rename doc/{zh(Trandition) => zh-TW}/types/equality.md (100%) rename doc/{zh(Trandition) => zh-TW}/types/instanceof.md (100%) rename doc/{zh(Trandition) => zh-TW}/types/typeof.md (100%) create mode 100644 site/zh-TW/index.html diff --git a/.gitignore b/.gitignore index 237404f0..63b10902 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ /site/es *.md~ *.src.md +*.DS_store diff --git a/doc/zh(Trandition)/core/undefined.md b/doc/zh(Trandition)/core/undefined.md deleted file mode 100644 index 51101912..00000000 --- a/doc/zh(Trandition)/core/undefined.md +++ /dev/null @@ -1,70 +0,0 @@ -## `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`. - - diff --git a/doc/zh(Trandition)/function/arguments.md b/doc/zh(Trandition)/function/arguments.md deleted file mode 100644 index 2394177d..00000000 --- a/doc/zh(Trandition)/function/arguments.md +++ /dev/null @@ -1,118 +0,0 @@ -## The `arguments` Object - -Every function scope in JavaScript can access the special variable `arguments`. -This variable holds a list of all the arguments that were passed to the function. - -> **Note:** In case `arguments` has already been defined inside the function's -> scope either via a `var` statement or being the name of a formal parameter, -> the `arguments` object will not be created. - -The `arguments` object is **not** an `Array`. While it has some of the -semantics of an array - namely the `length` property - it does not inherit from -`Array.prototype` and is in fact an `Object`. - -Due to this, it is **not** possible to use standard array methods like `push`, -`pop` or `slice` on `arguments`. While iteration with a plain `for` loop works -just fine, it is necessary to convert it to a real `Array` in order to use the -standard `Array` methods on it. - -### Converting to an Array - -The code below will return a new `Array` containing all the elements of the -`arguments` object. - - Array.prototype.slice.call(arguments); - -Because this conversion is **slow**, it is **not recommended** to use it in -performance-critical sections of code. - -### Passing Arguments - -The following is the recommended way of passing arguments from one function to -another. - - function foo() { - bar.apply(null, arguments); - } - function bar(a, b, c) { - // do stuff here - } - -Another trick is to use both `call` and `apply` together to create fast, unbound -wrappers. - - function Foo() {} - - Foo.prototype.method = function(a, b, c) { - console.log(this, a, b, c); - }; - - // Create an unbound version of "method" - // It takes the parameters: this, arg1, arg2...argN - Foo.method = function() { - - // Result: Foo.prototype.method.call(this, arg1, arg2... argN) - Function.call.apply(Foo.prototype.method, arguments); - }; - - -### Formal Parameters and Arguments Indices - -The `arguments` object creates *getter* and *setter* functions for both its -properties, as well as the function's formal parameters. - -As a result, changing the value of a formal parameter will also change the value -of the corresponding property on the `arguments` object, and the other way around. - - function foo(a, b, c) { - arguments[0] = 2; - a; // 2 - - b = 4; - arguments[1]; // 4 - - var d = c; - d = 9; - c; // 3 - } - foo(1, 2, 3); - -### Performance Myths and Truths - -The only time the `arguments` object is not created is where it is declared as -a name inside of a function or one of its formal parameters. It does not matter -whether it is used or not. - -Both *getters* and *setters* are **always** created; thus, using it has nearly -no performance impact at all, especially not in real world code where there is -more than a simple access to the `arguments` object's properties. - -> **ES5 Note:** These *getters* and *setters* are not created in strict mode. - -However, there is one case which will drastically reduce the performance in -modern JavaScript engines. That case is the use of `arguments.callee`. - - function foo() { - arguments.callee; // do something with this function object - arguments.callee.caller; // and the calling function object - } - - function bigLoop() { - for(var i = 0; i < 100000; i++) { - foo(); // Would normally be inlined... - } - } - -In the above code, `foo` can no longer be a subject to [inlining][1] since it -needs to know about both itself and its caller. This not only defeats possible -performance gains that would arise from inlining, but it also breaks encapsulation -because the function may now be dependent on a specific calling context. - -Making use of `arguments.callee` or any of its properties is **highly discouraged**. - -> **ES5 Note:** In strict mode, `arguments.callee` will throw a `TypeError` since -> its use has been deprecated. - -[1]: http://en.wikipedia.org/wiki/Inlining - - diff --git a/doc/zh(Trandition)/array/constructor.md b/doc/zh-TW/array/constructor.md similarity index 100% rename from doc/zh(Trandition)/array/constructor.md rename to doc/zh-TW/array/constructor.md diff --git a/doc/zh(Trandition)/array/general.md b/doc/zh-TW/array/general.md similarity index 100% rename from doc/zh(Trandition)/array/general.md rename to doc/zh-TW/array/general.md diff --git a/doc/zh(Trandition)/core/delete.md b/doc/zh-TW/core/delete.md similarity index 100% rename from doc/zh(Trandition)/core/delete.md rename to doc/zh-TW/core/delete.md diff --git a/doc/zh(Trandition)/core/eval.md b/doc/zh-TW/core/eval.md similarity index 100% rename from doc/zh(Trandition)/core/eval.md rename to doc/zh-TW/core/eval.md diff --git a/doc/zh(Trandition)/core/semicolon.md b/doc/zh-TW/core/semicolon.md similarity index 100% rename from doc/zh(Trandition)/core/semicolon.md rename to doc/zh-TW/core/semicolon.md diff --git a/doc/zh-TW/core/undefined.md b/doc/zh-TW/core/undefined.md new file mode 100644 index 00000000..4c9378be --- /dev/null +++ b/doc/zh-TW/core/undefined.md @@ -0,0 +1,55 @@ +## `undefined` 和 `null` + +JavaScript 中有兩個表示空值的方式, `null` 和 `undefined` , `undefined`式比較常用的一種。 + +### `undefined` 的值 + +`undefined` 是一個值為 `undefined` 的類型。 + +語言中也定義了一個全域變數,它的值為 `undefined`,這個變數的被稱作 `undefined` 。 +這個變數 **不是** 一個常數,也不是一個關鍵字。這表示它的值可以被輕易的覆蓋。 + +> **ES5 提示: ** `undefined` 在 ECMAScript 5 裡 **不再是** *可寫* 的 +> 但是它的名稱還是可以被隱藏,比如說定義一個函數為 `undefined`。 + +這裡有一些例子會回傳 `undefined` 的值: + + - 進入尚未修改的全域變數 `undefined`。 + - 進入一個宣告但 **尚未** 初始化的變數。 + - `return` 表示式中沒有返回任何內容。 + - 呼叫不存在的屬性。 + - 函式參數沒有被傳遞數值。 + - 任何被被設定為 `undefined` 的變數。 + - 任何表達式中形式為 `void(expression)` + +### 處理 `undefined` 值的改變 + +由於全域變數 `undefined` 只有保存 `undefined` 類型實際值的一個副本,指定了一個新的值並 **不會** 改變 `undefined`類型裡面的值。 + +為了避免去改變 `undefined` 的值,常用的技巧就是加上一個新的變數到 [匿名包裝器](#function.scopes)。在使用的時候,這個參數不會接受任何的值。 + + var undefined = 123; + (function(something, foo, undefined) { + // undefined 在區域區間內得到了 `undefined` 的值 + + })('Hello World', 42); + +另外一個可以得到同樣的效果就是在內部宣告一個變數 + + var undefined = 123; + (function(something, foo) { + var undefined; + ... + + })('Hello World', 42); + +唯一的不同就是在下者會多 4 個多 bytes 用來壓縮檔案,而且函數內野沒有其他需要使用 `var` + +### 使用 `null` + +JavaScript 中所使用的 `undefined` 類似別的語言中的 *null* , 但實際上在 JavaScript 中的 `null` 算是另外一個類型。 + +它在 JavaScript 有些可以使用的地方 (例如說宣告一個原型的終結,例如 `Foo.prototype = null` )。 +但是在大部分的時候可以用 `undefined`,來取代。 + + diff --git a/doc/zh-TW/function/arguments.md b/doc/zh-TW/function/arguments.md new file mode 100644 index 00000000..428a575d --- /dev/null +++ b/doc/zh-TW/function/arguments.md @@ -0,0 +1,103 @@ +## `arguments` 物件 + +所有函數在 JavaScript 中都可以有個特別的參數 `arguments`。 +這個變數掌握了一列傳入函數中的參數 + +> **注意:** 由於 `arguments` 都已經在函數中被定義了 +> 經過 `var` 定義或是用 `arguments` 宣告參數 +> `arguments` 物件都不會被建立 + +`arguments` 物件 **不是** 一個 `Array`,雖然都有很多 Array 的語法 - 就像是 `length` 屬性 - 但是它沒有繼承來自 `Array.prototype` 事實上它繼承 `object`。 + +由於這些原因,這 **不可能** 用 Array 的一些功能像是 `push`、`pop`或是 `slice` 在 `arguments`。 +但是像 `for` 迴圈這些迴圈都是可以用的,如果真的需要使用一些標準的 `Array` 功能可以先把它轉成真的 `Array` 再去使用。 + +### 轉為 Array + +下面的程式可以回傳一個新的 `Array` 包含所有的元素在 `Arguments`的物件中 + + Array.prototype.slice.call(arguments); + +這種轉化方式比較 **慢** ,不建議使用這種作法如果再追求效率的程式中。 + + +### 傳遞參數 + +下面是建議用這種方式去傳參數到另一個函數 + + function foo() { + bar.apply(null, arguments); + } + function bar(a, b, c) { + // 在這裡做一些事情 + } + +另一個技巧是用 `call` 和 `apply` 放在一起來創造一個更快的解綁定包裝器 + + function Foo() {} + + Foo.prototype.method = function(a, b, c) { + console.log(this, a, b, c); + }; + + // Create an unbound version of "method" + // 輸入的參數: this, arg1, arg2...argN + Foo.method = function() { + + // 結果: Foo.prototype.method.call(this, arg1, arg2... argN) + Function.call.apply(Foo.prototype.method, arguments); + }; + + +### 自動更新 + +在 `Arguments` 物件創造的 *getter* 和 *setter* 的函數方法,可以被視為原本函數的變數。 + +因此,改變了一個變數會跟著改變它的值而且也間接的改變稻香對應的 `arguments` 的物件,反之亦然。 + + function foo(a, b, c) { + arguments[0] = 2; + a; // 2 + + b = 4; + arguments[1]; // 4 + + var d = c; + d = 9; + c; // 3 + } + foo(1, 2, 3); + +### 性能 + +`arguments` 總是會被宣告,但除了兩個情況,一個是在一個函式中或是在其中一個參入。而不論他是否有被使用。 + +*getters* 和 *setter* 會永遠被創造。然而,他們對任何性能都沒有影響,除非對它的屬性有多次的訪問 + + +> **ES5 提示:** 那些 *getters* 和 *setters* 在嚴格的模式像不會被建立 + +然而會有一種情況來降低 JavaScript 引擎的效能。就是使用 `arguments.callee`。 + + function foo() { + arguments.callee; // 做一些在這個函數物件 + arguments.callee.caller; // 然後呼叫這個函數物件 + } + + function bigLoop() { + for(var i = 0; i < 100000; i++) { + foo(); // 通常會在內聯 + } + } + +在上面的程式中, `foo` 不再是一個單存的互聯函數 +因為它需要知道他自己和它的調用者。 +這不僅減低了它的性能,而且還破壞的封裝 + +**強烈建議不要使用** `arguments.callee` 或是其他它的屬性 + +> **ES5 Note:** 在嚴格的模式下 `arguments.callee` 會丟出一個 `TypeError`, 因為這種方法已經被廢除了 + +[1]: http://en.wikipedia.org/wiki/Inlining + + diff --git a/doc/zh(Trandition)/function/closures.md b/doc/zh-TW/function/closures.md similarity index 100% rename from doc/zh(Trandition)/function/closures.md rename to doc/zh-TW/function/closures.md diff --git a/doc/zh(Trandition)/function/constructors.md b/doc/zh-TW/function/constructors.md similarity index 100% rename from doc/zh(Trandition)/function/constructors.md rename to doc/zh-TW/function/constructors.md diff --git a/doc/zh(Trandition)/function/general.md b/doc/zh-TW/function/general.md similarity index 100% rename from doc/zh(Trandition)/function/general.md rename to doc/zh-TW/function/general.md diff --git a/doc/zh(Trandition)/function/scopes.md b/doc/zh-TW/function/scopes.md similarity index 100% rename from doc/zh(Trandition)/function/scopes.md rename to doc/zh-TW/function/scopes.md diff --git a/doc/zh(Trandition)/function/this.md b/doc/zh-TW/function/this.md similarity index 100% rename from doc/zh(Trandition)/function/this.md rename to doc/zh-TW/function/this.md diff --git a/doc/zh(Trandition)/index.json b/doc/zh-TW/index.json similarity index 100% rename from doc/zh(Trandition)/index.json rename to doc/zh-TW/index.json diff --git a/doc/zh(Trandition)/intro/index.md b/doc/zh-TW/intro/index.md similarity index 100% rename from doc/zh(Trandition)/intro/index.md rename to doc/zh-TW/intro/index.md diff --git a/doc/zh(Trandition)/object/forinloop.md b/doc/zh-TW/object/forinloop.md similarity index 100% rename from doc/zh(Trandition)/object/forinloop.md rename to doc/zh-TW/object/forinloop.md diff --git a/doc/zh(Trandition)/object/general.md b/doc/zh-TW/object/general.md similarity index 100% rename from doc/zh(Trandition)/object/general.md rename to doc/zh-TW/object/general.md diff --git a/doc/zh(Trandition)/object/hasownproperty.md b/doc/zh-TW/object/hasownproperty.md similarity index 100% rename from doc/zh(Trandition)/object/hasownproperty.md rename to doc/zh-TW/object/hasownproperty.md diff --git a/doc/zh(Trandition)/object/prototype.md b/doc/zh-TW/object/prototype.md similarity index 100% rename from doc/zh(Trandition)/object/prototype.md rename to doc/zh-TW/object/prototype.md diff --git a/doc/zh(Trandition)/other/timeouts.md b/doc/zh-TW/other/timeouts.md similarity index 100% rename from doc/zh(Trandition)/other/timeouts.md rename to doc/zh-TW/other/timeouts.md diff --git a/doc/zh(Trandition)/types/casting.md b/doc/zh-TW/types/casting.md similarity index 100% rename from doc/zh(Trandition)/types/casting.md rename to doc/zh-TW/types/casting.md diff --git a/doc/zh(Trandition)/types/equality.md b/doc/zh-TW/types/equality.md similarity index 100% rename from doc/zh(Trandition)/types/equality.md rename to doc/zh-TW/types/equality.md diff --git a/doc/zh(Trandition)/types/instanceof.md b/doc/zh-TW/types/instanceof.md similarity index 100% rename from doc/zh(Trandition)/types/instanceof.md rename to doc/zh-TW/types/instanceof.md diff --git a/doc/zh(Trandition)/types/typeof.md b/doc/zh-TW/types/typeof.md similarity index 100% rename from doc/zh(Trandition)/types/typeof.md rename to doc/zh-TW/types/typeof.md diff --git a/site/zh-TW/index.html b/site/zh-TW/index.html new file mode 100644 index 00000000..8ae0e924 --- /dev/null +++ b/site/zh-TW/index.html @@ -0,0 +1,1913 @@ +JavaScript Garden +

Intro

JavaScript Garden is a growing collection of documentation about the most +quirky parts of the JavaScript programming language. It gives advice to +avoid common mistakes and subtle bugs, as well as performance issues and bad +practices, that non-expert JavaScript programmers may encounter on their +endeavours into the depths of the language.

+ +

JavaScript Garden does not aim to teach you JavaScript. Former knowledge +of the language is strongly recommended in order to understand the topics covered +in this guide. In order to learn the basics of the language, please head over to +the excellent guide on the Mozilla Developer Network.

+ +

The Authors

+ +

This guide is the work of two lovely Stack Overflow users, Ivo Wetzel +(Writing) and Zhang Yi Jiang (Design).

+ +

Contributors

+ + + +

Hosting

+ +

JavaScript Garden is hosted on GitHub, but Cramer Development supports us +with a mirror at JavaScriptGarden.info.

+ +

License

+ +

JavaScript Garden is published under the MIT license and hosted on +GitHub. If you find errors or typos please file an issue or a pull +request on the repository. You can also find us in the JavaScript room on +Stack Overflow chat.

Objects

Object Usage and Properties

Everything in JavaScript acts like an object, with the only two exceptions being +null and undefined.

+ +
false.toString(); // 'false'
+[1, 2, 3].toString(); // '1,2,3'
+
+function Foo(){}
+Foo.bar = 1;
+Foo.bar; // 1
+
+ +

A common misconception is that number literals cannot be used as +objects. That is because a flaw in JavaScript's parser tries to parse the dot +notation on a number as a floating point literal.

+ +
2.toString(); // raises SyntaxError
+
+ +

There are a couple of workarounds that can be used to make number literals act +as objects too.

+ +
2..toString(); // the second point is correctly recognized
+2 .toString(); // note the space left to the dot
+(2).toString(); // 2 is evaluated first
+
+ +

Objects as a Data Type

+ +

Objects in JavaScript can also be used as Hashmaps; they mainly consist +of named properties mapping to values.

+ +

Using an object literal - {} notation - it is possible to create a +plain object. This new object inherits from Object.prototype and +does not have own properties defined.

+ +
var foo = {}; // a new empty object
+
+// a new object with a 'test' property with value 12
+var bar = {test: 12}; 
+
+ +

Accessing Properties

+ +

The properties of an object can be accessed in two ways, via either the dot +notation or the square bracket notation.

+ +
var foo = {name: 'kitten'}
+foo.name; // kitten
+foo['name']; // kitten
+
+var get = 'name';
+foo[get]; // kitten
+
+foo.1234; // SyntaxError
+foo['1234']; // works
+
+ +

The notations work almost identically, with the only difference being that the +square bracket notation allows for dynamic setting of properties and +the use of property names that would otherwise lead to a syntax error.

+ +

Deleting Properties

+ +

The only way to remove a property from an object is to use the delete +operator; setting the property to undefined or null only removes the +value associated with the property, but not the key.

+ +
var obj = {
+    bar: 1,
+    foo: 2,
+    baz: 3
+};
+obj.bar = undefined;
+obj.foo = null;
+delete obj.baz;
+
+for(var i in obj) {
+    if (obj.hasOwnProperty(i)) {
+        console.log(i, '' + obj[i]);
+    }
+}
+
+ +

The above outputs both bar undefined and foo null - only baz was +removed and is therefore missing from the output.

+ +

Notation of Keys

+ +
var test = {
+    'case': 'I am a keyword, so I must be notated as a string',
+    delete: 'I am a keyword, so me too' // raises SyntaxError
+};
+
+ +

Object properties can be both notated as plain characters and as strings. Due to +another mis-design in JavaScript's parser, the above will throw +a SyntaxError prior to ECMAScript 5.

+ +

This error arises from the fact that delete is a keyword; therefore, it must be +notated as a string literal to ensure that it will be correctly interpreted by +older JavaScript engines.

The Prototype

JavaScript does not feature a classical inheritance model; instead, it uses a +prototypal one.

+ +

While this is often considered to be one of JavaScript's weaknesses, the +prototypal inheritance model is in fact more powerful than the classic model. +It is, for example, fairly trivial to build a classic model on top of a +prototypal model, while the other way around is a far more difficult task.

+ +

JavaScript is the only widely used language that features prototypal +inheritance, so it can take time to adjust to the differences between the two +models.

+ +

The first major difference is that inheritance in JavaScript uses prototype +chains.

+ + + +
function Foo() {
+    this.value = 42;
+}
+Foo.prototype = {
+    method: function() {}
+};
+
+function Bar() {}
+
+// Set Bar's prototype to a new instance of Foo
+Bar.prototype = new Foo();
+Bar.prototype.foo = 'Hello World';
+
+// Make sure to list Bar as the actual constructor
+Bar.prototype.constructor = Bar;
+
+var test = new Bar() // create a new bar instance
+
+// The resulting prototype chain
+test [instance of Bar]
+    Bar.prototype [instance of Foo] 
+        { foo: 'Hello World' }
+        Foo.prototype
+            { method: ... }
+            Object.prototype
+                { toString: ... /* etc. */ }
+
+ +

In the code above, the object test will inherit from both Bar.prototype and +Foo.prototype; hence, it will have access to the function method that was +defined on Foo. It will also have access to the property value of the +one Foo instance that is its prototype. It is important to note that new +Bar() does not create a new Foo instance, but reuses the one assigned to +its prototype; thus, all Bar instances will share the same value property.

+ + + +

Property Lookup

+ +

When accessing the properties of an object, JavaScript will traverse the +prototype chain upwards until it finds a property with the requested name.

+ +

If it reaches the top of the chain - namely Object.prototype - and still +hasn't found the specified property, it will return the value +undefined instead.

+ +

The Prototype Property

+ +

While the prototype property is used by the language to build the prototype +chains, it is still possible to assign any given value to it. However, +primitives will simply get ignored when assigned as a prototype.

+ +
function Foo() {}
+Foo.prototype = 1; // no effect
+
+ +

Assigning objects, as shown in the example above, will work, and allows for dynamic +creation of prototype chains.

+ +

Performance

+ +

The lookup time for properties that are high up on the prototype chain can have +a negative impact on performance, and this may be significant in code where +performance is critical. Additionally, trying to access non-existent properties +will always traverse the full prototype chain.

+ +

Also, when iterating over the properties of an object +every property that is on the prototype chain will be enumerated.

+ +

Extension of Native Prototypes

+ +

One mis-feature that is often used is to extend Object.prototype or one of the +other built in prototypes.

+ +

This technique is called monkey patching and breaks encapsulation. While +used by popular frameworks such as Prototype, there is still no good +reason for cluttering built-in types with additional non-standard functionality.

+ +

The only good reason for extending a built-in prototype is to backport +the features of newer JavaScript engines; for example, +Array.forEach.

+ +

In Conclusion

+ +

It is essential to understand the prototypal inheritance model before +writing complex code that makes use of it. Also, be aware of the length of the +prototype chains in your code and break them up if necessary to avoid possible +performance problems. Further, the native prototypes should never be +extended unless it is for the sake of compatibility with newer JavaScript +features.

hasOwnProperty

To check whether an object has a property defined on itself and not somewhere +on its prototype chain, it is necessary to use the +hasOwnProperty method which all objects inherit from Object.prototype.

+ + + +

hasOwnProperty is the only thing in JavaScript which deals with properties and +does not traverse the prototype chain.

+ +
// Poisoning Object.prototype
+Object.prototype.bar = 1; 
+var foo = {goo: undefined};
+
+foo.bar; // 1
+'bar' in foo; // true
+
+foo.hasOwnProperty('bar'); // false
+foo.hasOwnProperty('goo'); // true
+
+ +

Only hasOwnProperty will give the correct and expected result; this is +essential when iterating over the properties of any object. There is no other +way to exclude properties that are not defined on the object itself, but +somewhere on its prototype chain.

+ +

hasOwnProperty as a Property

+ +

JavaScript does not protect the property name hasOwnProperty; thus, if the +possibility exists that an object might have a property with this name, it is +necessary to use an external hasOwnProperty to get correct results.

+ +
var foo = {
+    hasOwnProperty: function() {
+        return false;
+    },
+    bar: 'Here be dragons'
+};
+
+foo.hasOwnProperty('bar'); // always returns false
+
+// Use another Object's hasOwnProperty and call it with 'this' set to foo
+({}).hasOwnProperty.call(foo, 'bar'); // true
+
+// It's also possible to use the hasOwnProperty property from the Object property for this purpose
+Object.prototype.hasOwnProperty.call(obj, 'bar'); // true
+
+ +

In Conclusion

+ +

Using hasOwnProperty is the only reliable method to check for the +existence of a property on an object. It is recommended that hasOwnProperty +is used in every for in loop to avoid errors from +extended native prototypes.

The for in Loop

Just like the in operator, the for in loop traverses the prototype +chain when iterating over the properties of an object.

+ + + +
// Poisoning Object.prototype
+Object.prototype.bar = 1;
+
+var foo = {moo: 2};
+for(var i in foo) {
+    console.log(i); // prints both bar and moo
+}
+
+ +

Since it is not possible to change the behavior of the for in loop itself, it +is necessary to filter out the unwanted properties inside the loop body; +this is done using the hasOwnProperty method of +Object.prototype.

+ + + +

Using hasOwnProperty for Filtering

+ +
// still the foo from above
+for(var i in foo) {
+    if (foo.hasOwnProperty(i)) {
+        console.log(i);
+    }
+}
+
+ +

This version is the only correct one to use. Due to the use of hasOwnProperty, it +will only print out moo. When hasOwnProperty is left out, the code is +prone to errors in cases where the native prototypes - e.g. Object.prototype - +have been extended.

+ +

One widely used framework that extends Object.prototype is Prototype. +When this framework is included, for in loops that do not use +hasOwnProperty are guaranteed to break.

+ +

In Conclusion

+ +

It is recommended to always use hasOwnProperty. Assumptions should never +be made about the environment the code is running in, or whether the native +prototypes have been extended or not.

Functions

Function Declarations and Expressions

Functions in JavaScript are first class objects. That means they can be +passed around like any other value. One common use of this feature is to pass +an anonymous function as a callback to another, possibly an asynchronous function.

+ +

The function Declaration

+ +
function foo() {}
+
+ +

The above function gets hoisted before the execution of the +program starts; thus, it is available everywhere in the scope it was +defined, even if called before the actual definition in the source.

+ +
foo(); // Works because foo was created before this code runs
+function foo() {}
+
+ +

The function Expression

+ +
var foo = function() {};
+
+ +

This example assigns the unnamed and anonymous function to the variable foo.

+ +
foo; // 'undefined'
+foo(); // this raises a TypeError
+var foo = function() {};
+
+ +

Due to the fact that var is a declaration that hoists the variable name foo +before the actual execution of the code starts, foo is already defined when +the script gets executed.

+ +

But since assignments only happen at runtime, the value of foo will default +to undefined before the corresponding code is executed.

+ +

Named Function Expression

+ +

Another special case is the assignment of named functions.

+ +
var foo = function bar() {
+    bar(); // Works
+}
+bar(); // ReferenceError
+
+ +

Here, bar is not available in the outer scope, since the function only gets +assigned to foo; however, inside of bar, it is available. This is due to +how name resolution in JavaScript works, the name of the +function is always made available in the local scope of the function itself.

How this Works

JavaScript has a different concept of what the special name this refers to +than most other programming languages. There are exactly five different +ways in which the value of this can be bound in the language.

+ +

The Global Scope

+ +
this;
+
+ +

When using this in global scope, it will simply refer to the global object.

+ +

Calling a Function

+ +
foo();
+
+ +

Here, this will again refer to the global object.

+ + + +

Calling a Method

+ +
test.foo(); 
+
+ +

In this example, this will refer to test.

+ +

Calling a Constructor

+ +
new foo(); 
+
+ +

A function call that is preceded by the new keyword acts as +a constructor. Inside the function, this will refer +to a newly created Object.

+ +

Explicit Setting of this

+ +
function foo(a, b, c) {}
+
+var bar = {};
+foo.apply(bar, [1, 2, 3]); // array will expand to the below
+foo.call(bar, 1, 2, 3); // results in a = 1, b = 2, c = 3
+
+ +

When using the call or apply methods of Function.prototype, the value of +this inside the called function gets explicitly set to the first argument +of the corresponding function call.

+ +

As a result, in the above example the method case does not apply, and this +inside of foo will be set to bar.

+ + + +

Common Pitfalls

+ +

While most of these cases make sense, the first can be considered another +mis-design of the language because it never has any practical use.

+ +
Foo.method = function() {
+    function test() {
+        // this is set to the global object
+    }
+    test();
+}
+
+ +

A common misconception is that this inside of test refers to Foo; while in +fact, it does not.

+ +

In order to gain access to Foo from within test, it is necessary to create a +local variable inside of method that refers to Foo.

+ +
Foo.method = function() {
+    var that = this;
+    function test() {
+        // Use that instead of this here
+    }
+    test();
+}
+
+ +

that is just a normal variable name, but it is commonly used for the reference to an +outer this. In combination with closures, it can also +be used to pass this values around.

+ +

Assigning Methods

+ +

Another thing that does not work in JavaScript is function aliasing, which is +assigning a method to a variable.

+ +
var test = someObject.methodTest;
+test();
+
+ +

Due to the first case, test now acts like a plain function call; therefore, +this inside it will no longer refer to someObject.

+ +

While the late binding of this might seem like a bad idea at first, in +fact, it is what makes prototypal inheritance work.

+ +
function Foo() {}
+Foo.prototype.method = function() {};
+
+function Bar() {}
+Bar.prototype = Foo.prototype;
+
+new Bar().method();
+
+ +

When method gets called on an instance of Bar, this will now refer to that +very instance.

Closures and References

One of JavaScript's most powerful features is the availability of closures. +With closures, scopes always keep access to the outer scope, in which they +were defined. Since the only scoping that JavaScript has is +function scope, all functions, by default, act as closures.

+ +

Emulating private variables

+ +
function Counter(start) {
+    var count = start;
+    return {
+        increment: function() {
+            count++;
+        },
+
+        get: function() {
+            return count;
+        }
+    }
+}
+
+var foo = Counter(4);
+foo.increment();
+foo.get(); // 5
+
+ +

Here, Counter returns two closures: the function increment as well as +the function get. Both of these functions keep a reference to the scope of +Counter and, therefore, always keep access to the count variable that was +defined in that scope.

+ +

Why Private Variables Work

+ +

Since it is not possible to reference or assign scopes in JavaScript, there is +no way of accessing the variable count from the outside. The only way to +interact with it is via the two closures.

+ +
var foo = new Counter(4);
+foo.hack = function() {
+    count = 1337;
+};
+
+ +

The above code will not change the variable count in the scope of Counter, +since foo.hack was not defined in that scope. It will instead create - or +override - the global variable count.

+ +

Closures Inside Loops

+ +

One often made mistake is to use closures inside of loops, as if they were +copying the value of the loop's index variable.

+ +
for(var i = 0; i < 10; i++) {
+    setTimeout(function() {
+        console.log(i);  
+    }, 1000);
+}
+
+ +

The above will not output the numbers 0 through 9, but will simply print +the number 10 ten times.

+ +

The anonymous function keeps a reference to i. At the time +console.log gets called, the for loop has already finished, and the value of +i as been set to 10.

+ +

In order to get the desired behavior, it is necessary to create a copy of +the value of i.

+ +

Avoiding the Reference Problem

+ +

In order to copy the value of the loop's index variable, it is best to use an +anonymous wrapper.

+ +
for(var i = 0; i < 10; i++) {
+    (function(e) {
+        setTimeout(function() {
+            console.log(e);  
+        }, 1000);
+    })(i);
+}
+
+ +

The anonymous outer function gets called immediately with i as its first +argument and will receive a copy of the value of i as its parameter e.

+ +

The anonymous function that gets passed to setTimeout now has a reference to +e, whose value does not get changed by the loop.

+ +

There is another possible way of achieving this, which is to return a function +from the anonymous wrapper that will then have the same behavior as the code +above.

+ +
for(var i = 0; i < 10; i++) {
+    setTimeout((function(e) {
+        return function() {
+            console.log(e);
+        }
+    })(i), 1000)
+}
+

arguments 物件

所有函數在 JavaScript 中都可以有個特別的參數 arguments。 +這個變數掌握了一列傳入函數中的參數

+ + + +

arguments 物件 不是 一個 Array,雖然都有很多 Array 的語法 - 就像是 length 屬性 - 但是它沒有繼承來自 Array.prototype 事實上它繼承 object

+ +

由於這些原因,這 不可能 用 Array 的一些功能像是 pushpop或是 slicearguments。 +但是像 for 迴圈這些迴圈都是可以用的,如果真的需要使用一些標準的 Array 功能可以先把它轉成真的 Array 再去使用。

+ +

轉為 Array

+ +

下面的程式可以回傳一個新的 Array 包含所有的元素在 Arguments的物件中

+ +
Array.prototype.slice.call(arguments);
+
+ +

這種轉化方式比較 ,不建議使用這種作法如果再追求效率的程式中。

+ +

傳遞參數

+ +

下面是建議用這種方式去傳參數到另一個函數

+ +
function foo() {
+    bar.apply(null, arguments);
+}
+function bar(a, b, c) {
+    // 在這裡做一些事情
+}
+
+ +

另一個技巧是用 callapply 放在一起來創造一個更快的解綁定包裝器

+ +
function Foo() {}
+
+Foo.prototype.method = function(a, b, c) {
+    console.log(this, a, b, c);
+};
+
+// Create an unbound version of "method" 
+// 輸入的參數: this, arg1, arg2...argN
+Foo.method = function() {
+
+    // 結果: Foo.prototype.method.call(this, arg1, arg2... argN)
+    Function.call.apply(Foo.prototype.method, arguments);
+};
+
+ +

自動更新

+ +

Arguments 物件創造的 gettersetter 的函數方法,可以被視為原本函數的變數。

+ +

因此,改變了一個變數會跟著改變它的值而且也間接的改變稻香對應的 arguments 的物件,反之亦然。

+ +
function foo(a, b, c) {
+    arguments[0] = 2;
+    a; // 2
+
+    b = 4;
+    arguments[1]; // 4
+
+    var d = c;
+    d = 9;
+    c; // 3
+}
+foo(1, 2, 3);
+
+ +

性能

+ +

arguments 總是會被宣告,但除了兩個情況,一個是在一個函式中或是在其中一個參入。而不論他是否有被使用。

+ +

getterssetter 會永遠被創造。然而,他們對任何性能都沒有影響,除非對它的屬性有多次的訪問

+ + + +

然而會有一種情況來降低 JavaScript 引擎的效能。就是使用 arguments.callee

+ +
function foo() {
+    arguments.callee; // 做一些在這個函數物件
+    arguments.callee.caller; // 然後呼叫這個函數物件
+}
+
+function bigLoop() {
+    for(var i = 0; i < 100000; i++) {
+        foo(); // 通常會在內聯
+    }
+}
+
+ +

在上面的程式中, foo 不再是一個單存的互聯函數 +因為它需要知道他自己和它的調用者。 +這不僅減低了它的性能,而且還破壞的封裝

+ +

強烈建議不要使用 arguments.callee 或是其他它的屬性

+ +

Constructors

Constructors in JavaScript are yet again different from many other languages. Any +function call that is preceded by the new keyword acts as a constructor.

+ +

Inside the constructor - the called function - the value of this refers to a +newly created object. The prototype of this new +object is set to the prototype of the function object that was invoked as the +constructor.

+ +

If the function that was called has no explicit return statement, then it +implicitly returns the value of this - the new object.

+ +
function Foo() {
+    this.bla = 1;
+}
+
+Foo.prototype.test = function() {
+    console.log(this.bla);
+};
+
+var test = new Foo();
+
+ +

The above calls Foo as constructor and sets the prototype of the newly +created object to Foo.prototype.

+ +

In case of an explicit return statement, the function returns the value +specified by that statement, but only if the return value is an Object.

+ +
function Bar() {
+    return 2;
+}
+new Bar(); // a new object
+
+function Test() {
+    this.value = 2;
+
+    return {
+        foo: 1
+    };
+}
+new Test(); // the returned object
+
+ +

When the new keyword is omitted, the function will not return a new object.

+ +
function Foo() {
+    this.bla = 1; // gets set on the global object
+}
+Foo(); // undefined
+
+ +

While the above example might still appear to work in some cases, due to the +workings of this in JavaScript, it will use the +global object as the value of this.

+ +

Factories

+ +

In order to be able to omit the new keyword, the constructor function has to +explicitly return a value.

+ +
function Bar() {
+    var value = 1;
+    return {
+        method: function() {
+            return value;
+        }
+    }
+}
+Bar.prototype = {
+    foo: function() {}
+};
+
+new Bar();
+Bar();
+
+ +

Both calls to Bar return the same thing, a newly create object that +has a property called method, which is a +Closure.

+ +

It should also be noted that the call new Bar() does not affect the +prototype of the returned object. While the prototype will be set on the newly +created object, Bar never returns that new object.

+ +

In the above example, there is no functional difference between using and +not using the new keyword.

+ +

Creating New Objects via Factories

+ +

It is often recommended to not use new because forgetting its use may +lead to bugs.

+ +

In order to create a new object, one should rather use a factory and construct a +new object inside of that factory.

+ +
function Foo() {
+    var obj = {};
+    obj.value = 'blub';
+
+    var private = 2;
+    obj.someMethod = function(value) {
+        this.value = value;
+    }
+
+    obj.getPrivate = function() {
+        return private;
+    }
+    return obj;
+}
+
+ +

While the above is robust against a missing new keyword and certainly makes +the use of private variables easier, it comes with some +downsides.

+ +
    +
  1. It uses more memory since the created objects do not share the methods +on a prototype.
  2. +
  3. In order to inherit, the factory needs to copy all the methods from another +object or put that object on the prototype of the new object.
  4. +
  5. Dropping the prototype chain just because of a left out new keyword +is contrary to the spirit of the language.
  6. +
+ +

In Conclusion

+ +

While omitting the new keyword might lead to bugs, it is certainly not a +reason to drop the use of prototypes altogether. In the end it comes down to +which solution is better suited for the needs of the application. It is +especially important to choose a specific style of object creation and use it +consistently.

Scopes and Namespaces

Although JavaScript deals fine with the syntax of two matching curly +braces for blocks, it does not support block scope; hence, all that is left +in the language is function scope.

+ +
function test() { // a scope
+    for(var i = 0; i < 10; i++) { // not a scope
+        // count
+    }
+    console.log(i); // 10
+}
+
+ + + +

There are also no distinct namespaces in JavaScript, which means that everything +gets defined in one globally shared namespace.

+ +

Each time a variable is referenced, JavaScript will traverse upwards through all +the scopes until it finds it. In the case that it reaches the global scope and +still has not found the requested name, it will raise a ReferenceError.

+ +

The Bane of Global Variables

+ +
// script A
+foo = '42';
+
+// script B
+var foo = '42'
+
+ +

The above two scripts do not have the same effect. Script A defines a +variable called foo in the global scope, and script B defines a foo in the +current scope.

+ +

Again, that is not at all the same effect: not using var can have major +implications.

+ +
// global scope
+var foo = 42;
+function test() {
+    // local scope
+    foo = 21;
+}
+test();
+foo; // 21
+
+ +

Leaving out the var statement inside the function test will override the +value of foo. While this might not seem like a big deal at first, having +thousands of lines of JavaScript and not using var will introduce horrible, +hard-to-track-down bugs.

+ +
// global scope
+var items = [/* some list */];
+for(var i = 0; i < 10; i++) {
+    subLoop();
+}
+
+function subLoop() {
+    // scope of subLoop
+    for(i = 0; i < 10; i++) { // missing var statement
+        // do amazing stuff!
+    }
+}
+
+ +

The outer loop will terminate after the first call to subLoop, since subLoop +overwrites the global value of i. Using a var for the second for loop would +have easily avoided this error. The var statement should never be left out +unless the desired effect is to affect the outer scope.

+ +

Local Variables

+ +

The only source for local variables in JavaScript are +function parameters and variables declared via the +var statement.

+ +
// global scope
+var foo = 1;
+var bar = 2;
+var i = 2;
+
+function test(i) {
+    // local scope of the function test
+    i = 5;
+
+    var foo = 3;
+    bar = 4;
+}
+test(10);
+
+ +

While foo and i are local variables inside the scope of the function test, +the assignment of bar will override the global variable with the same name.

+ +

Hoisting

+ +

JavaScript hoists declarations. This means that both var statements and +function declarations will be moved to the top of their enclosing scope.

+ +
bar();
+var bar = function() {};
+var someValue = 42;
+
+test();
+function test(data) {
+    if (false) {
+        goo = 1;
+
+    } else {
+        var goo = 2;
+    }
+    for(var i = 0; i < 100; i++) {
+        var e = data[i];
+    }
+}
+
+ +

The above code gets transformed before execution starts. JavaScript moves +the var statements, as well as function declarations, to the top of the +nearest surrounding scope.

+ +
// var statements got moved here
+var bar, someValue; // default to 'undefined'
+
+// the function declaration got moved up too
+function test(data) {
+    var goo, i, e; // missing block scope moves these here
+    if (false) {
+        goo = 1;
+
+    } else {
+        goo = 2;
+    }
+    for(i = 0; i < 100; i++) {
+        e = data[i];
+    }
+}
+
+bar(); // fails with a TypeError since bar is still 'undefined'
+someValue = 42; // assignments are not affected by hoisting
+bar = function() {};
+
+test();
+
+ +

Missing block scoping will not only move var statements out of loops and +their bodies, it will also make the results of certain if constructs +non-intuitive.

+ +

In the original code, although the if statement seemed to modify the global +variable goo, it actually modifies the local variable - after hoisting +has been applied.

+ +

Without knowledge of hoisting, one might suspect the code below would raise a +ReferenceError.

+ +
// check whether SomeImportantThing has been initialized
+if (!SomeImportantThing) {
+    var SomeImportantThing = {};
+}
+
+ +

But of course, this works due to the fact that the var statement is being +moved to the top of the global scope.

+ +
var SomeImportantThing;
+
+// other code might initialize SomeImportantThing here, or not
+
+// make sure it's there
+if (!SomeImportantThing) {
+    SomeImportantThing = {};
+}
+
+ +

Name Resolution Order

+ +

All scopes in JavaScript, including the global scope, have the special name +this, defined in them, which refers to the current object.

+ +

Function scopes also have the name arguments, defined in +them, which contains the arguments that were passed to the function.

+ +

For example, when trying to access a variable named foo inside the scope of a +function, JavaScript will look up the name in the following order:

+ +
    +
  1. In case there is a var foo statement in the current scope, use that.
  2. +
  3. If one of the function parameters is named foo, use that.
  4. +
  5. If the function itself is called foo, use that.
  6. +
  7. Go to the next outer scope, and start with #1 again.
  8. +
+ + + +

Namespaces

+ +

A common problem associated with having only one global namespace is the +likelihood of running into problems where variable names clash. In JavaScript, +this problem can easily be avoided with the help of anonymous wrappers.

+ +
(function() {
+    // a self contained "namespace"
+
+    window.foo = function() {
+        // an exposed closure
+    };
+
+})(); // execute the function immediately
+
+ +

Unnamed functions are considered expressions; so in order to +being callable, they must first be evaluated.

+ +
( // evaluate the function inside the parentheses
+function() {}
+) // and return the function object
+() // call the result of the evaluation
+
+ +

There are other ways to evaluate and directly call the function expression +which, while different in syntax, behave the same way.

+ +
// A few other styles for directly invoking the 
+!function(){}()
++function(){}()
+(function(){}());
+// and so on...
+
+ +

In Conclusion

+ +

It is recommended to always use an anonymous wrapper to encapsulate code in +its own namespace. This does not only protect code against name clashes, but it +also allows for better modularization of programs.

+ +

Additionally, the use of global variables is considered bad practice. Any +use of them indicates badly written code that is prone to errors and hard to maintain.

Arrays

Array 迴圈和屬性

雖然在 Javascript 中 Array 都是 Objects,但是沒有好的理由要使用他 +在 for in 的迴圈中。事實上有很多原因要避免使用 for in 在 Array 之中

+ + + +

因為 for in 迴圈會列舉所有在原型 Array 上的屬性因為他會使用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 迴圈則是會讓程式中有更多的錯誤和性能問題。

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 的建構函式需要避免,建議使用字面語法。因為他們比較簡短、也更增加閱讀性

Types

Equality and Comparisons

JavaScript has two different ways of comparing the values of objects for equality.

+ +

The Equality Operator

+ +

The equality operator consists of two equal signs: ==

+ +

JavaScript features weak typing. This means that the equality operator +coerces types in order to compare them.

+ +
""           ==   "0"           // false
+0            ==   ""            // true
+0            ==   "0"           // true
+false        ==   "false"       // false
+false        ==   "0"           // true
+false        ==   undefined     // false
+false        ==   null          // false
+null         ==   undefined     // true
+" \t\r\n"    ==   0             // true
+
+ +

The above table shows the results of the type coercion, and it is the main reason +why the use of == is widely regarded as bad practice. It introduces +hard-to-track-down bugs due to its complicated conversion rules.

+ +

Additionally, there is also a performance impact when type coercion is in play; +for example, a string has to be converted to a number before it can be compared +to another number.

+ +

The Strict Equality Operator

+ +

The strict equality operator consists of three equal signs: ===.

+ +

It works like the normal equality operator, except that strict equality +operator does not perform type coercion between its operands.

+ +
""           ===   "0"           // false
+0            ===   ""            // false
+0            ===   "0"           // false
+false        ===   "false"       // false
+false        ===   "0"           // false
+false        ===   undefined     // false
+false        ===   null          // false
+null         ===   undefined     // false
+" \t\r\n"    ===   0             // false
+
+ +

The above results are a lot clearer and allow for early breakage of code. This +hardens code to a certain degree and also gives performance improvements in case +the operands are of different types.

+ +

Comparing Objects

+ +

While both == and === are called equality operators, they behave +differently when at least one of their operands is an Object.

+ +
{} === {};                   // false
+new String('foo') === 'foo'; // false
+new Number(10) === 10;       // false
+var foo = {};
+foo === foo;                 // true
+
+ +

Here, both operators compare for identity and not equality; that is, they +will compare for the same instance of the object, much like is in Python +and pointer comparison in C.

+ +

In Conclusion

+ +

It is highly recommended to only use the strict equality operator. In cases +where types need to be coerced, it should be done explicitly +and not left to the language's complicated coercion rules.

The typeof Operator

The typeof operator (together with +instanceof) is probably the biggest +design flaw of JavaScript, as it is almost completely broken.

+ +

Although instanceof still has limited uses, typeof really has only one +practical use case, which does not happen to be checking the type of an +object.

+ + + +

The JavaScript Type Table

+ +
Value               Class      Type
+-------------------------------------
+"foo"               String     string
+new String("foo")   String     object
+1.2                 Number     number
+new Number(1.2)     Number     object
+true                Boolean    boolean
+new Boolean(true)   Boolean    object
+new Date()          Date       object
+new Error()         Error      object
+[1,2,3]             Array      object
+new Array(1, 2, 3)  Array      object
+new Function("")    Function   function
+/abc/g              RegExp     object (function in Nitro/V8)
+new RegExp("meow")  RegExp     object (function in Nitro/V8)
+{}                  Object     object
+new Object()        Object     object
+
+ +

In the above table, Type refers to the value that the typeof operator returns. +As can be clearly seen, this value is anything but consistent.

+ +

The Class refers to the value of the internal [[Class]] property of an object.

+ + + +

In order to retrieve the value of [[Class]], one has to make use of the +toString method of Object.prototype.

+ +

The Class of an Object

+ +

The specification gives exactly one way of accessing the [[Class]] value, +with the use of Object.prototype.toString.

+ +
function is(type, obj) {
+    var clas = Object.prototype.toString.call(obj).slice(8, -1);
+    return obj !== undefined && obj !== null && clas === type;
+}
+
+is('String', 'test'); // true
+is('String', new String('test')); // true
+
+ +

In the above example, Object.prototype.toString gets called with the value of +this being set to the object whose [[Class]] value should be +retrieved.

+ + + +

Testing for Undefined Variables

+ +
typeof foo !== 'undefined'
+
+ +

The above will check whether foo was actually declared or not; just +referencing it would result in a ReferenceError. This is the only thing +typeof is actually useful for.

+ +

In Conclusion

+ +

In order to check the type of an object, it is highly recommended to use +Object.prototype.toString because this is the only reliable way of doing so. +As shown in the above type table, some return values of typeof are not defined +in the specification; thus, they can differ between implementations.

+ +

Unless checking whether a variable is defined, typeof should be avoided.

The instanceof Operator

The instanceof operator compares the constructors of its two operands. It is +only useful when comparing custom made objects. Used on built-in types, it is +nearly as useless as the typeof operator.

+ +

Comparing Custom Objects

+ +
function Foo() {}
+function Bar() {}
+Bar.prototype = new Foo();
+
+new Bar() instanceof Bar; // true
+new Bar() instanceof Foo; // true
+
+// This just sets Bar.prototype to the function object Foo,
+// but not to an actual instance of Foo
+Bar.prototype = Foo;
+new Bar() instanceof Foo; // false
+
+ +

Using instanceof with Native Types

+ +
new String('foo') instanceof String; // true
+new String('foo') instanceof Object; // true
+
+'foo' instanceof String; // false
+'foo' instanceof Object; // false
+
+ +

One important thing to note here is that instanceof does not work on objects +that originate from different JavaScript contexts (e.g. different documents +in a web browser), since their constructors will not be the exact same object.

+ +

In Conclusion

+ +

The instanceof operator should only be used when dealing with custom made +objects that originate from the same JavaScript context. Just like the +typeof operator, every other use of it should be avoided.

Type Casting

JavaScript is a weakly typed language, so it will apply type coercion +wherever possible.

+ +
// These are true
+new Number(10) == 10; // Number.toString() is converted
+                      // back to a number
+
+10 == '10';           // Strings gets converted to Number
+10 == '+10 ';         // More string madness
+10 == '010';          // And more 
+isNaN(null) == false; // null converts to 0
+                      // which of course is not NaN
+
+// These are false
+10 == 010;
+10 == '-10';
+
+ + + +

To avoid the issues above, use of the strict equal operator +is highly recommended. Although this avoids a lot of common pitfalls, there +are still many further issues that arise from JavaScript's weak typing system.

+ +

Constructors of Built-In Types

+ +

The constructors of the built in types like Number and String behave +differently when being used with the new keyword and without it.

+ +
new Number(10) === 10;     // False, Object and Number
+Number(10) === 10;         // True, Number and Number
+new Number(10) + 0 === 10; // True, due to implicit conversion
+
+ +

Using a built-in type like Number as a constructor will create a new Number +object, but leaving out the new keyword will make the Number function behave +like a converter.

+ +

In addition, passing literals or non-object values will result in even more +type coercion.

+ +

The best option is to cast to one of the three possible types explicitly.

+ +

Casting to a String

+ +
'' + 10 === '10'; // true
+
+ +

By prepending an empty string, a value can easily be cast to a string.

+ +

Casting to a Number

+ +
+'10' === 10; // true
+
+ +

Using the unary plus operator, it is possible to cast to a number.

+ +

Casting to a Boolean

+ +

By using the not operator twice, a value can be converted a boolean.

+ +
!!'foo';   // true
+!!'';      // false
+!!'0';     // true
+!!'1';     // true
+!!'-1'     // true
+!!{};      // true
+!!true;    // true
+

Core

為什麼不要使用 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

+ +

定時函數 setTimeoutsetInterval 都可以接受一個字串當做他們第一個參數。這些字串 永遠 都會在全域範圍內執行,因此在這種情況下 eval 沒有被直接的使用。

+ +

安全上的顧慮

+ +

eval 同樣有安全上的問題,因為所有的程式碼都可以被直接執行。 +而他不應去執行一串未知的字串或是來自不幸任的來源。

+ +

結語

+ +

eval 應該永遠不要去只用它,任何的程式在被他執行後都有性能和安全上的考慮。如果有情況需要去使用他,他都不應該列為第一順位的解決方法。

+ +

應該有更好的方法能夠去使用,但是最好都不要去使用 eval

undefinednull

JavaScript 中有兩個表示空值的方式, nullundefinedundefined式比較常用的一種。

+ +

undefined 的值

+ +

undefined 是一個值為 undefined 的類型。

+ +

語言中也定義了一個全域變數,它的值為 undefined,這個變數的被稱作 undefined 。 +這個變數 不是 一個常數,也不是一個關鍵字。這表示它的值可以被輕易的覆蓋。

+ + + +

這裡有一些例子會回傳 undefined 的值:

+ +
    +
  • 進入尚未修改的全域變數 undefined
  • +
  • 進入一個宣告但 尚未 初始化的變數。
  • +
  • return 表示式中沒有返回任何內容。
  • +
  • 呼叫不存在的屬性。
  • +
  • 函式參數沒有被傳遞數值。
  • +
  • 任何被被設定為 undefined 的變數。
  • +
  • 任何表達式中形式為 void(expression)
  • +
+ +

處理 undefined 值的改變

+ +

由於全域變數 undefined 只有保存 undefined 類型實際值的一個副本,指定了一個新的值並 不會 改變 undefined類型裡面的值。

+ +

為了避免去改變 undefined 的值,常用的技巧就是加上一個新的變數到 匿名包裝器。在使用的時候,這個參數不會接受任何的值。

+ +
var undefined = 123;
+(function(something, foo, undefined) {
+    // undefined 在區域區間內得到了 `undefined` 的值
+
+})('Hello World', 42);
+
+ +

另外一個可以得到同樣的效果就是在內部宣告一個變數

+ +
var undefined = 123;
+(function(something, foo) {
+    var undefined;
+    ...
+
+})('Hello World', 42);
+
+ +

唯一的不同就是在下者會多 4 個多 bytes 用來壓縮檔案,而且函數內野沒有其他需要使用 var

+ +

使用 null

+ +

JavaScript 中所使用的 undefined 類似別的語言中的 null , 但實際上在 JavaScript 中的 null 算是另外一個類型。

+ +

它在 JavaScript 有些可以使用的地方 (例如說宣告一個原型的終結,例如 Foo.prototype = null )。 +但是在大部分的時候可以用 undefined,來取代。

自動插入分號

雖然 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); //<- 插入分號
+
+ + + +

編譯器在上面的程式碼中改變了原本程式碼的行為。在一些情況下,會做出 錯誤的行為

+ +

前置括號

+ +

在這種前置括號的情況下,編譯器 不會 自動的插入分號。

+ +
log('testing!')
+(options.list || []).forEach(function(i) {})
+
+ +

上面的程式碼被編譯器轉為只有一行程式

+ +
log('testing!')(options.list || []).forEach(function(i) {})
+
+ +

以上的範例中 log很大 的可能 不是 回傳一個函數。然而這個情況下會出現 TypeError 的錯誤或是會出現 undefined is not a function .

+ +

結語

+ +

建議永遠 不要 忽略分號。同樣的也建議大括號應在他對應的表達式在同一行。在 if... else...的表達式中也是如此,不應省略大括號。 +這個習慣可以不僅僅是讓你的程式更一致,也可以避免編譯器因為改變程式而出錯。

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 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 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 +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.

Other

setTimeout and setInterval

Since JavaScript is asynchronous, it is possible to schedule the execution of a +function using the setTimeout and setInterval functions.

+ + + +
function foo() {}
+var id = setTimeout(foo, 1000); // returns a Number > 0
+
+ +

When setTimeout is called, it returns the ID of the timeout and schedule +foo to run approximately one thousand milliseconds in the future. +foo will then be executed once.

+ +

Depending on the timer resolution of the JavaScript engine running the code, as +well as the fact that JavaScript is single threaded and other code that gets +executed might block the thread, it is by no means a safe bet that one will +get the exact delay specified in the setTimeout call.

+ +

The function that was passed as the first parameter will get called by the +global object, which means that this inside the called function +refers to the global object.

+ +
function Foo() {
+    this.value = 42;
+    this.method = function() {
+        // this refers to the global object
+        console.log(this.value); // will log undefined
+    };
+    setTimeout(this.method, 500);
+}
+new Foo();
+
+ + + +

Stacking Calls with setInterval

+ +

While setTimeout only runs the function once, setInterval - as the name +suggests - will execute the function every X milliseconds, but its use is +discouraged.

+ +

When code that is being executed blocks the timeout call, setInterval will +still issue more calls to the specified function. This can, especially with small +intervals, result in function calls stacking up.

+ +
function foo(){
+    // something that blocks for 1 second
+}
+setInterval(foo, 1000);
+
+ +

In the above code, foo will get called once and will then block for one second.

+ +

While foo blocks the code, setInterval will still schedule further calls to +it. Now, when foo has finished, there will already be ten further calls to +it waiting for execution.

+ +

Dealing with Possible Blocking Code

+ +

The easiest solution, as well as most controllable solution, is to use setTimeout within +the function itself.

+ +
function foo(){
+    // something that blocks for 1 second
+    setTimeout(foo, 1000);
+}
+foo();
+
+ +

Not only does this encapsulate the setTimeout call, but it also prevents the +stacking of calls and gives additional control. foo itself can now decide +whether it wants to run again or not.

+ +

Manually Clearing Timeouts

+ +

Clearing timeouts and intervals works by passing the respective ID to +clearTimeout or clearInterval, depending on which set function was used +in the first place.

+ +
var id = setTimeout(foo, 1000);
+clearTimeout(id);
+
+ +

Clearing All Timeouts

+ +

As there is no built-in method for clearing all timeouts and/or intervals, +it is necessary to use brute force in order to achieve this functionality.

+ +
// clear "all" timeouts
+for(var i = 1; i < 1000; i++) {
+    clearTimeout(i);
+}
+
+ +

But there might still be timeouts that are unaffected by this arbitrary number. +Another way of doing this is to consider that the ID given to a timeout is +incremented by one every time you call setTimeout.

+ +
// clear "all" timeouts
+var biggestTimeoutId = window.setTimeout(function(){}, 1),
+i;
+for(i = 1; i <= biggestTimeoutId; i++) {
+    clearTimeout(i);
+}
+
+ +

Even though this works on all major browsers today, it isn't specified that +the IDs should be ordered that way and it may change. Therefore, it is instead +recommended to keep track of all the timeout IDs, so they can be cleared +specifically.

+ +

Hidden Use of eval

+ +

setTimeout and setInterval can also take a string as their first parameter. +This feature should never be used because it internally makes use of eval.

+ + + +
function foo() {
+    // will get called
+}
+
+function bar() {
+    function foo() {
+        // never gets called
+    }
+    setTimeout('foo()', 1000);
+}
+bar();
+
+ +

Since eval is not getting called directly in this case, the string +passed to setTimeout will be executed in the global scope; thus, it will +not use the local variable foo from the scope of bar.

+ +

It is further recommended to not use a string to pass arguments to the +function that will get called by either of the timeout functions.

+ +
function foo(a, b, c) {}
+
+// NEVER use this
+setTimeout('foo(1, 2, 3)', 1000)
+
+// Instead use an anonymous function
+setTimeout(function() {
+    foo(a, b, c);
+}, 1000)
+
+ + + +

In Conclusion

+ +

A string should never be used as the parameter of setTimeout or +setInterval. It is a clear sign of really bad code, when arguments need +to be supplied to the function that gets called. An anonymous function should +be passed that then takes care of the actual call.

+ +

Furthermore, the use of setInterval should be avoided because its scheduler is not +blocked by executing JavaScript.

\ No newline at end of file From 4a2617698774b12942c24b7411e9088db5f53513 Mon Sep 17 00:00:00 2001 From: howardchi Date: Thu, 14 Mar 2013 02:57:50 +0800 Subject: [PATCH 070/277] finished function/ closures, general --- doc/zh-TW/function/closures.md | 63 ++++++++++++---------------------- doc/zh-TW/function/general.md | 45 +++++++++++------------- 2 files changed, 42 insertions(+), 66 deletions(-) diff --git a/doc/zh-TW/function/closures.md b/doc/zh-TW/function/closures.md index 76f2d078..8c558efa 100644 --- a/doc/zh-TW/function/closures.md +++ b/doc/zh-TW/function/closures.md @@ -1,11 +1,10 @@ -## Closures and References +## Closures 和 References -One of JavaScript's most powerful features is the availability of *closures*. -With closures, scopes **always** keep access to the outer scope, in which they -were defined. Since the only scoping that JavaScript has is -[function scope](#function.scopes), all functions, by default, act as closures. +JavaScript 有一個很重要的特徵就是 **closures** +因為有 Closures,所以作用域 **永遠** 能夠去訪問作用區間外面的變數。 +[函數區間](#function.scopes) 是JavaScript 中唯一擁有自生作用域的結構,因此 Closures 的創立需要依賴函數 -### Emulating private variables +### 模仿私有變數 function Counter(start) { var count = start; @@ -24,30 +23,24 @@ were defined. Since the only scoping that JavaScript has is foo.increment(); foo.get(); // 5 -Here, `Counter` returns **two** closures: the function `increment` as well as -the function `get`. Both of these functions keep a **reference** to the scope of -`Counter` and, therefore, always keep access to the `count` variable that was -defined in that scope. +這裡,`Counter` 返回兩個 Closures,函數 `increment` 還有 `get`。這兩個函數都維持著對外部作用域 `Counter` 的引用,因此總可以訪問作用域的變數 `count`。 -### Why Private Variables Work -Since it is not possible to reference or assign scopes in JavaScript, there is -**no** way of accessing the variable `count` from the outside. The only way to -interact with it is via the two closures. +### 為什麼不可以在外部訪問私有變數 + +因為 Javascript **不可以** 對作用域進行引用或賦值。因此外部的地方沒有辦法訪問 `count` 變數。 +唯一的途徑就是經過那兩個 Closures var foo = new Counter(4); foo.hack = function() { count = 1337; }; -The above code will **not** change the variable `count` in the scope of `Counter`, -since `foo.hack` was not defined in **that** scope. It will instead create - or -override - the *global* variable `count`. +在上面的例子中 `count` **不會** 改變到 `Counter` 裡面的 `count` 的值。因為 `foo.hack` 沒有在 **那個** 作用域內被宣告。它只有會覆蓋或者建立在一個 **全域** 的變數 `count` -### Closures Inside Loops +### 在循環內的 Closures -One often made mistake is to use closures inside of loops, as if they were -copying the value of the loop's index variable. +一個常見的錯誤就是在 Closures 中使用迴圈,假設我們要使用每次迴圈中所使用的進入變數 for(var i = 0; i < 10; i++) { setTimeout(function() { @@ -55,20 +48,14 @@ copying the value of the loop's index variable. }, 1000); } -The above will **not** output the numbers `0` through `9`, but will simply print -the number `10` ten times. - -The *anonymous* function keeps a **reference** to `i`. At the time -`console.log` gets called, the `for loop` has already finished, and the value of -`i` as been set to `10`. - -In order to get the desired behavior, it is necessary to create a **copy** of -the value of `i`. +在上面的例子中它 **不會** 輸出數字從 `0` 到 `9`,但只會出現數字 `10` 十次。 +在 `console.log` 被呼叫的時候,這個 *匿名* 函數中保持一個 **參考** 到 i ,此時 `for`迴圈已經結束, `i` 的值被修改成了 `10`。 +為了要達到想要的結果,需要在每次創造 **副本** 來儲存 `i` 的變數。 -### Avoiding the Reference Problem +### 避免引用錯誤 -In order to copy the value of the loop's index variable, it is best to use an -[anonymous wrapper](#function.scopes). +為了要有達到正確的效果,最好是把它包在一個 +[匿名函數](#function.scopes). for(var i = 0; i < 10; i++) { (function(e) { @@ -78,15 +65,9 @@ In order to copy the value of the loop's index variable, it is best to use an })(i); } -The anonymous outer function gets called immediately with `i` as its first -argument and will receive a copy of the **value** of `i` as its parameter `e`. - -The anonymous function that gets passed to `setTimeout` now has a reference to -`e`, whose value does **not** get changed by the loop. - -There is another possible way of achieving this, which is to return a function -from the anonymous wrapper that will then have the same behavior as the code -above. +匿名外部的函數被呼叫,並把 `i` 作為它第一個參數,此時函數內 `e` 變數就擁有了一個 `i` 的拷貝。 +當傳遞給 `setTimeout` 這個匿名函數執行時,它就擁有了對 `e` 的引用,而這個值 **不會** 被循環改變。 +另外有一個方法也可以完成這樣的工作,那就是在匿名函數中返回一個函數,這和上面的程式碼有同樣的效果。 for(var i = 0; i < 10; i++) { setTimeout((function(e) { diff --git a/doc/zh-TW/function/general.md b/doc/zh-TW/function/general.md index b2788e46..57f4810f 100644 --- a/doc/zh-TW/function/general.md +++ b/doc/zh-TW/function/general.md @@ -1,48 +1,43 @@ -## Function Declarations and Expressions +## 函式的宣告和表達方式 -Functions in JavaScript are first class objects. That means they can be -passed around like any other value. One common use of this feature is to pass -an *anonymous function* as a callback to another, possibly an asynchronous function. +函式在 JavaScript 是第一等物件。這表示他們可以把函式當做值一樣傳遞。 +一個常見的用法是用 *匿名函式* 當做一個回傳去呼叫另一個函式,這是一種非同步函式 -### The `function` Declaration +### 函式的宣告 function foo() {} -The above function gets [hoisted](#function.scopes) before the execution of the -program starts; thus, it is available *everywhere* in the scope it was -*defined*, even if called before the actual definition in the source. +上面的函式在被執行之前會被 [解析(hoisted)](#function.scopes),因此它可以在 **任意** 的地方都是 *有宣告的* ,就算是在比這個函式還早呼叫。 - foo(); // Works because foo was created before this code runs + + foo(); // 可以執行,因為 foo 已經在運行前就被建立 function foo() {} -### The `function` Expression +### `function` 的表達式 var foo = function() {}; -This example assigns the unnamed and *anonymous* function to the variable `foo`. +這個例子把一個 *匿名* 函式賦值給變數 `foo`。 foo; // 'undefined' - foo(); // this raises a TypeError + foo(); // 錯誤: TypeError var foo = function() {}; -Due to the fact that `var` is a declaration that hoists the variable name `foo` -before the actual execution of the code starts, `foo` is already defined when -the script gets executed. +由於 `var` 已經宣告變數 `foo` 在所有的程式碼執行之前。 +所以 `foo`已經在程式運行前就已經被定義過了。 +但是因為賦值只會在運行時去職情,所以在程式碼執行前,`foo` 的值還沒被宣告所以為 [undefined](#core.undefined)。 -But since assignments only happen at runtime, the value of `foo` will default -to [undefined](#core.undefined) before the corresponding code is executed. -### Named Function Expression +### 命名函式的賦值表達式 -Another special case is the assignment of named functions. +另一個特殊狀況就勢將一個命名函式賦值給一個變數。 var foo = function bar() { - bar(); // Works + bar(); // 可以運行 } - bar(); // ReferenceError + bar(); // 錯誤:ReferenceError -Here, `bar` is not available in the outer scope, since the function only gets -assigned to `foo`; however, inside of `bar`, it is available. This is due to -how [name resolution](#function.scopes) in JavaScript works, the name of the -function is *always* made available in the local scope of the function itself. +`bar` 不可以在外部的區域被執行,因為它只有在 `foo` 的函式內才可以去執行。 +然而在 `bar` 內部還是可以看見。這是由於 JavaScript的 [命名處理](#function.scopes)所致。 +函式名在函式內 *都* 可以去使用。 From 5804c903bc52bdd878ea635fbf24b06405fcbf3e Mon Sep 17 00:00:00 2001 From: howardchi Date: Thu, 14 Mar 2013 12:38:22 +0800 Subject: [PATCH 071/277] modify language.json, index.json, constructors.md --- doc/language.json | 2 +- doc/zh-TW/function/constructors.md | 81 +++++++++++------------------- doc/zh-TW/function/scopes.md | 18 +++---- doc/zh-TW/function/this.md | 42 +++++++--------- doc/zh-TW/index.json | 20 ++++---- 5 files changed, 67 insertions(+), 96 deletions(-) diff --git a/doc/language.json b/doc/language.json index 19ef049f..c45b38b6 100644 --- a/doc/language.json +++ b/doc/language.json @@ -1,5 +1,5 @@ { "default": "en", - "listed": ["en", "fi", "ru", "zh", "tr", "pl", "ko", "ja", "es"] + "listed": ["en", "fi", "ru", "zh", "tr", "pl", "ko", "ja", "es", "zh-Tw"] } diff --git a/doc/zh-TW/function/constructors.md b/doc/zh-TW/function/constructors.md index bf9771dc..8c493854 100644 --- a/doc/zh-TW/function/constructors.md +++ b/doc/zh-TW/function/constructors.md @@ -1,15 +1,12 @@ -## Constructors +## 建構函式 -Constructors in JavaScript are yet again different from many other languages. Any -function call that is preceded by the `new` keyword acts as a constructor. - -Inside the constructor - the called function - the value of `this` refers to a -newly created object. The [prototype](#object.prototype) of this **new** -object is set to the `prototype` of the function object that was invoked as the -constructor. +JavaScript 中的建構函式和其他語言中的建構函式是不同的。 +用 `new` 的關鍵字方式調用的函式都被認為是建構函式。 +在建構函式內部 - 被呼叫的函式 - `this` 指向一個新建立的 `object`。[prototype](#object.prototype) 這是一個新的物件一個被指向函式的 `prototype` 的建構函式。 If the function that was called has no explicit `return` statement, then it implicitly returns the value of `this` - the new object. +如果被使用的函式沒有明顯的呼叫 `return` 的表達式,它會回傳一個隱性的 `this` 的新物件。 function Foo() { this.bla = 1; @@ -21,16 +18,13 @@ implicitly returns the value of `this` - the new object. var test = new Foo(); -The above calls `Foo` as constructor and sets the `prototype` of the newly -created object to `Foo.prototype`. - -In case of an explicit `return` statement, the function returns the value -specified by that statement, but **only** if the return value is an `Object`. +在上面的例子中 `Foo` 建立一個建構函式,並設立一個 `prototype` 來創建一個新的物件叫 `Foo.prototype`。 +這個情況下它顯示的 `return` 一個表達式,但他 **只** 返回一個 `Object`。 function Bar() { return 2; } - new Bar(); // a new object + new Bar(); // 返回一個新物件 function Test() { this.value = 2; @@ -39,23 +33,20 @@ specified by that statement, but **only** if the return value is an `Object`. foo: 1 }; } - new Test(); // the returned object + new Test(); // 回傳物件 -When the `new` keyword is omitted, the function will **not** return a new object. +如果 `new` 的關鍵字被忽略,函式就 **不會** 回傳一個新的物件。 function Foo() { - this.bla = 1; // gets set on the global object + this.bla = 1; // 獲取一個全域的參數 } Foo(); // undefined -While the above example might still appear to work in some cases, due to the -workings of [`this`](#function.this) in JavaScript, it will use the -*global object* as the value of `this`. +雖然上面有些情況也能正常運行,但是由於 JavaScript 中 [`this`](#funciton.this) 的工作原理,這裡的 `this` 指向 *全域對象*。 -### Factories +### 工廠模式 -In order to be able to omit the `new` keyword, the constructor function has to -explicitly return a value. +為了不使用 `new` 關鍵字,建構函式必須顯性的返回一個值。 function Bar() { var value = 1; @@ -72,25 +63,17 @@ explicitly return a value. new Bar(); Bar(); -Both calls to `Bar` return the same thing, a newly create object that -has a property called `method`, which is a -[Closure](#function.closures). - -It should also be noted that the call `new Bar()` does **not** affect the -prototype of the returned object. While the prototype will be set on the newly -created object, `Bar` never returns that new object. - -In the above example, there is no functional difference between using and -not using the `new` keyword. +上面兩個呼叫 `Bar` 的方法回傳的值都一樣,一個新創建的擁有 `method` 屬性被返回,這裡創建了一個 [Closure](#function.closures). +還有注意, `new Bar()` 並 **不會** 改變返回物件的原型。 +因為建構函式的原型會指向剛剛創立的新物件,而在這裡的 `Bar` 沒有把這個新物件返回。 +在上面的例子中,使用或者不使用 `new` 關鍵字沒有什麼功能性的區別 -### Creating New Objects via Factories -It is often recommended to **not** use `new` because forgetting its use may -lead to bugs. +### 通過工廠模式創建的新對象 -In order to create a new object, one should rather use a factory and construct a -new object inside of that factory. +常聽到建議 **不要** 使用 `new`,因為如果忘記如何使用它會造成錯誤。 +為了創建一個新的物件,我們可以用工廠方法,來創造一個新的物件在那個方法中。 function Foo() { var obj = {}; @@ -107,22 +90,14 @@ new object inside of that factory. return obj; } -While the above is robust against a missing `new` keyword and certainly makes -the use of [private variables](#function.closures) easier, it comes with some -downsides. +雖然上面的方式比起 `new` 的調用方式更不容易出錯,並且可以充分的使用 [私有變數](#function.closures)所帶來的便利,但是還是有一些不好的地方 - 1. It uses more memory since the created objects do **not** share the methods - on a prototype. - 2. In order to inherit, the factory needs to copy all the methods from another - object or put that object on the prototype of the new object. - 3. Dropping the prototype chain just because of a left out `new` keyword - is contrary to the spirit of the language. -### In Conclusion +1. 會占用更多的記憶體,因為創建的物件 **沒有** 辦法放在在同一個原型上。 +2. 為了要用繼承的方式,工廠方法需要複製所有的屬性或是把一個物件作為新的物件的原型。 +3. 放棄原型鏈僅僅是因為防止遺漏 `new` 所帶來的問題,這與語言本身的思想鄉違背。 -While omitting the `new` keyword might lead to bugs, it is certainly **not** a -reason to drop the use of prototypes altogether. In the end it comes down to -which solution is better suited for the needs of the application. It is -especially important to choose a specific style of object creation and use it -**consistently**. +### 結語 +雖然遺漏 `new` 關鍵字可能會導致問題,但這並 **不是** 放棄只用原型的藉口。 +最終使用哪種方式取決於應用程式的需求,選擇一種程式語言風格並堅持下去才是最重要的。 diff --git a/doc/zh-TW/function/scopes.md b/doc/zh-TW/function/scopes.md index 879e1e8a..00263804 100644 --- a/doc/zh-TW/function/scopes.md +++ b/doc/zh-TW/function/scopes.md @@ -1,12 +1,11 @@ -## Scopes and Namespaces +## 作用域和命名空間 -Although JavaScript deals fine with the syntax of two matching curly -braces for blocks, it does **not** support block scope; hence, all that is left -in the language is *function scope*. +儘管 JavaScript 支持一個大括號創建的程式碼,但並不支持塊級作用域。 +而僅僅支援 *函式作用域* - function test() { // a scope - for(var i = 0; i < 10; i++) { // not a scope - // count + function test() { // 一個作用域 + for(var i = 0; i < 10; i++) { // 不是一個作用域 + // 算數 } console.log(i); // 10 } @@ -16,6 +15,7 @@ in the language is *function scope*. > **not** as an object literal. This, in conjunction with > [automatic insertion of semicolons](#core.semicolon), can lead to subtle errors. + There are also no distinct namespaces in JavaScript, which means that everything gets defined in one *globally shared* namespace. @@ -23,7 +23,7 @@ Each time a variable is referenced, JavaScript will traverse upwards through all the scopes until it finds it. In the case that it reaches the global scope and still has not found the requested name, it will raise a `ReferenceError`. -### The Bane of Global Variables +### 全域變數的壞處 // script A foo = '42'; @@ -222,7 +222,7 @@ which, while different in syntax, behave the same way. (function(){}()); // and so on... -### In Conclusion +### 結語 It is recommended to always use an *anonymous wrapper* to encapsulate code in its own namespace. This does not only protect code against name clashes, but it diff --git a/doc/zh-TW/function/this.md b/doc/zh-TW/function/this.md index 48070d2e..31081883 100644 --- a/doc/zh-TW/function/this.md +++ b/doc/zh-TW/function/this.md @@ -1,50 +1,46 @@ -## How `this` Works +## `this` 的工作原理 -JavaScript has a different concept of what the special name `this` refers to -than most other programming languages. There are exactly **five** different -ways in which the value of `this` can be bound in the language. +JavaScript 有移到完全部屬於其他語言處理 `this` 的處理機制。 +在 **五** 種物同的情況下, `this` 指向的個不相同 -### The Global Scope +### 全域變數 this; -When using `this` in global scope, it will simply refer to the *global* object. +如果再全域範圍內使用 `this`,會指向 *全域* 的物件 -### Calling a Function +### 呼叫一個函式 foo(); -Here, `this` will again refer to the *global* object. +這裡 `this` 也會指向 *全域* 對象。 -> **ES5 Note:** In strict mode, the global case **no longer** exists. -> `this` will instead have the value of `undefined` in that case. +> **ES5 注意:** 在嚴格模式下,不存在全域變數。 +> `this` 將會是 `undefined`。 -### Calling a Method +### 方法調用 test.foo(); -In this example, `this` will refer to `test`. +這個例子中, `this` 指向 `test` 物件。 -### Calling a Constructor +### 呼叫一個建構函式 new foo(); -A function call that is preceded by the `new` keyword acts as -a [constructor](#function.constructors). Inside the function, `this` will refer -to a *newly created* `Object`. +如果函式傾向用 `new` 關鍵詞使用,我們稱這個函式為 [建構函式](#function.constructors)。 +在函式內部, `this` 指向 *新物件的創立* -### Explicit Setting of `this` +### 顯示的設置 `this` function foo(a, b, c) {} var bar = {}; - foo.apply(bar, [1, 2, 3]); // array will expand to the below - foo.call(bar, 1, 2, 3); // results in a = 1, b = 2, c = 3 + foo.apply(bar, [1, 2, 3]); // Array 會被擴展,如下所示 + foo.call(bar, 1, 2, 3); // 傳遞參數 a = 1, b = 2, c = 3 -When using the `call` or `apply` methods of `Function.prototype`, the value of -`this` inside the called function gets **explicitly set** to the first argument -of the corresponding function call. +當使用 `function.prototype` 上的 `call` 或只 `apply` 方法時,函式內的 `this` 將會被 **顯示設置** 為函式調用的第一個參數。 As a result, in the above example the *method case* does **not** apply, and `this` inside of `foo` will be set to `bar`. @@ -53,7 +49,7 @@ inside of `foo` will be set to `bar`. > literal. So `var obj = {me: this}` will **not** result in `me` referring to > `obj`, since `this` only gets bound by one of the five listed cases. -### Common Pitfalls +### 常見誤解 While most of these cases make sense, the first can be considered another mis-design of the language because it **never** has any practical use. diff --git a/doc/zh-TW/index.json b/doc/zh-TW/index.json index bffcbf2c..362fcb44 100644 --- a/doc/zh-TW/index.json +++ b/doc/zh-TW/index.json @@ -1,15 +1,15 @@ { - "title": "JavaScript Garden", - "langTitle": "JavaScript Garden in English", - "description": "A Guide to JavaScript's Quirks and Flaws.", + "title": "JavaScript 庭院", + "langTitle": "JavaScript Garden 繁體中文翻譯", + "description": "JavaScript 語言中古怪用法及缺點的文件總集", "sections": [ { - "title": "Intro", + "title": "簡介", "dir": "intro", "articles": [] }, { - "title": "Objects", + "title": "物件", "dir": "object", "articles": [ "general", @@ -19,7 +19,7 @@ ] }, { - "title": "Functions", + "title": "函式", "dir": "function", "articles": [ "general", @@ -31,7 +31,7 @@ ] }, { - "title": "Arrays", + "title": "陣列", "dir": "array", "articles": [ "general", @@ -39,7 +39,7 @@ ] }, { - "title": "Types", + "title": "類型", "dir": "types", "articles": [ "equality", @@ -49,7 +49,7 @@ ] }, { - "title": "Core", + "title": "核心", "dir": "core", "articles": [ "eval", @@ -59,7 +59,7 @@ ] }, { - "title": "Other", + "title": "其他", "dir": "other", "articles": [ "timeouts" From 3cb2af35117fea202c740ac1708dd8300b3512bc Mon Sep 17 00:00:00 2001 From: howardchi Date: Thu, 14 Mar 2013 15:51:02 +0800 Subject: [PATCH 072/277] finished function/ scope.md --- doc/zh-TW/function/scopes.md | 158 +++++++++------------- site/zh-TW/index.html | 251 ++++++++++++++--------------------- 2 files changed, 161 insertions(+), 248 deletions(-) diff --git a/doc/zh-TW/function/scopes.md b/doc/zh-TW/function/scopes.md index 00263804..3f7c72dd 100644 --- a/doc/zh-TW/function/scopes.md +++ b/doc/zh-TW/function/scopes.md @@ -10,18 +10,13 @@ console.log(i); // 10 } -> **Note:** When not used in an assignment, return statement or as a function -> argument, the `{...}` notation will get interpreted as a block statement and -> **not** as an object literal. This, in conjunction with -> [automatic insertion of semicolons](#core.semicolon), can lead to subtle errors. +> **注意:** 如果不是在賦值語句中,而是在 return 表達式或者函數參數中, `{...}` 將會作為程式碼中的解析,而不是作為物件的字面語法解析。 +> 如果考慮到 [自動分號插入](#core.semicolon),可能會造成一些不易察覺的錯誤。 +JavaScript 中沒有寫示的命名空間定義,這代表著它所有定義的東西都是 *全域共享* 在同一個命名空間下。 -There are also no distinct namespaces in JavaScript, which means that everything -gets defined in one *globally shared* namespace. - -Each time a variable is referenced, JavaScript will traverse upwards through all -the scopes until it finds it. In the case that it reaches the global scope and -still has not found the requested name, it will raise a `ReferenceError`. +每次引用一個變數,JavaScript 會向上找整個作用域直到找到這個變數為止。 +如果在全域中無法找到那個變數,它會拋出 `ReferenceError` 錯誤碼。 ### 全域變數的壞處 @@ -31,17 +26,14 @@ still has not found the requested name, it will raise a `ReferenceError`. // script B var foo = '42' -The above two scripts do **not** have the same effect. Script A defines a -variable called `foo` in the *global* scope, and script B defines a `foo` in the -*current* scope. +上面兩個腳本 *不會* 有同樣的效果。腳本 A 在 *全域* 空間定義了變數 `foo`,腳本 B 定義了 `foo` 在目前的區間內。 -Again, that is **not** at all the *same effect*: not using `var` can have major -implications. +再次強調,上面的效果是 **完全不同**,不使用 `var` 會導致隱性的全域變數。 - // global scope + // 全域作用區 var foo = 42; function test() { - // local scope + // 局部作用區 foo = 21; } test(); @@ -51,38 +43,39 @@ Leaving out the `var` statement inside the function `test` will override the value of `foo`. While this might not seem like a big deal at first, having thousands of lines of JavaScript and not using `var` will introduce horrible, hard-to-track-down bugs. +在函數 `test` 中部使用 `var` 會覆蓋到原本在外面的 `foo`。 +雖然看起來不是什麼大問題,但是當程式有幾千行的時候沒有使用 `var` 會照成難以追蹤的臭蟲。 + - // global scope + // 全域作用域 var items = [/* some list */]; for(var i = 0; i < 10; i++) { subLoop(); } function subLoop() { - // scope of subLoop - for(i = 0; i < 10; i++) { // missing var statement - // do amazing stuff! + // subLoop 的作用域 + for(i = 0; i < 10; i++) { // 缺少了 var + // 做一些事情 } } -The outer loop will terminate after the first call to `subLoop`, since `subLoop` -overwrites the global value of `i`. Using a `var` for the second `for` loop would -have easily avoided this error. The `var` statement should **never** be left out -unless the *desired effect* is to affect the outer scope. +在外面的迴圈在呼叫第一次 `subLoop` 之後就會停止,因為 `subLoop` 全域變數中的 `i` 被覆蓋了。 +在第二次使用 `for` 迴圈的時候,使用 `var` 就可以避免這種錯誤。 +在宣告變數的時候 **絕對不要** 忘記 `var`,除非就是 `希望他的效果` 是取改變外部的作用域。 -### Local Variables +### 局部變數 -The only source for local variables in JavaScript are -[function](#function.general) parameters and variables declared via the -`var` statement. +在 javascript 中能用兩種方式來宣告局部變數。 +[函式](#function.general) 參數和透過 `var` 來宣告變數。 - // global scope + // 全域變數 var foo = 1; var bar = 2; var i = 2; function test(i) { - // local scope of the function test + // 函式 test 內部的局部作用域 i = 5; var foo = 3; @@ -90,13 +83,11 @@ The only source for local variables in JavaScript are } test(10); -While `foo` and `i` are local variables inside the scope of the function `test`, -the assignment of `bar` will override the global variable with the same name. +`foo` 和 `i` 是它的局部變數在 `test` 函式中,但是在 `bar` 的賦值會覆蓋全區域的作用域內的同名變數。 -### Hoisting +### 變數宣告 -JavaScript **hoists** declarations. This means that both `var` statements and -`function` declarations will be moved to the top of their enclosing scope. +JavaScript 會 **提昇** 變數宣告, 這代表著 `var` 和 `function` 的圈告都會被提升到當前作用域的頂端。 bar(); var bar = function() {}; @@ -115,16 +106,14 @@ JavaScript **hoists** declarations. This means that both `var` statements and } } -The above code gets transformed before execution starts. JavaScript moves -the `var` statements, as well as `function` declarations, to the top of the -nearest surrounding scope. +在上面的程式碼會被轉化在執行之前。 JavaScript 會把 `var`,和 `function` 宣告,放到最頂端最接近的作用區間 - // var statements got moved here - var bar, someValue; // default to 'undefined' + // var 被移到這裡 + var bar, someValue; // 值等於 'undefined' - // the function declaration got moved up too + // function 的宣告也被搬上來 function test(data) { - var goo, i, e; // missing block scope moves these here + var goo, i, e; // 沒有作用域的也被搬至頂端 if (false) { goo = 1; @@ -136,87 +125,72 @@ nearest surrounding scope. } } - bar(); // fails with a TypeError since bar is still 'undefined' - someValue = 42; // assignments are not affected by hoisting + bar(); // 出錯:TypeError , bar 還是 'undefined' + someValue = 42; // 賦值語句不會被提昇規則影響 bar = function() {}; test(); -Missing block scoping will not only move `var` statements out of loops and -their bodies, it will also make the results of certain `if` constructs -non-intuitive. +沒有作用域區間不只會把 `var` 放到迴圈之外,還會使得 `if` 表達式更難看懂。 -In the original code, although the `if` statement seemed to modify the *global -variable* `goo`, it actually modifies the *local variable* - after hoisting -has been applied. +在一般的程式中,雖然 `if` 表達式中看起來修改了 *全域變數* `goo`,但實際上在提昇規則被運用後,卻是在修改 *局部變數* -Without knowledge of *hoisting*, one might suspect the code below would raise a -`ReferenceError`. +如果沒有提昇規則的話,可能會出現像下面的看起來會出現 `ReferenceError` 的錯誤。 - // check whether SomeImportantThing has been initialized + // 檢查 SomeImportantThing 是否已經被初始化 if (!SomeImportantThing) { var SomeImportantThing = {}; } -But of course, this works due to the fact that the `var` statement is being -moved to the top of the *global scope*. +但是它沒有錯誤,因為 `var` 的表達式會被提升到 *全域作用域* 的頂端。 var SomeImportantThing; - // other code might initialize SomeImportantThing here, or not + // 有些程式,可能會初始化。 + SomeImportantThing here, or not - // make sure it's there + // 檢查是否已經被初始化。 if (!SomeImportantThing) { SomeImportantThing = {}; } -### Name Resolution Order - -All scopes in JavaScript, including the *global scope*, have the special name -[`this`](#function.this), defined in them, which refers to the *current object*. +### 名稱解析順序 + +JavaScript 中所有的作用區,包括 *全域作用域*,都有一個特殊的名字 [`this`](#function.this), 在它們裡面被定義,指向當前的物件 -Function scopes also have the name [`arguments`](#function.arguments), defined in -them, which contains the arguments that were passed to the function. +函式作用域也有一個名稱叫做 [`arguments`](#function.arguments), 定義它們,其中包括傳到函式內的參數。 -For example, when trying to access a variable named `foo` inside the scope of a -function, JavaScript will look up the name in the following order: +例如,它們開始試著進入到 `foo` 的作用域裡面, JavaScript 會依照下面的順序去查詢: - 1. In case there is a `var foo` statement in the current scope, use that. - 2. If one of the function parameters is named `foo`, use that. - 3. If the function itself is called `foo`, use that. - 4. Go to the next outer scope, and start with **#1** again. + 1. 當作用域內是否有 `var foo` 的定義。 + 2. 函式形式參數是否有使用 `foo` 名稱定義。 + 3. 函式自身是剖叫做 `foo`。 + 4. 回溯到上一個層級然後再從第一個開始往下去查。 -> **Note:** Having a parameter called `arguments` will **prevent** the creation -> of the default `arguments` object. +> **注意: ** 自定義 `arguments` 參數會阻止原生的 `arguments` 的物件創立 -### Namespaces +### 命名空間 -A common problem associated with having only one global namespace is the -likelihood of running into problems where variable names clash. In JavaScript, -this problem can easily be avoided with the help of *anonymous wrappers*. +只有一個全域作用域會導致常見的錯誤是命名衝突。在 JavaScript 中可以透過 *匿名包裝器* 來解決。 (function() { - // a self contained "namespace" + // 自己本身的匿名空間 window.foo = function() { - // an exposed closure + // 對外公開的函式 }; - })(); // execute the function immediately + })(); // 馬上執行這個匿名函式 +匿名函式被認為是 [表達式](#function.general)因此為了要可以調用,它們會先被執行。 -Unnamed functions are considered [expressions](#function.general); so in order to -being callable, they must first be evaluated. - - ( // evaluate the function inside the parentheses + ( // 小括號內的先被執行 function() {} - ) // and return the function object - () // call the result of the evaluation + ) // 回傳函數對象 + () // 調用上面的執行結果 -There are other ways to evaluate and directly call the function expression -which, while different in syntax, behave the same way. +還有其他方式也可以像上面一樣調用函式的方式達到 - // A few other styles for directly invoking the !function(){}() +function(){}() (function(){}()); @@ -224,10 +198,6 @@ which, while different in syntax, behave the same way. ### 結語 -It is recommended to always use an *anonymous wrapper* to encapsulate code in -its own namespace. This does not only protect code against name clashes, but it -also allows for better modularization of programs. - -Additionally, the use of global variables is considered **bad practice**. **Any** -use of them indicates badly written code that is prone to errors and hard to maintain. +建議最好是都用 *匿名包裝器* 來封裝你的程式碼在自己的命名區間內。這不僅是要防止命名衝突也可以使得程序更有模組化。 +另外,全域變數是個 **不好的** 習慣,因為它會帶來錯誤和更難去維護。 \ No newline at end of file diff --git a/site/zh-TW/index.html b/site/zh-TW/index.html index 8ae0e924..94c2d741 100644 --- a/site/zh-TW/index.html +++ b/site/zh-TW/index.html @@ -1,7 +1,7 @@ -JavaScript Garden -

Intro

JavaScript Garden is a growing collection of documentation about the most +

簡介

JavaScript Garden is a growing collection of documentation about the most quirky parts of the JavaScript programming language. It gives advice to avoid common mistakes and subtle bugs, as well as performance issues and bad practices, that non-expert JavaScript programmers may encounter on their @@ -34,7 +34,7 @@

License

JavaScript Garden is published under the MIT license and hosted on GitHub. If you find errors or typos please file an issue or a pull request on the repository. You can also find us in the JavaScript room on -Stack Overflow chat.

Objects

Object Usage and Properties

Everything in JavaScript acts like an object, with the only two exceptions being +Stack Overflow chat.

物件

Object Usage and Properties

Everything in JavaScript acts like an object, with the only two exceptions being null and undefined.

false.toString(); // 'false'
@@ -357,105 +357,94 @@ 

License

It is recommended to always use hasOwnProperty. Assumptions should never be made about the environment the code is running in, or whether the native -prototypes have been extended or not.

Functions

Function Declarations and Expressions

Functions in JavaScript are first class objects. That means they can be -passed around like any other value. One common use of this feature is to pass -an anonymous function as a callback to another, possibly an asynchronous function.

+prototypes have been extended or not.

函式

函式的宣告和表達方式

函式在 JavaScript 是第一等物件。這表示他們可以把函式當做值一樣傳遞。 +一個常見的用法是用 匿名函式 當做一個回傳去呼叫另一個函式,這是一種非同步函式

-

The function Declaration

+

函式的宣告

function foo() {}
 
-

The above function gets hoisted before the execution of the -program starts; thus, it is available everywhere in the scope it was -defined, even if called before the actual definition in the source.

+

上面的函式在被執行之前會被 解析(hoisted),因此它可以在 任意 的地方都是 有宣告的 ,就算是在比這個函式還早呼叫。

-
foo(); // Works because foo was created before this code runs
+
foo(); // 可以執行,因為 foo 已經在運行前就被建立
 function foo() {}
 
-

The function Expression

+

function 的表達式

var foo = function() {};
 
-

This example assigns the unnamed and anonymous function to the variable foo.

+

這個例子把一個 匿名 函式賦值給變數 foo

foo; // 'undefined'
-foo(); // this raises a TypeError
+foo(); // 錯誤: TypeError
 var foo = function() {};
 
-

Due to the fact that var is a declaration that hoists the variable name foo -before the actual execution of the code starts, foo is already defined when -the script gets executed.

+

由於 var 已經宣告變數 foo 在所有的程式碼執行之前。 +所以 foo已經在程式運行前就已經被定義過了。 +但是因為賦值只會在運行時去職情,所以在程式碼執行前,foo 的值還沒被宣告所以為 undefined

-

But since assignments only happen at runtime, the value of foo will default -to undefined before the corresponding code is executed.

+

命名函式的賦值表達式

-

Named Function Expression

- -

Another special case is the assignment of named functions.

+

另一個特殊狀況就勢將一個命名函式賦值給一個變數。

var foo = function bar() {
-    bar(); // Works
+    bar(); // 可以運行
 }
-bar(); // ReferenceError
+bar(); // 錯誤:ReferenceError
 
-

Here, bar is not available in the outer scope, since the function only gets -assigned to foo; however, inside of bar, it is available. This is due to -how name resolution in JavaScript works, the name of the -function is always made available in the local scope of the function itself.

How this Works

JavaScript has a different concept of what the special name this refers to -than most other programming languages. There are exactly five different -ways in which the value of this can be bound in the language.

+

bar 不可以在外部的區域被執行,因為它只有在 foo 的函式內才可以去執行。 +然而在 bar 內部還是可以看見。這是由於 JavaScript的 命名處理所致。 +函式名在函式內 可以去使用。

this 的工作原理

JavaScript 有移到完全部屬於其他語言處理 this 的處理機制。 +在 種物同的情況下, this 指向的個不相同

-

The Global Scope

+

全域變數

this;
 
-

When using this in global scope, it will simply refer to the global object.

+

如果再全域範圍內使用 this,會指向 全域 的物件

-

Calling a Function

+

呼叫一個函式

foo();
 
-

Here, this will again refer to the global object.

+

這裡 this 也會指向 全域 對象。

-

Calling a Method

+

方法調用

test.foo(); 
 
-

In this example, this will refer to test.

+

這個例子中, this 指向 test 物件。

-

Calling a Constructor

+

呼叫一個建構函式

new foo(); 
 
-

A function call that is preceded by the new keyword acts as -a constructor. Inside the function, this will refer -to a newly created Object.

+

如果函式傾向用 new 關鍵詞使用,我們稱這個函式為 建構函式。 +在函式內部, this 指向 新物件的創立

-

Explicit Setting of this

+

顯示的設置 this

function foo(a, b, c) {}
 
 var bar = {};
-foo.apply(bar, [1, 2, 3]); // array will expand to the below
-foo.call(bar, 1, 2, 3); // results in a = 1, b = 2, c = 3
+foo.apply(bar, [1, 2, 3]); // Array 會被擴展,如下所示
+foo.call(bar, 1, 2, 3); // 傳遞參數 a = 1, b = 2, c = 3
 
-

When using the call or apply methods of Function.prototype, the value of -this inside the called function gets explicitly set to the first argument -of the corresponding function call.

+

當使用 function.prototype 上的 call 或只 apply 方法時,函式內的 this 將會被 顯示設置 為函式調用的第一個參數。

As a result, in the above example the method case does not apply, and this inside of foo will be set to bar.

@@ -466,7 +455,7 @@

License

obj, since this only gets bound by one of the five listed cases.

-

Common Pitfalls

+

常見誤解

While most of these cases make sense, the first can be considered another mis-design of the language because it never has any practical use.

@@ -523,12 +512,11 @@

License

When method gets called on an instance of Bar, this will now refer to that -very instance.

Closures and References

One of JavaScript's most powerful features is the availability of closures. -With closures, scopes always keep access to the outer scope, in which they -were defined. Since the only scoping that JavaScript has is -function scope, all functions, by default, act as closures.

+very instance.

Closures 和 References

JavaScript 有一個很重要的特徵就是 closures +因為有 Closures,所以作用域 永遠 能夠去訪問作用區間外面的變數。 +函數區間 是JavaScript 中唯一擁有自生作用域的結構,因此 Closures 的創立需要依賴函數

-

Emulating private variables

+

模仿私有變數

function Counter(start) {
     var count = start;
@@ -548,16 +536,12 @@ 

License

foo.get(); // 5
-

Here, Counter returns two closures: the function increment as well as -the function get. Both of these functions keep a reference to the scope of -Counter and, therefore, always keep access to the count variable that was -defined in that scope.

+

這裡,Counter 返回兩個 Closures,函數 increment 還有 get。這兩個函數都維持著對外部作用域 Counter 的引用,因此總可以訪問作用域的變數 count

-

Why Private Variables Work

+

為什麼不可以在外部訪問私有變數

-

Since it is not possible to reference or assign scopes in JavaScript, there is -no way of accessing the variable count from the outside. The only way to -interact with it is via the two closures.

+

因為 Javascript 不可以 對作用域進行引用或賦值。因此外部的地方沒有辦法訪問 count 變數。 +唯一的途徑就是經過那兩個 Closures

var foo = new Counter(4);
 foo.hack = function() {
@@ -565,14 +549,11 @@ 

License

};
-

The above code will not change the variable count in the scope of Counter, -since foo.hack was not defined in that scope. It will instead create - or -override - the global variable count.

+

在上面的例子中 count 不會 改變到 Counter 裡面的 count 的值。因為 foo.hack 沒有在 那個 作用域內被宣告。它只有會覆蓋或者建立在一個 全域 的變數 count

-

Closures Inside Loops

+

在循環內的 Closures

-

One often made mistake is to use closures inside of loops, as if they were -copying the value of the loop's index variable.

+

一個常見的錯誤就是在 Closures 中使用迴圈,假設我們要使用每次迴圈中所使用的進入變數

for(var i = 0; i < 10; i++) {
     setTimeout(function() {
@@ -581,20 +562,14 @@ 

License

}
-

The above will not output the numbers 0 through 9, but will simply print -the number 10 ten times.

- -

The anonymous function keeps a reference to i. At the time -console.log gets called, the for loop has already finished, and the value of -i as been set to 10.

+

在上面的例子中它 不會 輸出數字從 09,但只會出現數字 10 十次。 +在 console.log 被呼叫的時候,這個 匿名 函數中保持一個 參考 到 i ,此時 for迴圈已經結束, i 的值被修改成了 10。 +為了要達到想要的結果,需要在每次創造 副本 來儲存 i 的變數。

-

In order to get the desired behavior, it is necessary to create a copy of -the value of i.

+

避免引用錯誤

-

Avoiding the Reference Problem

- -

In order to copy the value of the loop's index variable, it is best to use an -anonymous wrapper.

+

為了要有達到正確的效果,最好是把它包在一個 +匿名函數.

for(var i = 0; i < 10; i++) {
     (function(e) {
@@ -605,15 +580,9 @@ 

License

}
-

The anonymous outer function gets called immediately with i as its first -argument and will receive a copy of the value of i as its parameter e.

- -

The anonymous function that gets passed to setTimeout now has a reference to -e, whose value does not get changed by the loop.

- -

There is another possible way of achieving this, which is to return a function -from the anonymous wrapper that will then have the same behavior as the code -above.

+

匿名外部的函數被呼叫,並把 i 作為它第一個參數,此時函數內 e 變數就擁有了一個 i 的拷貝。 +當傳遞給 setTimeout 這個匿名函數執行時,它就擁有了對 e 的引用,而這個值 不會 被循環改變。 +另外有一個方法也可以完成這樣的工作,那就是在匿名函數中返回一個函數,這和上面的程式碼有同樣的效果。

for(var i = 0; i < 10; i++) {
     setTimeout((function(e) {
@@ -724,16 +693,13 @@ 

License

強烈建議不要使用 arguments.callee 或是其他它的屬性

Constructors

Constructors in JavaScript are yet again different from many other languages. Any -function call that is preceded by the new keyword acts as a constructor.

- -

Inside the constructor - the called function - the value of this refers to a -newly created object. The prototype of this new -object is set to the prototype of the function object that was invoked as the -constructor.

+

建構函式

JavaScript 中的建構函式和其他語言中的建構函式是不同的。 +用 new 的關鍵字方式調用的函式都被認為是建構函式。 +在建構函式內部 - 被呼叫的函式 - this 指向一個新建立的 objectprototype 這是一個新的物件一個被指向函式的 prototype 的建構函式。

If the function that was called has no explicit return statement, then it -implicitly returns the value of this - the new object.

+implicitly returns the value of this - the new object. +如果被使用的函式沒有明顯的呼叫 return 的表達式,它會回傳一個隱性的 this 的新物件。

function Foo() {
     this.bla = 1;
@@ -746,16 +712,13 @@ 

License

var test = new Foo();
-

The above calls Foo as constructor and sets the prototype of the newly -created object to Foo.prototype.

- -

In case of an explicit return statement, the function returns the value -specified by that statement, but only if the return value is an Object.

+

在上面的例子中 Foo 建立一個建構函式,並設立一個 prototype 來創建一個新的物件叫 Foo.prototype。 +這個情況下它顯示的 return 一個表達式,但他 返回一個 Object

function Bar() {
     return 2;
 }
-new Bar(); // a new object
+new Bar(); // 返回一個新物件
 
 function Test() {
     this.value = 2;
@@ -764,25 +727,22 @@ 

License

foo: 1 }; } -new Test(); // the returned object +new Test(); // 回傳物件
-

When the new keyword is omitted, the function will not return a new object.

+

如果 new 的關鍵字被忽略,函式就 不會 回傳一個新的物件。

function Foo() {
-    this.bla = 1; // gets set on the global object
+    this.bla = 1; // 獲取一個全域的參數
 }
 Foo(); // undefined
 
-

While the above example might still appear to work in some cases, due to the -workings of this in JavaScript, it will use the -global object as the value of this.

+

雖然上面有些情況也能正常運行,但是由於 JavaScript 中 this 的工作原理,這裡的 this 指向 全域對象

-

Factories

+

工廠模式

-

In order to be able to omit the new keyword, the constructor function has to -explicitly return a value.

+

為了不使用 new 關鍵字,建構函式必須顯性的返回一個值。

function Bar() {
     var value = 1;
@@ -800,24 +760,16 @@ 

License

Bar();
-

Both calls to Bar return the same thing, a newly create object that -has a property called method, which is a -Closure.

+

上面兩個呼叫 Bar 的方法回傳的值都一樣,一個新創建的擁有 method 屬性被返回,這裡創建了一個 Closure.

-

It should also be noted that the call new Bar() does not affect the -prototype of the returned object. While the prototype will be set on the newly -created object, Bar never returns that new object.

+

還有注意, new Bar()不會 改變返回物件的原型。 +因為建構函式的原型會指向剛剛創立的新物件,而在這裡的 Bar 沒有把這個新物件返回。 +在上面的例子中,使用或者不使用 new 關鍵字沒有什麼功能性的區別

-

In the above example, there is no functional difference between using and -not using the new keyword.

+

通過工廠模式創建的新對象

-

Creating New Objects via Factories

- -

It is often recommended to not use new because forgetting its use may -lead to bugs.

- -

In order to create a new object, one should rather use a factory and construct a -new object inside of that factory.

+

常聽到建議 不要 使用 new,因為如果忘記如何使用它會造成錯誤。 +為了創建一個新的物件,我們可以用工廠方法,來創造一個新的物件在那個方法中。

function Foo() {
     var obj = {};
@@ -835,32 +787,23 @@ 

License

}
-

While the above is robust against a missing new keyword and certainly makes -the use of private variables easier, it comes with some -downsides.

+

雖然上面的方式比起 new 的調用方式更不容易出錯,並且可以充分的使用 私有變數所帶來的便利,但是還是有一些不好的地方

    -
  1. It uses more memory since the created objects do not share the methods -on a prototype.
  2. -
  3. In order to inherit, the factory needs to copy all the methods from another -object or put that object on the prototype of the new object.
  4. -
  5. Dropping the prototype chain just because of a left out new keyword -is contrary to the spirit of the language.
  6. +
  7. 會占用更多的記憶體,因為創建的物件 沒有 辦法放在在同一個原型上。
  8. +
  9. 為了要用繼承的方式,工廠方法需要複製所有的屬性或是把一個物件作為新的物件的原型。
  10. +
  11. 放棄原型鏈僅僅是因為防止遺漏 new 所帶來的問題,這與語言本身的思想鄉違背。
-

In Conclusion

+

結語

-

While omitting the new keyword might lead to bugs, it is certainly not a -reason to drop the use of prototypes altogether. In the end it comes down to -which solution is better suited for the needs of the application. It is -especially important to choose a specific style of object creation and use it -consistently.

Scopes and Namespaces

Although JavaScript deals fine with the syntax of two matching curly -braces for blocks, it does not support block scope; hence, all that is left -in the language is function scope.

- -
function test() { // a scope
-    for(var i = 0; i < 10; i++) { // not a scope
-        // count
+

雖然遺漏 new 關鍵字可能會導致問題,但這並 不是 放棄只用原型的藉口。 +最終使用哪種方式取決於應用程式的需求,選擇一種程式語言風格並堅持下去才是最重要的。

作用域和命名空間

儘管 JavaScript 支持一個大括號創建的程式碼,但並不支持塊級作用域。 +而僅僅支援 函式作用域

+ +
function test() { // 一個作用域
+    for(var i = 0; i < 10; i++) { // 不是一個作用域
+        // 算數
     }
     console.log(i); // 10
 }
@@ -880,7 +823,7 @@ 

License

the scopes until it finds it. In the case that it reaches the global scope and still has not found the requested name, it will raise a ReferenceError.

-

The Bane of Global Variables

+

全域變數的壞處

// script A
 foo = '42';
@@ -1093,14 +1036,14 @@ 

License

// and so on...
-

In Conclusion

+

結語

It is recommended to always use an anonymous wrapper to encapsulate code in its own namespace. This does not only protect code against name clashes, but it also allows for better modularization of programs.

Additionally, the use of global variables is considered bad practice. Any -use of them indicates badly written code that is prone to errors and hard to maintain.

Arrays

Array 迴圈和屬性

雖然在 Javascript 中 Array 都是 Objects,但是沒有好的理由要使用他 +use of them indicates badly written code that is prone to errors and hard to maintain.

陣列

Array 迴圈和屬性

雖然在 Javascript 中 Array 都是 Objects,但是沒有好的理由要使用他 在 for in 的迴圈中。事實上有很多原因要避免使用 for in 在 Array 之中

結語

-

Array 的建構函式需要避免,建議使用字面語法。因為他們比較簡短、也更增加閱讀性

Types

Equality and Comparisons

JavaScript has two different ways of comparing the values of objects for equality.

+

Array 的建構函式需要避免,建議使用字面語法。因為他們比較簡短、也更增加閱讀性

類型

Equality and Comparisons

JavaScript has two different ways of comparing the values of objects for equality.

The Equality Operator

@@ -1440,7 +1383,7 @@

License

!!'-1' // true !!{}; // true !!true; // true -

Core

為什麼不要使用 eval

因為 eval 函數會在 Javascript 的區域性的區間執行那段程式碼。

+

核心

為什麼不要使用 eval

因為 eval 函數會在 Javascript 的區域性的區間執行那段程式碼。

var foo = 1;
 function test() {
@@ -1728,7 +1671,7 @@ 

License

In conclusion

The delete operator often has unexpected behaviour and can only be safely -used to delete explicitly set properties on normal objects.

Other

setTimeout and setInterval

Since JavaScript is asynchronous, it is possible to schedule the execution of a +used to delete explicitly set properties on normal objects.

其他

setTimeout and setInterval

Since JavaScript is asynchronous, it is possible to schedule the execution of a function using the setTimeout and setInterval functions.