diff --git a/doc/en/function/closures.md b/doc/en/function/closures.md index a5fbc91e..58005a5e 100644 --- a/doc/en/function/closures.md +++ b/doc/en/function/closures.md @@ -97,7 +97,7 @@ above. } The other popular way to achieve this is to add an additional argument to -the setTimeout function, which passes these arguments to the callback. +the `setTimeout` function, which passes these arguments to the callback. for(var i = 0; i < 10; i++) { setTimeout(function(e) { diff --git a/doc/ko/array/general.md b/doc/ko/array/general.md index 1a665fa3..12f66100 100644 --- a/doc/ko/array/general.md +++ b/doc/ko/array/general.md @@ -25,14 +25,15 @@ JavaScript에서는 배열(Array)도 객체(Object)지만 객체 순회(Iterate) `length` 프로퍼티의 *getter*는 단순히 Array 안에 있는 엘리먼트의 개수를 반환하고 *setter*는 배열을 할당한 수만큼 잘라 버린다. - var foo = [1, 2, 3, 4, 5, 6]; - foo.length = 3; - foo; // [1, 2, 3] + var arr = [1, 2, 3, 4, 5, 6]; + arr.length = 3; + arr; // [1, 2, 3] - foo.length = 6; - foo; // [1, 2, 3] + arr.length = 6; + arr.push(4); + arr; // [1, 2, 3, undefined, undefined, undefined, 4] -현재 크기보다 더 작은 값을 할당하면 배열을 자르지만, 현재 크기보다 더 큰 값을 할당한다고 해서 배열을 늘리진 않는다. +현재 크기보다 더 작은 값을 할당하면 배열을 자른다. 배열의 크기를 증가시키면 드문드문(sparse)한 배열을 생성한다. ### 결론 diff --git a/doc/ko/core/eval.md b/doc/ko/core/eval.md index 528b1883..2a97ebea 100644 --- a/doc/ko/core/eval.md +++ b/doc/ko/core/eval.md @@ -2,26 +2,26 @@ `eval` 함수는 JavaScript 문자열을 지역 스코프에서 실행한다. - var foo = 1; + var number = 1; function test() { - var foo = 2; - eval('foo = 3'); - return foo; + var number = 2; + eval('number = 3'); + return number; } test(); // 3 - foo; // 1 + number; // 1 `eval`함수는 `eval`이라는 이름으로 **직접** 실행할 때에만 지역 스코프에서 실행된다. 그리고 `eval`이라는 이름에 걸맞게 악명또한 높다. - var foo = 1; + var number = 1; function test() { - var foo = 2; - var bar = eval; - bar('foo = 3'); - return foo; + var number = 2; + var copyOfEval = eval; + copyOfEval('number = 3'); + return number; } test(); // 2 - foo; // 3 + number; // 3 어쨌든 `eval`은 사용하지 말아야 한다. eval을 사용하는 99.9%는 사실 eval 없이도 만들수있다. diff --git a/doc/ko/function/arguments.md b/doc/ko/function/arguments.md index 5ea383cb..88ce01bc 100644 --- a/doc/ko/function/arguments.md +++ b/doc/ko/function/arguments.md @@ -27,22 +27,37 @@ JavaScript의 모든 함수 스코프에는 `arguments`라는 특별한 변수 // 내곡동에 땅이라도 산다. } -또 다른 방법으로는 함수를 랩핑하지 않고, 풀어서 `call`과 `apply`를 함께 사용하는 방법이 있다. (역주: 프로토타입에 있는 method를 호출하기 전에 Foo 객체 안에 있는 method로 한번더 필터링하는 효과가 있다. ) +또 다른 트릭은 `call`과 `apply`를 함께 사용하여 메써드(`this`의 값과 인자들을 사용하는 함수)를 +단지 인자들만 사용하는 일반 함수로 바꾸는 것이다. - function Foo() {} + function Person(first, last) { + this.first = first; + this.last = last; + } - Foo.prototype.method = function(a, b, c) { - console.log(this, a, b, c); + Person.prototype.fullname = function(joiner, options) { + options = options || { order: "western" }; + var first = options.order === "western" ? this.first : this.last; + var last = options.order === "western" ? this.last : this.first; + return first + (joiner || " ") + last; }; - // "method"를 풀어 쓴(unbound) 버전 - // 이 Function의 인자: this, arg1, arg2...argN - Foo.method = function() { - - // 결과: Foo.prototype.method.call(this, arg1, arg2... argN) - Function.call.apply(Foo.prototype.method, arguments); + // "fullname" 메써드의 비결합(unbound) 버전을 생성한다. + // 첫번째 인자로 'first'와 'last' 속성을 가지고 있는 어떤 객체도 사용 가능하다. + // "fullname"의 인자 개수나 순서가 변경되더라도 이 랩퍼를 변경할 필요는 없을 것이다. + Person.fullname = function() { + // 결과: Person.prototype.fullname.call(this, joiner, ..., argN); + return Function.call.apply(Person.prototype.fullname, arguments); }; + var grace = new Person("Grace", "Hopper"); + + // 'Grace Hopper' + grace.fullname(); + + // 'Turing, Alan' + Person.fullname({ first: "Alan", last: "Turing" }, ", ", { order: "eastern" }); + ### 일반 파라미터와 arguments 객체의 인덱스 일반 파라미터와 `arguments` 객체의 프로퍼티는 모두 *getter*와 *setter*를 가진다. diff --git a/doc/ko/function/closures.md b/doc/ko/function/closures.md index 4d7463a6..4e5631fa 100644 --- a/doc/ko/function/closures.md +++ b/doc/ko/function/closures.md @@ -75,3 +75,21 @@ JavaScript에서는 스코프(Scope)를 어딘가에 할당해두거나 참조 } })(i), 1000) } + +즐겨 쓰이는 또 하나의 방법은 `setTimeout` 함수에 세번째 인자를 추가하는 방법이다. +추가된 인자는 콜백 함수에 전달된다. + + for(var i = 0; i < 10; i++) { + setTimeout(function(e) { + console.log(e); + }, 1000, i); + } + +레거시 JS 환경(Internet Explorer 9 이하)은 이 방법을 지원하지 않는다. + +`.bind`를 사용하는 방법도 있다. `.bind`는 `this` 컨텍스트와 인자들을 함수에 결속(bind)시킨다. +아래 코드는 위 코드와 동일하게 동작한다. + + for(var i = 0; i < 10; i++) { + setTimeout(console.log.bind(console, i), 1000); + } diff --git a/doc/ko/function/constructors.md b/doc/ko/function/constructors.md index 1aa6de4a..2b26dc24 100644 --- a/doc/ko/function/constructors.md +++ b/doc/ko/function/constructors.md @@ -6,40 +6,40 @@ JavaScript의 생성자는 다른 언어들과 다르게 `new` 키워드로 호 그리고 생성자에 명시적인 `return` 구문이 없으면 this가 가리키는 객체를 반환한다. - function Foo() { - this.bla = 1; + function Person(name) { + this.name = name; } - Foo.prototype.test = function() { - console.log(this.bla); + Person.prototype.logName = function() { + console.log(this.name); }; - var test = new Foo(); + var sean = new Person(); -위 코드는 `new` 키워드가 실행되는 시점에 `Foo`를 생성자로 호출하고 `Foo.prototype`을 새 객체의 prototype에 할당한다. +위 코드는 `Person`을 생성자로 호출하고 새로 생성된 객체의 `prototype`을 `Person.prototype`으로 설정한다. 아래 코드와 같이 생성자에 명시적인 `return` 문이 있는 경우에는 반환하는 값이 객체인 경우에만 그 값을 반환한다. - function Bar() { - return 2; + function Car() { + return 'ford'; } - new Bar(); // 새 객체를 만들어 반환 + new Car(); // 'ford'가 아닌 새로운 객체를 반환 - function Test() { - this.value = 2; + function Person() { + this.someValue = 2; return { - foo: 1 + name: 'Charles' }; } - new Test(); // 명시한 객체를 반환 + new Person(); // someValue가 포함되지 않은 ({name:'Charles'}) 객체 반환 new 키워드가 없으면 그 함수는 객체를 반환하지 않는다. - function Foo() { - this.bla = 1; // 전역객체에 할당된다. + function Pirate() { + this.hasEyePatch = true; // 전역 객체를 준비! } - Foo(); // undefined + var somePirate = Pirate(); // somePirate = undefined 위 예제는 그때그때 다르게 동작한다. 그리고 [`this`](#function.this) 객체의 동작 원리에 따라서 Foo 함수안의 `this`의 값은 *Global 객체*를 가리키게된다. (역주: 결국 new 키워드를 빼고, 코드를 작성할 경우 원치 않은 this 참조 오류가 발생할 수 있다.) @@ -48,24 +48,24 @@ new 키워드가 없으면 그 함수는 객체를 반환하지 않는다. 생성자가 객체를 반환하면 `new` 키워드를 생략할 수 있다. - function Bar() { - var value = 1; + function Robot() { + var color = 'gray'; return { - method: function() { - return value; + getColor: function() { + return color; } } } - Bar.prototype = { - foo: function() {} + Robot.prototype = { + someFunction: function() {} }; - new Bar(); - Bar(); + new Robot(); + Robot(); -new 키워드의 유무과 관계없이 `Bar` 생성자의 동작은 동일한다. 즉 [클로저](#function.closures)가 할당된 method 프로퍼티가 있는 새로운 객체를 만들어 반환한다. +new 키워드의 유무과 관계없이 `Robot` 생성자의 동작은 동일하다. 즉 [클로저](#function.closures)가 할당된 method 프로퍼티가 있는 새로운 객체를 만들어 반환한다. -`new Bar()`로 호출되는 생성자는 반환되는 객체의 prototype 프로퍼티에 아무런 영향을 주지 않는다. 객체를 반환하지 않는 생성자로 만들어지는 경우에만 객체의 prototype이 생성자의 것으로 할당된다. +`new Robot()`으로 호출되는 생성자는 반환되는 객체의 prototype 프로퍼티에 아무런 영향을 주지 않는다. 객체를 반환하지 않는 생성자로 만들어지는 경우에만 객체의 prototype이 생성자의 것으로 할당된다. 그러니까 이 예제에서 `new` 키워드의 유무는 아무런 차이가 없다. (역주: 생성자에 객체를 만들어 명시적으로 반환하면 new 키워드에 관계없이 잘 동작하는 생성자를 만들수있다. 즉, new 키워드가 빠졌을때 발생하는 this 참조 오류를 방어해준다.) @@ -76,19 +76,21 @@ new 키워드의 유무과 관계없이 `Bar` 생성자의 동작은 동일한 객체를 만들고 반환해주는 팩토리를 사용하여 `new` 키워드 문제를 회피할 수 있다. - function Foo() { - var obj = {}; - obj.value = 'blub'; + function CarFactory() { + var car = {}; + car.owner = 'nobody'; - var private = 2; - obj.someMethod = function(value) { - this.value = value; + var milesPerGallon = 2; + + car.setOwner = function(newOwner) { + this.owner = newOwner; } - obj.getPrivate = function() { - return private; + car.getMPG = function() { + return milesPerGallon; } - return obj; + + return car; } `new` 키워드가 없어도 잘 동작하고 [private 변수](#function.closures)를 사용하기도 쉽다. 그렇지만, 단점도 있다. diff --git a/doc/ko/function/this.md b/doc/ko/function/this.md index b6d57aa6..9230c5af 100644 --- a/doc/ko/function/this.md +++ b/doc/ko/function/this.md @@ -58,16 +58,26 @@ Global Scope에서도 this가 사용될 수 있고 이때에는 *Global* 객체 `test`에서 `Foo`에 접근하려면 method에 Local 변수를 하나 만들고 `Foo`를 가리키게 하여야 한다. Foo.method = function() { - var that = this; + var self = this; function test() { - // 여기에서 this 대신에 that을 사용하여 Foo에 접근한다. + // 여기에서 this 대신에 self를 사용하여 Foo에 접근한다 } test(); } -`that`은 this에 접근하기 위해 만든 변수다. [closures](#function.closures)와 함께 `this`의 값을 넘기는 데 사용할 수 있다. +`self`는 통상적인 변수 이름이지만, 바깥쪽의 `this`를 참조하기 위해 일반적으로 사용된다. +또한 [클로저](#function.closures)와 결합하여 `this`의 값을 주고 받는 용도로 사용할 수도 있다. -### Method할당 하기 +ECMAScript 5부터는 익명 함수와 결합된 `bind` 메써드를 사용하여 같은 결과를 얻을 수 있다. + + Foo.method = function() { + var test = function() { + // this는 이제 Foo를 참조한다 + }.bind(this); + test(); + } + +### Method 할당하기 JavaScript의 또다른 함정은 바로 함수의 별칭을 만들수 없다는 점이다. 별칭을 만들기 위해 메소드를 변수에 넣으면 자바스크립트는 별칭을 만들지 않고 바로 *할당*해 버린다.