Skip to content
This repository
Browse code

Merge pull request #108 from dogfeet/ko

Korean Translation
  • Loading branch information...
commit a6cdc5e6c14c47aa6d743751d205720d6e9c7789 2 parents 4a93411 + 39f0b9f
Zhang Yi Jiang ZhangYiJiang authored
24 doc/ko/array/constructor.md
Source Rendered
... ... @@ -0,0 +1,24 @@
  1 +## `Array` 생성자
  2 +
  3 +`Array` 생성자가 파라미터를 처리하는 방법은 모호하기 때문에 항상 `[]` 노테이션으로 Array를 만들어야 한다.
  4 +
  5 + [1, 2, 3]; // Result: [1, 2, 3]
  6 + new Array(1, 2, 3); // Result: [1, 2, 3]
  7 +
  8 + [3]; // Result: [3]
  9 + new Array(3); // Result: []
  10 + new Array('3') // Result: ['3']
  11 +
  12 +`Array` 생성자에 인자로 숫자 하나를 넘기면 생성자는 `length`가 그 숫자인 텅 빈 `Array` 하나를 반환한다. 생성자는 **오직** `length` 프로퍼티에 할당하기만 하고 실제 `Array`는 초기화하지 않는다는 것을 기억해야 한다.
  13 +
  14 + var arr = new Array(3);
  15 + arr[1]; // undefined
  16 + 1 in arr; // false, 이 인덱스는 초기화되지 않음.
  17 +
  18 +Array의 length 프로퍼티에 숫자를 할당해주는 이 기능이 유용할 때도 있긴 있다. `for loop`을 사용하지 않고 스트링을 더하는 경우가 그렇다.
  19 +
  20 + new Array(count + 1).join(stringToRepeat);
  21 +
  22 +### 결론
  23 +
  24 +`Array` 생성자는 가능하면 사용하지 말아야 한다. `[]` 노테이션이 더 알맞다. 더 간략하고 명확하기 때문에 보기도 좋다.
39 doc/ko/array/general.md
Source Rendered
... ... @@ -0,0 +1,39 @@
  1 +## Array Iteration과 프로퍼티
  2 +
  3 +JavaScript에서는 Array도 객체지만 Iterate를 할 때 [`for in`](#object.forinloop)을 사용해서 좋을 게 없다.
  4 +
  5 +> **Note:** JavaScript의 Array는 *Associative Array*가 **아니다**. JavaScript [객체](#object.general)는 key/value만 mapping 할 뿐이다. Associative Array는 순서를 보장하지만, 객체는 보장하지 않는다.
  6 +
  7 +`for in`은 프로토타입 체인에 있는 프로퍼티를 모두 훑는(enumerate) 데다가 객체 자신의 프로퍼티만 훑으려면 [`hasOwnProperty`](#object.hasownproperty)를 사용해야 하기 때문에 `for`보다 20배 느리다.
  8 +
  9 +### Iteration
  10 +
  11 +Array를 Iterate 할 때에는 구식인 `for`를 사용하는 것이 가장 빠르다.
  12 +
  13 + var list = [1, 2, 3, 4, 5, ...... 100000000];
  14 + for(var i = 0, l = list.length; i < l; i++) {
  15 + console.log(list[i]);
  16 + }
  17 +
  18 +위 예제에서 꼭 기억해야 하는 것은 `l = list.length`로 Array의 length 값을 캐시 했다는 것이다.
  19 +
  20 +Array에 있는 `length` 프로퍼티를 iterate마다 사용하는 것은 좀 부담스럽다. 최신 JavaScript 엔진은 이 일을 알아서 처리하기도 하지만 코드가 새 엔진에서 실행되도록 보장할 방법이 없다.
  21 +
  22 +실제로 캐시 하지 않으면 성능이 반으로 줄어든다.
  23 +
  24 +### `length` 프로퍼티
  25 +
  26 +`length` 프로퍼티의 *getter*는 단순히 Array 안에 있는 엘리먼트의 개수를 반환하고 *setter*는 할당한 수로 Array를 잘라 버린다.
  27 +
  28 + var foo = [1, 2, 3, 4, 5, 6];
  29 + foo.length = 3;
  30 + foo; // [1, 2, 3]
  31 +
  32 + foo.length = 6;
  33 + foo; // [1, 2, 3]
  34 +
  35 +현재 크기보다 더 작은 값을 할당하면 Array를 자르지만, 현재 크기보다 더 큰 값을 할당하면 아무것도 하지 않는다.
  36 +
  37 +### 결론
  38 +
  39 +최적의 성능을 위해서 `for`를 사용하고 `length` 프로퍼티 값을 캐시 하길 바란다. Array에 `for in`을 사용하면 성능도 떨어지고 버그 나기도 쉽다.
76 doc/ko/core/delete.md
Source Rendered
... ... @@ -0,0 +1,76 @@
  1 +## `delete`
  2 +
  3 +간단히 말해서 global 변수, 함수, 등은 `DontDelete` 속성이기 때문에 삭제 못 한다.
  4 +
  5 +### Global 코드와 함수 코드
  6 +
  7 +Global이나 Function scope에 정의된 함수나 변수는 모두 Activation 객체나 Global 객체의 프로퍼티다. 이 프로퍼티는 모두 `DontDelete`속성을 가진다. Global이나 Function 코드에서 변수나 함수의 정의하면 항상 `DontDelete` 프로퍼티로 만들어진다. 그러니까 삭제할 수 없다:
  8 +
  9 + // Global 변수:
  10 + var a = 1; // DontDelete가 설정된다.
  11 + delete a; // false
  12 + a; // 1
  13 +
  14 + // 함수:
  15 + function f() {} // DontDelete가 설정된다.
  16 + delete f; // false
  17 + typeof f; // "function"
  18 +
  19 + // 다시 할당해도 삭제할 수 없다:
  20 + f = 1;
  21 + delete f; // false
  22 + f; // 1
  23 +
  24 +### Explicit 프로퍼티
  25 +
  26 +다음 예제에서 만드는 property는 정상적으로 지워진다. 이런 걸 Explicit 프로퍼티라고 부른다:
  27 +
  28 + // Explicit 프로퍼티를 만든다:
  29 + var obj = {x: 1};
  30 + obj.y = 2;
  31 + delete obj.x; // true
  32 + delete obj.y; // true
  33 + obj.x; // undefined
  34 + obj.y; // undefined
  35 +
  36 +`obj.x`와 `obj.y`는 `DontDelete` 속성이 아녀서 삭제된다. 그러나 다음과 같은 코드도 잘 동작하기 때문에 헷갈린다.:
  37 +
  38 + // IE를 빼고 잘 동작한다.:
  39 + var GLOBAL_OBJECT = this;
  40 + GLOBAL_OBJECT.a = 1;
  41 + a === GLOBAL_OBJECT.a; // true - 진짜 Global 변순지 확인하는 것
  42 + delete GLOBAL_OBJECT.a; // true
  43 + GLOBAL_OBJECT.a; // undefined
  44 +
  45 +[`this`](#function.this)가 Global 객체를 가리키는 것을 이용해서 명시적으로 프로퍼티 `a`를 선언하면 삭제할 수 있다. 이런 꼼수가 가능하다.
  46 +
  47 +IE (적어도 6-8)는 버그가 있어서 안 된다.
  48 +
  49 +### arguments와 함수의 기본 프로퍼티
  50 +
  51 +함수의 [`arguments` 객체](#function.arguments)와 built-in 프로퍼티도 `DontDelete` 속성이다.
  52 +
  53 + // 함수의 arguments와 프로퍼티:
  54 + (function (x) {
  55 +
  56 + delete arguments; // false
  57 + typeof arguments; // "object"
  58 +
  59 + delete x; // false
  60 + x; // 1
  61 +
  62 + function f(){}
  63 + delete f.length; // false
  64 + typeof f.length; // "number"
  65 +
  66 + })(1);
  67 +
  68 +### Host 객체
  69 +
  70 +(역주, Host 객체들은 document같은 DOM 객체를 말한다.)
  71 +
  72 +Host 객체를 delete하면 어떻게 될지 알 수 없다. 어떻게 Host 객체를 delete해야 하는지 표준에 정의되지 않았다.
  73 +
  74 +### 결론
  75 +
  76 +`delete` 연산자는 엉뚱하게 동작할 때가 잦다. 명시적으로 정의한 일반 객체의 프로퍼티만 delete하는 것이 안전하다.
38 doc/ko/core/eval.md
Source Rendered
... ... @@ -0,0 +1,38 @@
  1 +## 왜 `eval`을 사용하면 안 될까?
  2 +
  3 +`eval` 함수는 스트링으로 된 JavaScript 코드를 Local Scope에서 실행한다.
  4 +
  5 + var foo = 1;
  6 + function test() {
  7 + var foo = 2;
  8 + eval('foo = 3');
  9 + return foo;
  10 + }
  11 + test(); // 3
  12 + foo; // 1
  13 +
  14 +`eval`을 `eval`이라는 이름으로 **직접** 직행할 때에만 Local Scope에서 실행된다.
  15 +
  16 + var foo = 1;
  17 + function test() {
  18 + var foo = 2;
  19 + var bar = eval;
  20 + bar('foo = 3');
  21 + return foo;
  22 + }
  23 + test(); // 2
  24 + foo; // 3
  25 +
  26 +어쨌든 `eval`은 사용하지 말아야 한다. eval을 사용하는 경우의 99.9%는 사실 eval이 필요 없다.
  27 +
  28 +### 가짜 `eval`
  29 +
  30 +[timeout functions](#other.timeouts)인 `setTimeout`과 `setInterval`은 첫 번째 인자로 스트링을 입력받을 수 있다. 이 경우에는 `eval`을 직접 호출하는 것이 아녀서 항상 global scope에서 실행된다.
  31 +
  32 +### 보안 이슈
  33 +
  34 +`eval`은 보안 문제도 있다. 단순히 **모든** 코드를 실행하기 때문에 신뢰하지 못하는 코드가 **절대로** 포함되지 않도록 주의해야 한다.
  35 +
  36 +### 결론
  37 +
  38 +`eval`은 사용하지 않는 게 좋다. `eval`을 사용하는 모든 코드는 성능, 보안, 버그의 문제를 일으킬 수 있다. 만약 `eval`이 필요해지면 *설계를 변경*하여 `eval`이 필요 없게 만들어야 한다.
99 doc/ko/core/semicolon.md
Source Rendered
... ... @@ -0,0 +1,99 @@
  1 +## 세미콜론을 자동으로 삽입해준다.
  2 +
  3 +JavaScript는 C와 문법이 비슷하지만, 꼭 코드에 semicolon을 사용하도록 강제하지 않는다. 그래서 생략할 수 있다.
  4 +
  5 +사실 JavaScript는 semicolon이 꼭 있어야 하고 없으면 이해하지 못한다. 그래서 JavaScript 파서는 semicolon이 없으면 **자동으로** semicolon을 추가한다.
  6 +
  7 + var foo = function() {
  8 + } // 세미콜론이 없으니 에러 난다.
  9 + test()
  10 +
  11 +파서는 세미콜론을 삽입하고 다시 시도한다.
  12 +
  13 + var foo = function() {
  14 + }; // 에러가 없어짐.
  15 + test()
  16 +
  17 +JavaScript에서 세미콜론을 자동으로 삽입한 것은 **대표적인** 설계 오류 중 하나다. 세미콜론 유무에 따라 *전혀* 다른 코드가 될 수 있다.
  18 +
  19 +### 어떻게 다를까?
  20 +
  21 +코드에 세미콜론이 없으면 파서가 어디에 넣을지 결정한다.
  22 +
  23 + (function(window, undefined) {
  24 + function test(options) {
  25 + log('testing!')
  26 +
  27 + (options.list || []).forEach(function(i) {
  28 +
  29 + })
  30 +
  31 + options.value.test(
  32 + 'long string to pass here',
  33 + 'and another long string to pass'
  34 + )
  35 +
  36 + return
  37 + {
  38 + foo: function() {}
  39 + }
  40 + }
  41 + window.test = test
  42 +
  43 + })(window)
  44 +
  45 + (function(window) {
  46 + window.someLibrary = {}
  47 +
  48 + })(window)
  49 +
  50 +파서는 다음과 같이 삽입한다.
  51 +
  52 + (function(window, undefined) {
  53 + function test(options) {
  54 +
  55 + // 세미콜론을 넣는 것이 아니라 줄을 합친다.
  56 + log('testing!')(options.list || []).forEach(function(i) {
  57 +
  58 + }); // <- 여기
  59 +
  60 + options.value.test(
  61 + 'long string to pass here',
  62 + 'and another long string to pass'
  63 + ); // <- 여기
  64 +
  65 + return; // <- 여기에 넣어서 그냥 반환시킨다.
  66 + { // 파서는 단순 블럭이라고 생각하고
  67 +
  68 + // 단순한 레이블과 함수
  69 + foo: function() {}
  70 + }; // <- 여기
  71 + }
  72 + window.test = test; // <- 여기
  73 +
  74 + // 이 줄도 합쳐진다.
  75 + })(window)(function(window) {
  76 + window.someLibrary = {}; // <- 여기
  77 +
  78 + })(window); //<- 여기에 파서는 세미콜론을 넣는다.
  79 +
  80 +> **주의:** JavaScript 파서는 new line 문자가 뒤따라 오는 return 구문을 제대로 처리하지 못한다. 자동으로 세미콜론을 넣는 것 자체의 문제는 아니지만 어쨌든 여전히 문제로 남아있다.
  81 +
  82 +파서는 완전히 다른 코드로 만들어 버린다. 이것은 **오류**다.
  83 +
  84 +### Parenthesis
  85 +
  86 +세미콜론 없이 괄호가 붙어 있으면 파서는 세미콜론을 넣지 않는다.
  87 +
  88 + log('testing!')
  89 + (options.list || []).forEach(function(i) {})
  90 +
  91 +파서는 다음과 같이 코드를 바꾼다.
  92 +
  93 + log('testing!')(options.list || []).forEach(function(i) {})
  94 +
  95 +`log` 함수가 함수를 반환할 가능성은 거의 없다. 아마도 `undefined is not a function`이라는 `TypeError`가 발생할 거다.
  96 +
  97 +### 결론
  98 +
  99 +세미콜론은 반드시 사용해야 한다. 그리고 `{}`도 생략하지 않고 꼭 사용하는 것이 좋다. 한 줄밖에 안 되는 `if` / `else` 블럭에서도 꼭 사용해야 한다. 이 두 가지 규칙을 잘 지키면 JavaScript 파서가 잘못 해석하는 일을 미리 방지하고 코드도 튼튼해진다.
52 doc/ko/core/undefined.md
Source Rendered
... ... @@ -0,0 +1,52 @@
  1 +## `undefined`와 `null`
  2 +
  3 +JavaScript는 `nothing`을 두 가지로 표현할 수 있고 그중 `undefined`가 더 유용하다.
  4 +
  5 +### `undefined`도 변수
  6 +
  7 +`undefined`는 `undefined`라는 값을 가지는 데이터 형식이다.
  8 +
  9 +`undefined`는 상수도 아니고 JavaScript의 키워드도 아니다. 그냥 `undefined`라는 이름의 Global 변수이고 이 변수에는 `undefined`라고 할당돼 있다. 그래서 이 Global 변수의 값을 쉽게 바꿀 수 있다.
  10 +
  11 +> **ES5 Note:** ECMAScript 5의 strict 모드에서는 `undefined`를 더는 바꿀 수 없도록 했다. 하지만 `undefined`라는 함수를 만들면 여전히 할당할 수 있다.
  12 +
  13 +`undefined` 값이 반환될 때:
  14 +
  15 + - global 변수 `undefined`에 접근할 때.
  16 + - `return` 구문이 없는 함수는 `undefined`를 반환함.
  17 + - `return` 구문으로 아무것도 반환하지 않을 때.
  18 + - 없는 프로퍼티를 찾을 때.
  19 + - 함수 인자가 생략될 때.
  20 + - `undefined`가 할당된 모든 것.
  21 +
  22 +### `undefined`가 바뀔 때를 대비하기
  23 +
  24 +global 변수 `undefined`는 `undefined`라는 객체를 가리키는 것뿐이기 때문에 새로운 값을 할당한다고 해도 `undefined`의 값 자체가 바뀌는 것이 아니다.
  25 +
  26 +그래서 `undefined`와 비교하려면 먼저 `undefined`의 값을 찾아와야 한다.
  27 +
  28 +보통 `undefined` 변수가 바뀌어 있을 때를 대비해서 undefined라는 변수를 인자로 받는 [anonymous wrapper](#function.scopes)로 감싸고 아무런 인자를 넘기지 않는 꼼수를 사용한다.
  29 +
  30 + var undefined = 123;
  31 + (function(something, foo, undefined) {
  32 + // Local Scope에 undefined를 만들어서
  33 + // 원래 값을 가리키도록 했다.
  34 +
  35 + })('Hello World', 42);
  36 +
  37 +wrapper 안에서 변수를 새로 정의하는 방법으로도 같은 효과를 볼 수 있다.
  38 +
  39 + var undefined = 123;
  40 + (function(something, foo) {
  41 + var undefined;
  42 + ...
  43 +
  44 + })('Hello World', 42);
  45 +
  46 +이 두 방법의 차이는 minified했을 때 4바이트만큼 차이 난다는 것과 한쪽은 wrapper 안에 var 구문이 없다는 것밖에 없다.
  47 +
  48 +### `Null` 객체의 용도
  49 +
  50 +JavaScript 언어에서는 `undefined`를 다른 언어에서 *null*을 사용하듯이 쓰고 진짜 `null`은 그냥 다른 데이터 타입 중 하나일 뿐이다.
  51 +
  52 +JavaScript 내부적인 곳에 사용하는 경우가 아니면 null 대신 `undefined`를 사용해도 된다(`Foo.prototype = null`같이 프로토타입 체인을 끊을 때는 null을 사용한다).
92 doc/ko/function/arguments.md
Source Rendered
... ... @@ -0,0 +1,92 @@
  1 +## `arguments` 객체
  2 +
  3 +JavaScript의 모든 Function Scope에는 `arguments`라는 특별한 변수가 있다. 이 변수는 함수에 넘겨진 모든 인자에 대한 정보가 담겨 있다.
  4 +
  5 +> **Note:** `arguments` 변수는 함수 안에서 다시 정의할 수 없다. `var` 구문이나 파라미터에 `arguments`라는 이름으로 변수를 정의해도 변수가 재정의되지 않는다.
  6 +
  7 +`length` 프로퍼티도 있고 대체로 Array와 비슷하게 생겼지만 Array.prototype을 상속받지 않았다. `arguments` 객체는 `Array`가 아니다.
  8 +
  9 +그래서 `arguments`에는 `push`, `pop`, `slice`같은 표준 메소드가 없다. `for`로 하는 iteration은 원래 잘되지만 `Array`의 메소드를 이용하려면 `arguments`를 Array로 변환해야 한다.
  10 +
  11 +### Array로 변환하기
  12 +
  13 +다음 코드는 arguments에 있는 객체를 새로운 Array에 담아 반환한다.
  14 +
  15 + Array.prototype.slice.call(arguments);
  16 +
  17 +이 변환 과정은 **느리기** 때문에 성능이 중요한 부분에 사용하는 것은 **별로 바람직하지** 못 하다.
  18 +
  19 +### arguemnts 객체 넘기기
  20 +
  21 +어떤 함수에서 다른 함수로 arguments 객체를 넘길 때에는 다음과 같이 하는 것이 좋다.
  22 +
  23 + function foo() {
  24 + bar.apply(null, arguments);
  25 + }
  26 + function bar(a, b, c) {
  27 + // 내곡동에 땅이라도 산다.
  28 + }
  29 +
  30 +`call`과 `apply`를 함께 사용하여 unbound wrapper도 쉽게 만들 수 있다.
  31 +
  32 + function Foo() {}
  33 +
  34 + Foo.prototype.method = function(a, b, c) {
  35 + console.log(this, a, b, c);
  36 + };
  37 +
  38 + // "method"의 unbound 버전
  39 + // 이 함수의 인자: this, arg1, arg2...argN
  40 + Foo.method = function() {
  41 +
  42 + // 결과: Foo.prototype.method.call(this, arg1, arg2... argN)
  43 + Function.call.apply(Foo.prototype.method, arguments);
  44 + };
  45 +
  46 +### 파라미터로 선언한 것과 arguments 객체 인덱스
  47 +
  48 +`arguments` 객체의 프로퍼티와 파라미터는 모두 *getter*와 *setter*가 만들어진다.
  49 +
  50 +그래서 파라미터의 값이나 `arguments` 객체의 프로퍼티 중 하나를 바꾸면 같이 바뀐다.
  51 +
  52 + function foo(a, b, c) {
  53 + arguments[0] = 2;
  54 + a; // 2
  55 +
  56 + b = 4;
  57 + arguments[1]; // 4
  58 +
  59 + var d = c;
  60 + d = 9;
  61 + c; // 3
  62 + }
  63 + foo(1, 2, 3);
  64 +
  65 +### 성능에 대한 진실과 오해.
  66 +
  67 +`arguments`라는 이름의 변수를 함수 안에 정의하거나 파라미터로 정의해도 `arguments` 객체는 만들어진다.
  68 +
  69 +getter*와 *setter*는 항상 생성되기 때문에 getter/setter를 사용하는 것은 성능에 별 영향을 끼치지 않는다. 단순히 `arguments` 객체의 프로퍼티에 접근하는 수준이 아닌 실제 코드에서도 그렇다.
  70 +
  71 +> **ES5 Note:** strict 모드에서는 *getter*와 *setter*가 생성되지 않는다.
  72 +
  73 +그러나 예외도 있다. 최신 JavaScript 엔진에서 `arguments.callee`를 사용하면 성능이 확 떨어진다.
  74 +
  75 + function foo() {
  76 + arguments.callee; // 이 함수를 가리킨다.
  77 + arguments.callee.caller; // 이 함수를 호출한 함수를 가리킨다.
  78 + }
  79 +
  80 + function bigLoop() {
  81 + for(var i = 0; i < 100000; i++) {
  82 + foo(); // 원래 인라인 돼야 하는디...
  83 + }
  84 + }
  85 +
  86 +이 코드에서 callee와 caller를 알아야 하기 때문에 `foo`는 더는 [inlining][1]되지 않는다. 이렇게 쓰면 inlining이 주는 성능상 장점을 포기해야 하는데다가 함수가 호출되는 상황(calling context)에 의존하게 돼 버려서 encapsulation도 해친다.
  87 +
  88 +`arguments.callee`와 그 프로퍼티들은 **절대** 사용하지 말아야 한다.
  89 +
  90 +> **ES5 Note:** strict 모드에서 `arguments.callee`는 deprecated됐기 때문에 사용하면 `TypeError`가 난다.
  91 +
  92 +[1]: http://en.wikipedia.org/wiki/Inlining
77 doc/ko/function/closures.md
Source Rendered
... ... @@ -0,0 +1,77 @@
  1 +## Closure와 Reference
  2 +
  3 +JavaScript가 두드러지는 점 중의 하나가 *Closure*를 사용할 수 있다는 것이다. Closure는 항상 그 Closure를 만든 외부 Scope에 접근할 수 있다. JavaScript에서 Scope을 만들려면 [function Scope](#function.scopes)을 사용하는 방법뿐이기 때문에 기본적으로 모든 함수는 Closure다.
  4 +
  5 +### private 변수
  6 +
  7 + function Counter(start) {
  8 + var count = start;
  9 + return {
  10 + increment: function() {
  11 + count++;
  12 + },
  13 +
  14 + get: function() {
  15 + return count;
  16 + }
  17 + }
  18 + }
  19 +
  20 + var foo = Counter(4);
  21 + foo.increment();
  22 + foo.get(); // 5
  23 +
  24 +`Counter`는 `increment` closure와 `get` closure를 두 개 반환한다. 이 두 closure는 `Counter` Scope에 대한 **reference**를 유지하고 있기 때문에 그 Scope에 있는 count 변수에 계속 접근할 수 있다.
  25 +
  26 +### Private 변수가 진짜 맞나?
  27 +
  28 +JavaScript에서 Scope을 어딘가에 할당하거나 저장해두는 것이 불가능해서 Scope 밖에서 count 변수에 직접 접근할 방법은 없다. 꼭 Scope 안에서 정의한 두 closure를 통해서만 접근할 수 있다.
  29 +
  30 + var foo = new Counter(4);
  31 + foo.hack = function() {
  32 + count = 1337;
  33 + };
  34 +
  35 +이 코드의 count는 `Counter` Scope의 변수 count가 아니다. `foo.hack`은 그 Scope 안에 정의되지 않았기 때문에 이 `count`는 *Global* 변수를 사용하는 것이다.
  36 +
  37 +### Loop에서 Closure 사용하기
  38 +
  39 +많은 사람은 Loop에서 closure를 사용할 때 자주 index 변수를 잘못 사용한다.
  40 +
  41 + for(var i = 0; i < 10; i++) {
  42 + setTimeout(function() {
  43 + console.log(i);
  44 + }, 1000);
  45 + }
  46 +
  47 +이 코드는 `0`부터 `9`까지의 수를 출력하지 않고 `10`만 열 번 출력한다.
  48 +
  49 +이 *anonymous* function은 변수 `i`에 대한 참조를 저장했다가 `console.log`가 호출되는 시점에 `i`의 값을 사용한다. `console.log`가 호출되는 시점은 `for loop`이 이미 끝난 상태라서 `i` 값은 10이다.
  50 +
  51 +기대한 결과를 얻으려면 `i` 값을 복사해 두어야 한다.
  52 +
  53 +### 이 Reference 문제 해결하기
  54 +
  55 +[anonymous wrapper](#function.scopes)로 index 값을 복사하는 것이 좋다.
  56 +
  57 + for(var i = 0; i < 10; i++) {
  58 + (function(e) {
  59 + setTimeout(function() {
  60 + console.log(e);
  61 + }, 1000);
  62 + })(i);
  63 + }
  64 +
  65 +이 anonymous function의 인자로 `i`를 넘기면 이 함수의 파라미터 e에 i의 **값**이 복사된다.
  66 +
  67 +이 `setTimeout`는 anonymous function 파라미터인 `e`에 대한 참조를 갖게 되고 `e`는 loop의 상태에 따라 변하지 않는다.
  68 +
  69 +함수를 반환하는 anonymous wrapper를 이용하는 방법도 있다. 다음 코드는 위 코드와 같다.
  70 +
  71 + for(var i = 0; i < 10; i++) {
  72 + setTimeout((function(e) {
  73 + return function() {
  74 + console.log(e);
  75 + }
  76 + })(i), 1000)
  77 + }
100 doc/ko/function/constructors.md
Source Rendered
... ... @@ -0,0 +1,100 @@
  1 +## 생성자
  2 +
  3 +JavaScript에서 생성자는 다른 언어들과 다르게 `new` 키워드로 호출되는 함수가 생성자다.
  4 +
  5 +어쨌든 생성자로 호출된 함수의 this는 막 만들어진 객체를 참조한다. **막 만든** 객체의 [`prototype`](#object.prototype)에는 생성자의 prototype이 할당된다.
  6 +
  7 +생성자에 `return` 구문이 없으면 this가 가리키는 객체를 반환한다.
  8 +
  9 + function Foo() {
  10 + this.bla = 1;
  11 + }
  12 +
  13 + Foo.prototype.test = function() {
  14 + console.log(this.bla);
  15 + };
  16 +
  17 + var test = new Foo();
  18 +
  19 +`new` 키워드가 실행되는 시점에 `Foo`를 생성자로 호출하고 `Foo.prototype`을 새 객체의 prototype에 할당한다.
  20 +
  21 +생성자에 `return` 구문이 있고 literal이 아니라 `객체`를 반환하면 그 객체가 반환된다.
  22 +
  23 + function Bar() {
  24 + return 2;
  25 + }
  26 + new Bar(); // 새 객체를 만들어 반환
  27 +
  28 + function Test() {
  29 + this.value = 2;
  30 +
  31 + return {
  32 + foo: 1
  33 + };
  34 + }
  35 + new Test(); // 명시한 객체를 반환
  36 +
  37 +new 키워드가 없으면 그 함수는 객체를 반환하지 않는다.
  38 +
  39 + function Foo() {
  40 + this.bla = 1; // gets set on the global object
  41 + }
  42 + Foo(); // undefined
  43 +
  44 +이 함수는 그때그때 다르게 동작하지만 보통 [`this`](#function.this)의 규칙에 따라 `this`의 값으로 *Global 객체*가 사용된다.:w
  45 +
  46 +### 팩토리
  47 +
  48 +생성자가 객체를 반환하면 `new` 키워드를 생략할 수 있다.
  49 +
  50 + function Bar() {
  51 + var value = 1;
  52 + return {
  53 + method: function() {
  54 + return value;
  55 + }
  56 + }
  57 + }
  58 + Bar.prototype = {
  59 + foo: function() {}
  60 + };
  61 +
  62 + new Bar();
  63 + Bar();
  64 +
  65 +new 키워드가 있으나 없으니 `Bar` 생성자는 똑같이 동작한다. [Closure](#function.closures)가 할당된 method 프로퍼티가 있는 객체를 만들어 반환한다.
  66 +
  67 +`new Bar()`는 반환된 객체의 prototype 프로퍼티에 아무런 영향을 주지 않는다. 객체를 반환하지 않는 생성자로 만들어지는 경우에만 객체의 prototype이 생성자의 것으로 할당된다.
  68 +
  69 +그러니까 이 예제에서 `new` 키워드의 유무는 아무 차이가 없다.
  70 +
  71 +### 팩토리로 객체 만들기
  72 +
  73 +`new` 키워들 빼먹었을 때 버그가 생긴다는 이유로 **아예 new를 사용하지 말 것**을 권하기도 한다.
  74 +
  75 +이를 위해서 객체를 만들고 반환해주는 팩토리를 사용할 수 있다.
  76 +
  77 + function Foo() {
  78 + var obj = {};
  79 + obj.value = 'blub';
  80 +
  81 + var private = 2;
  82 + obj.someMethod = function(value) {
  83 + this.value = value;
  84 + }
  85 +
  86 + obj.getPrivate = function() {
  87 + return private;
  88 + }
  89 + return obj;
  90 + }
  91 +
  92 +`new` 키워드가 없어도 괜찮고 [private 변수](#function.closures)를 사용하기도 쉽다. 그렇지만, 단점도 있다.
  93 +
  94 + 1. prototype으로 메소드를 공유하지 않으므로 메모리를 좀 더 사용한다.
  95 + 2. 팩토리를 상속하려면 모든 메소드를 복사하거나 객체의 prototype에 객체를 할당해 주어야 한다.
  96 + 3. `new` 키워드를 누락시켜서 prototype chain을 끊어버리는 것은 아무래도 언어의 의도에 어긋난다.
  97 +
  98 +### 결론
  99 +
  100 +`new` 키워가 생략되면 버그가 생길 수 있지만 그렇다고 prototype을 사용하지 않을 이유가 되지 않는다. 애플리케이션에 맞는 방법을 선택하는 것이 나을 거고 어떤 방법이든 **엄격하고 한결같이* 지켜야 한다.
38 doc/ko/function/general.md
Source Rendered
... ... @@ -0,0 +1,38 @@
  1 +## Function Declarations and Expressions
  2 +
  3 +JavaScript의 Function은 first class object라서 일반 객체처럼 취급될 수 있다. 그래서 익명 함수를 비동기 함수의 callback 같은 거로 넘길 수 있다.
  4 +
  5 +### `function` Declaration
  6 +
  7 + function foo() {}
  8 +
  9 +코드를 실행하기 전에 이 함수 [hoist](#function.scopes)되기 때문에 해당 Scope 어디에서나 이 함수를 호출할 수 있다. 심지어 함수를 정의하기 전에 호출해도 된다.
  10 +
  11 + foo(); // 이 코드가 실행되기 전에 foo가 만들어져서 잘 호출된다.
  12 + function foo() {}
  13 +
  14 +### `function` Expression
  15 +
  16 + var foo = function() {};
  17 +
  18 +`foo` 변수에 *익명* 함수를 할당하는 예를 보자.
  19 +
  20 + foo; // 'undefined'
  21 + foo(); // TypeError가 난다.
  22 + var foo = function() {};
  23 +
  24 +JavaScript가 hoist하는 것은 `var`로 선언하는 부분뿐이기 때문에 코드가 실행하기 전에 `foo` 변수는 정의된다.
  25 +
  26 +그러나 할당은 런타임에만 가능한 일이라 할당하는 코드가 실행될 때까지 `foo`변수는 기본 값인 [undefined](#core.undefined)다.
  27 +
  28 +### Named Function Expression
  29 +
  30 +Named Function을 할당하는 경우는 조금 특이하다.
  31 +
  32 + var foo = function bar() {
  33 + bar(); // 된다.
  34 + }
  35 + bar(); // ReferenceError
  36 +
  37 +함수 밖에서 `bar`를 사용할 수 없지만, 함수 안에서는 사용할 수 있다. JavaScript가 [이름을 찾는 방법](#function.scopes)이 있는데 function Scope에서는 항상 그 함수의 이름을 사용할 수 있다.
  38 +
189 doc/ko/function/scopes.md
Source Rendered
... ... @@ -0,0 +1,189 @@
  1 +## Scope과 Namespace
  2 +
  3 +JavaScript는 '{}' Block이 배배 꼬여 있어도 문법적으로는 잘 처리하지만, Block Scope은 지원하지 않는다. 그래서 JavaScript에서는 항상 *Function Scope*을 사용한다.
  4 +
  5 + function test() { // Scope
  6 + for(var i = 0; i < 10; i++) { // Scope이 아님
  7 + // count
  8 + }
  9 + console.log(i); // 10
  10 + }
  11 +
  12 +> **Note:** 할당할 때, 반환할 때, 함수 인자에서 사용되는 것을 제외하면 `{...}`는 모두 객체 리터럴이 아니라 Block 구문으로 해석된다. 그래서 [세미콜론을 자동으로 넣어주면](#core.semicolon) 에러가 생길 수 있다.
  13 +
  14 +그리고 JavaScript에는 namespace 개념이 없어서 *항상 공유하는* namepace가 하나 있는 거다.
  15 +
  16 +변수를 사용할 때마다 JavaScript는 아는 Scope을 상위방향으로 찾는다. Global Scope에까지 해당 변수를 찾지 못하면 `ReferenceError`가 난다.
  17 +
  18 +### Global 변수의 지옥.
  19 +
  20 + // script A
  21 + foo = '42';
  22 +
  23 + // script B
  24 + var foo = '42'
  25 +
  26 +이 두 스크립트는 다르다. Script A는 *Global* Scope에 `foo`라는 변수를 정의하는 것이고 Script B는 *현* Scope에 변수 `foo`를 정의하는 것이다.
  27 +
  28 +다시 말하지만, 이 둘은 전혀 다르고 `var`가 없는 것이 중요한 의미가 있다.
  29 +
  30 + // Global Scope
  31 + var foo = 42;
  32 + function test() {
  33 + // local Scope
  34 + foo = 21;
  35 + }
  36 + test();
  37 + foo; // 21
  38 +
  39 +함수에서 `var` 구문을 빼버리면 Global Scope의 `foo`의 값을 바꿔버린다. '뭐 이게 뭐가 문제야'라고 생각될 수 있지만 수천 줄인 JavaScript 코드에서 `var`를 빼먹어서 생긴 버그를 해결하는 것은 정말 어렵다.
  40 +
  41 + // Global Scope
  42 + var items = [/* some list */];
  43 + for(var i = 0; i < 10; i++) {
  44 + subLoop();
  45 + }
  46 +
  47 + function subLoop() {
  48 + // Scope of subLoop
  49 + for(i = 0; i < 10; i++) { // var가 없다.
  50 + // 내가 for문도 하는데...
  51 + }
  52 + }
  53 +
  54 +subLoop이 Global 변수 `i`의 값을 변경해버리기 때문에 외부 Loop은 `subLoop`을 한번 호출하고 나면 종료된다. 두 번째 `for` Loop에 `var`를 사용하여 `i`를 정의하면 이 문제는 생기지 않는다. 외부 Scope의 변수를 사용하는 것이 아니라면 `var`를 꼭 넣어야 한다.
  55 +
  56 +### Local 변수
  57 +
  58 +JavaScript에서 Local 변수를 정의하는 방법은 [함수 파라미터](#function.general)와 `var`로 정의한 변수뿐이다.
  59 +
  60 + // Global Scope
  61 + var foo = 1;
  62 + var bar = 2;
  63 + var i = 2;
  64 +
  65 + function test(i) {
  66 + // test 함수의 local Scope
  67 + i = 5;
  68 +
  69 + var foo = 3;
  70 + bar = 4;
  71 + }
  72 + test(10);
  73 +
  74 +`foo`, `i`는 `test` Function Scope에 있는 Local 변수라서 Global의 `foo`, `i` 값은 바뀌지 않는다. 하지만 `bar`는 Global 변수이기 때문에 Global의 `bar` 값이 변경된다.
  75 +
  76 +### Hoisting
  77 +
  78 +JavaScript는 선언문을 모두 **Hoist**한다. Hoist는 `var` 구문이나 `function`을 선언문을 해당 Scope의 가장 처음으로 옮기는 것을 말한다.
  79 +
  80 + bar();
  81 + var bar = function() {};
  82 + var someValue = 42;
  83 +
  84 + test();
  85 + function test(data) {
  86 + if (false) {
  87 + goo = 1;
  88 +
  89 + } else {
  90 + var goo = 2;
  91 + }
  92 + for(var i = 0; i < 100; i++) {
  93 + var e = data[i];
  94 + }
  95 + }
  96 +
  97 +코드를 본격적으로 실행하기 전에 JavaScript는 `var` 구문과 `function` 선언문을 해당 Scope의 상위로 옮긴다.
  98 +
  99 + // var 구문이 여기로 옮겨짐.
  100 + var bar, someValue; // default to 'undefined'
  101 +
  102 + // function 선언문도 여기로 옮겨짐
  103 + function test(data) {
  104 + var goo, i, e; // Block Scope은 없으므로 local 변수들은 여기로 옮겨짐
  105 + if (false) {
  106 + goo = 1;
  107 +
  108 + } else {
  109 + goo = 2;
  110 + }
  111 + for(i = 0; i < 100; i++) {
  112 + e = data[i];
  113 + }
  114 + }
  115 +
  116 + bar(); // bar()가 아직 'undefined'이기 때문에 TypeError가 남
  117 + someValue = 42; // Hoisting은 할당문까지 옮기지 않는다.
  118 + bar = function() {};
  119 +
  120 + test();
  121 +
  122 +Block Scope이 없으므로 Loop이나 if의 Block 안에 있는 `var` 구문들까지도 모두 Function Scope의 앞쪽으로 옮겨진다. 그래서 `if` Block의 결과는 좀 이상해진다.
  123 +
  124 +원래 코드에서 `if` Block은 *Global 변수* `goo`를 바꾸는 것처럼 보였지만 Hoisting 후에는 *local 변수*를 바꾼다.
  125 +
  126 +*Hoisting*을 모르면 다음과 같은 코드는 `ReferenceError`가 날 것으로 생각할 것이다.
  127 +
  128 + // SomeImportantThing이 초기화됐는지 검사한다.
  129 + if (!SomeImportantThing) {
  130 + var SomeImportantThing = {};
  131 + }
  132 +
  133 +`var` 구문은 *Global Scope* 상단으로 옮겨지기 때문에 이 코드는 잘 동작한다.
  134 +
  135 + var SomeImportantThing;
  136 +
  137 + // SomeImportantThing을 여기서 초기화하거나 말거나...
  138 +
  139 + // SomeImportantThing는 선언돼 있다.
  140 + if (!SomeImportantThing) {
  141 + SomeImportantThing = {};
  142 + }
  143 +
  144 +### 이름 찾는 순서
  145 +
  146 +JavaScript의 모든 Scope은 *현 객체*를 가리키는 [`this`](#function.this)를 가지고 있다. *Global Scope*에도 this가 있다.
  147 +
  148 +Function Scope에는 [`arguments`](#function.arguments)라는 변수가 하나 더 있다. 이 변수는 함수에 넘겨진 인자들이 담겨 있다.
  149 +
  150 +예를 들어 Function Scope에서 `foo`라는 변수에 접근할 때 JavaScript는 다음과 같은 순서로 찾는다.
  151 +
  152 + 1. 해당 Scope에서 `var foo` 구문으로 선언된 것을 찾는다.
  153 + 2. 함수 파라미터에서 `foo`라는 것을 찾는다.
  154 + 3. 해당 함수 이름이 `foo`인지 찾는다.
  155 + 4. 상위 Scope으로 있는지 확인하고 있으면 **#1**부터 다시 한다.
  156 +
  157 +> **Note:** `arguments`라는 파라미터가 있으면 Function의 기본 객체인 `arguments`가 생성되지 않는다.
  158 +
  159 +### Namespace
  160 +
  161 +JavaScript에서는 Global namespace 하나밖에 없어서 변수 이름이 중복되는 문제가 발생하기 쉽다. *Anonymous Wrappers*가 있어서 쉽게 피해갈 수 있다.
  162 +
  163 + (function() {
  164 + // 일종의 namespace라고 할 수 있다.
  165 +
  166 + window.foo = function() {
  167 + // 이 Closure는 Global Scope에 노출된다.
  168 + };
  169 +
  170 + })(); // 함수를 정의하자마자 실행한다.
  171 +
  172 +Unnamed Function은 [expressions](#function.general)이기 때문에 호출되려면 먼저 Evaluate돼야 한다.
  173 +
  174 + ( // 소괄호 안에 있는 것을 먼저 Evaluate한다.
  175 + function() {}
  176 + ) // 그리고 Function 객체를 반환한다.
  177 + () // Evaluation된 결과를 호출한다.
  178 +
  179 +같은 표기법이 두 가지 더 있다. 문법은 다르지만 똑같다.
  180 +
  181 + // 두 가지 다른 방법
  182 + +function(){}();
  183 + (function(){}());
  184 +
  185 +### 결론
  186 +
  187 +코드를 캡슐화할 때는 늘 *Anonymous Wrapper*로 namespace를 만들어 사용해야 한다. 이 Wrapper는 이름이 중복되는 것을 막아 주고 더 쉽게 모듈화할 수 있도록 해준다.
  188 +
  189 +그리고 Global 변수를 사용하는 것은 악질 습관이다. 이유야 어쨌든 에러 나기 쉽고 관리하기 어렵다.
89 doc/ko/function/this.md
Source Rendered
... ... @@ -0,0 +1,89 @@
  1 +## `this`
  2 +
  3 +다른 프로그래밍 언어에서 `this`가 가리키는 것과 JavaScript에서 `this`가 가리키는 것과는 좀 다르다. `this`가 가리킬 수 있는 객체는 정확히 5종류나 된다.
  4 +
  5 +### Global Scope에서
  6 +
  7 + this;
  8 +
  9 +Global Scope에서도 this가 사용될 수 있고 이때에는 *Global* 객체를 가리킨다.
  10 +
  11 +### 함수를 호출할 때
  12 +
  13 + foo();
  14 +
  15 +이때에도 `this`는 *Global* 객체를 가리킨다.
  16 +
  17 +> **ES5 Note:** strict 모드에서는 더는 Global 객체를 가리키지 않고 대신 `undefined`를 가리킨다.
  18 +
  19 +### 메소드로 호출할 때
  20 +
  21 + test.foo();
  22 +
  23 +이 경우에는 `this`가 `test`를 가리킨다.
  24 +
  25 +### 생성자를 호출할 때
  26 +
  27 + new foo();
  28 +
  29 +`new` 키워드로 [생성자](#function.constructors)를 실행시키는 경우에 이 생성자 안에서 `this`는 새로 만들어진 객체를 가리킨다.
  30 +
  31 +### `this`가 가리키는 객체 정해주기.
  32 +
  33 + function foo(a, b, c) {}
  34 +
  35 + var bar = {};
  36 + foo.apply(bar, [1, 2, 3]); // a = 1, b = 2, c = 3으로 넘어간다.
  37 + foo.call(bar, 1, 2, 3); // 이것도...
  38 +
  39 +`Function.prototype`의 `call`이나 `apply` 메소드를 호출하면 `this`가 무엇을 가리킬지 *정해줄 수 있다*. 호출할 때 첫 번째 인자로 `this`가 가리켜야 할 객체를 넘겨준다.
  40 +
  41 +그래서 `foo` Function 안에서 `this`는 위에서 설명했던 객체 중 하나를 가리키는 것이 아니라 `bar`를 가리킨다.
  42 +
  43 +> **Note:** 객체 리터럴에서 this는 그 객체를 가리키지 않는다. 예를 들어 `var obj= {me:this}`에서 `me`가 `obj`를 가리키는 것이 아니라 위에 설명한 5가지 객체 중 하나를 가리킨다.
  44 +
  45 +### 대표적인 결점
  46 +
  47 +`this`가 Global 객체를 가리키는 것도 잘못 설계된 부분 중 하나다. 괜찮아 보이지만 실제로는 전혀 사용하지 않는다.
  48 +
  49 + Foo.method = function() {
  50 + function test() {
  51 + // 여기에서 this는 Global 객체를 가리킨다.
  52 + }
  53 + test();
  54 + }
  55 +
  56 +`test` 에서 `this`가 `Foo`를 가리킬 것으로 생각할 테지만 틀렸다. 실제로는 그렇지 않다.
  57 +
  58 +`test`에서 `Foo`에 접근하려면 method에 Local 변수를 하나 만들고 `Foo`를 가리키게 하여야 한다.
  59 +
  60 + Foo.method = function() {
  61 + var that = this;
  62 + function test() {
  63 + // 여기에서 this 대신에 that을 사용하여 Foo에 접근한다.
  64 + }
  65 + test();
  66 + }
  67 +
  68 +`that`은 this에 접근하기 위해 만든 변수다. [closures](#function.closures)와 함께 `this`의 값을 넘기는 데 사용할 수 있다.
  69 +
  70 +### Method할당 하기
  71 +
  72 +메소드를 변수에 *할당*해 버리기 때문에 Function Aliasing은 JavaScript에서 안된다.
  73 +
  74 + var test = someObject.methodTest;
  75 + test();
  76 +
  77 +`test`는 다른 함수를 호출하는 것과 다름없어서 `this`가 someObject를 가리키지 않는다.
  78 +
  79 +처음에는 `this`를 늦게 바인딩하는 것이 나쁜 아이디어라고 생각할 수도 있지만, 이 점이 실제로 [prototypal inheritance](#object.prototype)를 가능케 해준다.
  80 +
  81 + function Foo() {}
  82 + Foo.prototype.method = function() {};
  83 +
  84 + function Bar() {}
  85 + Bar.prototype = Foo.prototype;
  86 +
  87 + new Bar().method();
  88 +
  89 +`Bar` 인스턴스에서 `method`를 호출하면 `method`에서 `this`는 바로 그 인스턴스를 가리킨다.
69 doc/ko/index.json
... ... @@ -0,0 +1,69 @@
  1 +{
  2 + "title": "JavaScript Garden",
  3 + "langTitle": "JavaScript Garden",
  4 + "description": "A Guide to JavaScript's Quirks and Flaws.",
  5 + "sections": [
  6 + {
  7 + "title": "소개",
  8 + "dir": "intro",
  9 + "articles": []
  10 + },
  11 + {
  12 + "title": "객체",
  13 + "dir": "object",
  14 + "articles": [
  15 + "general",
  16 + "prototype",
  17 + "hasownproperty",
  18 + "forinloop"
  19 + ]
  20 + },
  21 + {
  22 + "title": "함수",
  23 + "dir": "function",
  24 + "articles": [
  25 + "general",
  26 + "this",
  27 + "closures",
  28 + "arguments",
  29 + "constructors",
  30 + "scopes"
  31 + ]
  32 + },
  33 + {
  34 + "title": "Array",
  35 + "dir": "array",
  36 + "articles": [
  37 + "general",
  38 + "constructor"
  39 + ]
  40 + },
  41 + {
  42 + "title": "타입",
  43 + "dir": "types",
  44 + "articles": [
  45 + "equality",
  46 + "typeof",
  47 + "instanceof",
  48 + "casting"
  49 + ]
  50 + },
  51 + {
  52 + "title": "핵심",
  53 + "dir": "core",
  54 + "articles": [
  55 + "eval",
  56 + "undefined",
  57 + "semicolon",
  58 + "delete"
  59 + ]
  60 + },
  61 + {
  62 + "title": "기타",
  63 + "dir": "other",
  64 + "articles": [
  65 + "timeouts"
  66 + ]
  67 + }
  68 + ]
  69 +}
40 doc/ko/intro/index.md
Source Rendered
... ... @@ -0,0 +1,40 @@
  1 +## Intro
  2 +
  3 +**JavaScript Garden**은 JavaScript 언어의 핵심에 대한 글을 모은 것이다. 이 글은 초보자들이 JavaScript 익히면서 자주 겪는 실수, 미묘한 버그, 성능 이슈, 나쁜 습관들 줄일 수 있도록 도와줄 것이다.
  4 +
  5 +JavaScript Garden은 단순히 JavaScript를 설명하려 만들지 않았다. 그래서 이 글에서 설명하는 주제들을 이해하려면 반드시 언어에 대한 기본 지식이 필요하다. 먼저 Mozilla Developer Network에 있는 [문서][1]로 JavaScript 언어를 공부하기 바란다.
  6 +
  7 +## 저자들
  8 +
  9 +이 글은 [Stack Overflow][2]에서 사랑받는 두 사람 [Ivo Wetzel][3]과 [Zhang Yi Jiang][4]의 작품이다. Ivo Wetzel이 글을 썼고 Zhang Yi jiang이 디자인을 맡았다.
  10 +
  11 +## 기여자들
  12 +
  13 + - [Caio Romão][5] (철자 교정)
  14 + - [Andreas Blixt][6] (언어 교정)
  15 +
  16 +## 번역
  17 + - [박창우][]
  18 +
  19 +[박창우]: https://github.com/pismute
  20 +
  21 +## 호스팅
  22 +
  23 +JavaScript Garden은 Github에서 호스팅하고 있고 [Cramer Development][7]가 [JavaScriptGarden.info][8]에서 미러링해주고 있다.
  24 +
  25 +## 저작권
  26 +
  27 +JavaScript Garden은 [MIT license][9]를 따르고 [GitHub][10]에서 호스팅하고 있다. 문제를 발견하면 [이슈를 보고][11]하거나 수정해서 Pull Request를 하라. 아니면 Stack Overflow 채팅 사이트의 [Javascript room][12]에서 우리를 찾아도 된다.
  28 +
  29 +[1]: https://developer.mozilla.org/en/JavaScript/Guide
  30 +[2]: http://stackoverflow.com/
  31 +[3]: http://stackoverflow.com/users/170224/ivo-wetzel
  32 +[4]: http://stackoverflow.com/users/313758/yi-jiang
  33 +[5]: https://github.com/caio
  34 +[6]: https://github.com/blixt
  35 +[7]: http://cramerdev.com/
  36 +[8]: http://javascriptgarden.info/
  37 +[9]: https://github.com/BonsaiDen/JavaScript-Garden/blob/next/LICENSE
  38 +[10]: https://github.com/BonsaiDen/JavaScript-Garden
  39 +[11]: https://github.com/BonsaiDen/JavaScript-Garden/issues
  40 +[12]: http://chat.stackoverflow.com/rooms/17/javascript
36 doc/ko/object/forinloop.md
Source Rendered
... ... @@ -0,0 +1,36 @@
  1 +## `for in` Loop
  2 +
  3 +`in` 연산자와 마찬가지로 `for in`도 객체의 프로퍼티뿐만 아니라 프로토타입 체인까지 traverse 한다.
  4 +
  5 +> **Note:** `for in`은 Array의 `length`처럼 `enumerable` 속성이 `false`인 프로퍼티는 iterate 하지 않는다.
  6 +
  7 + // 원래는 Object.prototype을 바꾸면 안 된다.
  8 + Object.prototype.bar = 1;
  9 +
  10 + var foo = {moo: 2};
  11 + for(var i in foo) {
  12 + console.log(i); // bar와 moo 둘 다 출력한다.
  13 + }
  14 +
  15 +선택적으로 iterate 하려면 `for in`은 바꿀 수 없으니까 loop 바디에서 하는 수밖에 없다. `Object.prototype`의 [`hasOwnProperty`](#object.hasownproperty)메소드를 사용하면 객체의 프로퍼티만 골라낼 수 있다.
  16 +
  17 +> **Note:** `for in`은 프로토타입 체인을 모두 traverse 한다. 그래서 상속할 때마다 더 느려진다.
  18 +
  19 +### `hasOwnProperty`로 필터링 하기
  20 +
  21 + // 위의 예제에 이어서
  22 + for(var i in foo) {
  23 + if (foo.hasOwnProperty(i)) {
  24 + console.log(i);
  25 + }
  26 + }
  27 +
  28 +실무에 사용할 작정이라면 이렇게 써야 옳다. `hasOwnProperty` 때문에 **오직** `moo`만 출력된다. `hasOwnProperty`가 없으면 `Object.prototype`같은 네이티브 프로토타입이 확장될 때 에러 날 수 있다.
  29 +
  30 +네이티브 프로토타입을 확장하는 [Proptotype 라이브러리][1]을 사용할 때 `hasOwnProperty`가 없는 `for in` loop은 꼭 문제가 발생한다.
  31 +
  32 +### 결론
  33 +
  34 +`hasOwnProperty`는 항상 사용해야 한다. 실제로 코드가 동작할 환경에서 네이티브 프로토타입의 확장 여부에 대해 어떠한 가정도 하지 말아야 한다.
  35 +
  36 +[1]: http://www.prototypejs.org/
83 doc/ko/object/general.md
Source Rendered
... ... @@ -0,0 +1,83 @@
  1 +## 객체와 프로퍼티
  2 +
  3 +JavaScript에서 [`null`](#core.undefined)과 [`undefined`](#core.undefined)를 제외한 모든 것은 객체다.
  4 +
  5 + false.toString() // 'false'
  6 + [1, 2, 3].toString(); // '1,2,3'
  7 +
  8 + function Foo(){}
  9 + Foo.bar = 1;
  10 + Foo.bar; // 1
  11 +
  12 +숫자 리터럴은 객체가 아니라는 오해가 있는데 단지 JavaScript 파서의 문제일 뿐이다. JavaScript 파서는 숫자에 *Dot Notation*이 들어가면 오류라고 생각한다.
  13 +
  14 + 2.toString(); // SyntaxError가 난다.
  15 +
  16 +하지만, 숫자를 객체로 인식하는 꼼수가 몇 가지 있다.
  17 +
  18 + 2..toString(); // 두 번째 점은 잘 된다.
  19 + 2 .toString(); // 왼쪽 공백이 있으면 잘 된다.
  20 + (2).toString(); // 2를 먼저 해석한다.
  21 +
  22 +### Object 타입
  23 +
  24 +JavaScript 객체는 name/value 쌍으로 된 프로퍼티로 구성되기 때문에 [*Hashmap*][1]으로도 사용할 수 있다.
  25 +
  26 +객체 리터럴인 Object Notation으로 객체를 만들면 `Object.prototype`을 상속받고 [프로퍼티를 하나도 가지지 않은](#object.hasownproperty) 객체가 만들어진다.
  27 +
  28 + var foo = {}; // 깨끗한 새 객체를 만든다.
  29 +
  30 + // 값이 12인 'test' 프로퍼티가 있는 객체를 만든다.
  31 + var bar = {test: 12};
  32 +
  33 +### 프로퍼티
  34 +
  35 +객체의 프로퍼티는 Dot Notation이나 Square Bracket Notation으로 접근할 수 있다.
  36 +
  37 + var foo = {name: 'Kitten'}
  38 + foo.name; // kitten
  39 + foo['name']; // kitten
  40 +
  41 + var get = 'name';
  42 + foo[get]; // kitten
  43 +
  44 + foo.1234; // SyntaxError
  45 + foo['1234']; // works
  46 +
  47 +
  48 +'[]'은 프로퍼티를 동적으로 할당할 수 있고 변수 이름 규칙에도 구애받지 않는다. 그렇지만, 두 가지 방법은 근본적으로 서로 똑같다.
  49 +
  50 +### 프로퍼티 삭제
  51 +
  52 +객체의 프로퍼티를 삭제하는 방법은 `delete`를 사용하는 것뿐이다. 프로퍼티에 `undefined`나 `null`을 할당하는 것은 프로퍼티를 삭제하는 것이 아니라 프로퍼티에 할당된 *value*만 지우고 *key*는 그대로 두는 것이다.
  53 +
  54 + var obj = {
  55 + bar: 1,
  56 + foo: 2,
  57 + baz: 3
  58 + };
  59 + obj.bar = undefined;
  60 + obj.foo = null;
  61 + delete obj.baz;
  62 +
  63 + for(var i in obj) {
  64 + if (obj.hasOwnProperty(i)) {
  65 + console.log(i, '' + obj[i]);
  66 + }
  67 + }
  68 +
  69 +
  70 +`baz`만 제거했기 때문에 `bar undefined`와 `foo null`은 출력되고 `baz`와 관련된 것은 출력되지 않는다.
  71 +