티스토리 툴바


JavaScript Garden(http://bonsaiden.github.com/JavaScript-Garden/)이라는 좋은 문서가 있어 번역을 해봤습니다.
사실 영어가 너무도 짧아 한번도... 어떤 문서도... 번역해본 적이 없지만 Javascript 도 공부하고 영어도 공부할 겸
다소 오랜시간에 걸쳐 번역을 했습니다.
번역이 어설퍼 창피한 부분도 있지만 나름 뿌뜻한 마음에 포스팅 합니다.
혹시나 번역이 잘못된 부분을 알려주시면 정말 감사하겠습니다.

p.s.
- Intro 는 번역 생략...
- 문서내의 링크는 원글의 링크 그대로입니다. 

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, 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

Caio Romão (Spelling corrections)
Andreas Blixt (Language corrections)
 
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 Properites

JavaScript 에서는 null undefined  이 두가지 예외를 제외한 모든 것이 객체처럼 동작합니다.
Everything in JavaScript acts like an object, with the only two exceptions being null and undefined. 
1.false.toString() // 'false'
2.[1, 2, 3].toString(); // '1,2,3'
3. 
4.function Foo(){}
5.Foo.bar = 1;
6.Foo.bar; // 1
보통 number 리터럴은 객체로 사용될 수 없다고 잘못 알고 있는데,
그것은 JavaScript 의 파서가 number 의 dot(.) 표기법을 부동소수점 리터럴로 파싱하려는 결함(?) 때문입니다.
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. 
1.2.toString(); // raises SyntaxError
아래와 같이 number 리터럴을 객체처럼 사용하기 위한 몇가지 방법들이 있습니다.
There are a couple of workarounds which can be used in order make number literals act as objects too. 
1.2..toString(); // the second point is correctly recognized
2.2 .toString(); // note the space left to the dot
3.(2).toString(); // 2 is evaluated first

Objects as a Data Type

JavaScript 의 객체는 Hashmap 으로 사용될 수도 있는데, 그것은 주로 이름과 값이 매핑된 프로퍼티들로 이루어져 있습니다.
Objects in JavaScript can also be used as a Hashmap, they mainly consist of named properties mapping to values. 

객체 리터럴 -중괄호({}) 구문- 을 사용하여 일반적인 객체를 생성하는 것이 가능합니다.
이렇게 생성된 객체는 Object.prototype 으로부터 상속(inherits)되며 자신의 프로퍼티(own properties)가 없습니다.
Using a object literal - {} notation - it is possible to create a plain object. This new object inherits from Object.prototype and has no own properties defined on it. 
1.var foo = {}; // a new empty object
2. 
3.// a new object with a property called 'test' with value 12
4.var bar = {test: 12};

Accessing Properties

객체의 프로퍼티는 두가지 방법, 즉 dot(.) 표기법이나 대괄호([]) 표기법을 사용하여 접근할 수 있습니다.
The properties of an object can be accessed in two ways, via either the dot notation, or the square bracket notation. 
01.var foo = {name: 'Kitten'}
02.foo.name; // kitten
03.foo['name']; // kitten
04. 
05.var get = 'name';
06.foo[get]; // kitten
07. 
08.foo.1234; // SyntaxError
09.foo['1234']; // works
두 가지 표기법 모두 동일하게 동작하지만,
한가지 다른 점은 대괄호([]) 표기법을 사용하면 프로퍼티를 동적으로 할당할 수 있다는 것입니다.
dot(.) 표기법을 사용하여 프로퍼티를 동적으로 할당하려 할 경우는 문법오류(Syntax Error)가 발생합니다.
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 use of property names that would otherwise lead to a syntax error. 

Deleting Properties

객체에서 프로퍼티를 실제 삭제하는 유일한 방법은 delete 연산자를 사용하는 것입니다.
프로퍼티에 undefined 혹은 null 을 셋팅하는 것은 프로퍼티 자체를 삭제하는 것이 아니라 단지 프로퍼티에 할당된 값을 삭제하는 것일 뿐입니다.
The only way to actually remove a property from an object is to use the delete operator; setting the property to undefined or null only remove the value associated with the property, but not the key. 
01.var obj = {
02.    bar: 1,
03.    foo: 2,
04.    baz: 3
05.};
06.obj.bar = undefined;
07.obj.foo = null;
08.delete obj.baz;
09. 
10.for(var i in obj) {
11.    if (obj.hasOwnProperty(i)) {
12.        console.log(i, '' + obj[i]);
13.    }
14.}
위 소스의 실행 결과 bar undefined foo null 이 출력되고 baz 는 삭제되었기 때문에 출력이 되지 않습니다.
The above outputs both bar undefined and foo null - only baz was removed and is therefore missing from the output. 

Notation of Keys
1.var test = {
2.    'case': 'I am a keyword so I must be notated as a string',
3.    delete: 'I am a keyword too so me' // raises SyntaxError
4.};
객체의 프로퍼티는 순수 문자나 문자열로 표기할 수 있습니다.
JavaScript 파서의 잘못된 설계때문에 위 코드는 ECMAScript 5 이전에서는 문법오류(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. 

delete 가 키워드라서 발생하는 에러이기 때문에 이전 JavaScript 엔진에서 정확히 해석되게 하려면 문자열 리터럴로 표기해야만 한다.
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 는 클래스 기반의 상속 모델을 사용하지 않습니다. 대신에 프로토타입 기반의 상속 모델을 사용합니다.
JavaScript does not feature a classical inheritance model, instead it uses a prototypal one. 

이것은 JavaScript 의 약점 중 하나라고 자주 언급되지만 사실은 프로토타입 기반의 상속 모델이 클래스 기반의 상속 모델보다 더 강력합니다. 예를 들면 코드 상단에 클래스 기반의 모델을 구현하는 것은 별거 아니지만 그 반대로는 훨씬 더 어려운 작업이 됩니다.
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. 

프로토타입 기반의 상속이라는 특징을 가진 언어들 중에 JavaScript 가 유일하게 널리 사용된 언어이기 때문에 두 가지 모델 사이의 차이점에 적응하는 것은 시간이 다소 걸립니다.
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 는 프로토타입 체인(prototype chains)이라는 것을 사용하여 상속을 한다는 것입니다.
The first major difference is that inheritance in JavaScript is done by using so called prototype chains. 
01.function Foo() {
02.    this.value = 42;
03.}
04.Foo.prototype = {
05.    method: function() {}
06.};
07. 
08.function Bar() {}
09. 
10.// Set Bar's prototype to a new instance of Foo
11.Bar.prototype = new Foo();
12.Bar.prototype.foo = 'Hello World';
13. 
14.// Make sure to list Bar as the actual constructor
15.Bar.prototype.constructor = Bar;
16. 
17.var test = new Bar() // create a new bar instance
18. 
19.// The resulting prototype chain
20.test [instance of Bar]
21.    Bar.prototype [instance of Foo]
22.        { foo: 'Hello World' }
23.        Foo.prototype
24.            { method: ... }
25.            Object.prototype
26.                { toString: ... /* etc. */ }
위에서 test 객체는 Bar.prototype Foo.prototype 둘 다로부터 상속을 받게 되며 
따라서 Foo 에서 선언된 함수인 method 에 접근할 수 있게 되고 또한 prototype 에 할당된 그 Foo 인스턴스의 value 라는 프로퍼티에도 접근할 수 있게 됩니다.
여기서 주목해야 할 중요한 점은 new Bar() Foo 인스턴스를 새로 생성하는 것이 아니라 prototype 에 이미 할당된 것을 재사용한다는 것입니다.
요컨대 모든 Bar 인스턴스는 같은 value 프로퍼티를 공유한다는 것입니다.
In the 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

JavaScript 에서는 객체의 프로퍼티에 접근할 때 요청한 이름의 프로퍼티를 찾을때까지 프로토타입 체인을 아래에서 위로 순회하게 됩니다.
When accessing the properties of an object, JavaScript will traverse the prototype chain upwards until it finds a property with the requested name.
 
Object.prototype 이라는 체인의 가장 상단까지 가서도 해당 프로퍼티를 찾지 못하면 대신에 undefined 를 반환하게 됩니다.
When 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

prototype 프로퍼티가 프로토타입 체인을 구현하기 위해 언어 차원에서 사용이 되고는 있지만 그것에 다른 어떤 값을 할당하는 것도 가능은 합니다. 다만 원시타입(primitives)이 할당될 경우에는 단순히 무시해 버립니다.
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. Although primitives will simply get ignored when assigned as a prototype. 
1.function Foo() {}
2.Foo.prototype = 1; // no effect
위 예제에서 보는 것처럼 객체를 할당할 수도 있고 프로토타입 체인의 동적 생성도 가능합니다.
Assigning objects, as shown in the example above, will work, and allows for dynamic creation of prototype chains. 

Performance

프로토타입 체인 상에서 프로퍼티를 찾는 시간은 코드의 임계지역(critical sections)에서는 성능에 부정적인 영향이 있을 수 있습니다. 게다가, 존재하지 않는 프로퍼티를 접근하려 하면 항상 프로토타입 체인 전체를 순회하게 됩니다.
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. 

또한, 객체의 프로퍼티들을 반복(iterating)하여 접근할 경우(for 구문 등을 통해)에는 프로토타입 체인 상에 있는 모든 프로퍼티가 열거되게 됩니다.
Also, when iterating over the properties of an object every property that is on the prototype chain will get enumerated. 

Extension of Native Prototypes

종종 사용되는 한가지 잘못된 특성은 Object.prototype 또는 이미 프로토타입에 내장되어 있는 것을 확장한다는 것입니다.
One mis-feature that is often used is to extend Object.prototype or one of the other built in prototypes. 

이러한 기술을 monkey patching 이라고 하는데 이것은 캡슐화(encapsulation)에 어긋나는 기술입니다.
반면 Prototype 과 같이 널리 사용되는 프레임워크에서 사용되기도 하는데 이것은 표준화되지 않은 기능들의 추가로 인해 내장타입(built-in types) 자체가 혼란스러워지기 때문에 적당한 선택은 아닙니다.
This technique is called monkey patching and breaks encapsulation. While used by widely spread frameworks such as Prototype, there is still no good reason for cluttering built-in types with additional non-standard functionality. 

내장된(built-in) prototype 을 확장할만한 유일한 이유는 Array.forEach 와 같이 새로운 JavaScript 엔진의 특성을 backport(하위 버전에 적용)하기 위해서일 뿐입니다.
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

상속을 위한 복잡한 코드를 작성하기 이전에 프로토타입 기반의 상속 모델을 완벽히 이해해야만 합니다.
또한, 발생할 수 있는 성능이슈를 피해야 할 필요가 있을때는 프로토타입 체인의 범위를 인지하여 그것을 끊어야만 합니다.
나아가서, JavaScript 의 새로운 특성과의 호환성을 목적으로 하지 않는 한 원시(native) 프로토타입은 확장하지 않아야 합니다.
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. 



hasOwnProperty

프로토타입 체인(prototype chain) 상에 있는 것이 아닌 해당 객체 자체에 정의되어 있는 프로퍼티인지를 체크하기 위해서는 Object.prototype 으로부터 상속받아 모든 객체가 가지고 있는 hasOwnProperty 메소드를 사용해야만 합니다.
In order to check whether a 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 는 JavaScript 에서 프로토타입 체인을 순회하지 않으면서 프로퍼티를 다루는 유일한 방법입니다.
hasOwnProperty is the only thing in JavaScript which deals with properties and does not traverse the prototype chain. 
01.// Poisoning Object.prototype
02.Object.prototype.bar = 1;
03.var foo = {goo: undefined};
04. 
05.foo.bar; // 1
06.'bar' in foo; // true
07. 
08.foo.hasOwnProperty('bar'); // false
09.foo.hasOwnProperty('goo'); // true
오직 hasOwnProperty 만이 정확하고 예상했던 결과를 보여주기 때문에 어떤 객체의 모든 프로퍼티를 반복하여 다루는 경우에는 반드시 필요합니다.
해당 객체 자신의 프로퍼티가 아닌 프로토타입 체인 상의 어딘가에 있는 프로퍼티를 제외할 수 있는 다른 방법은 없습니다.
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 에서는 hasOwnProperty 라는 프로퍼티의 이름을 보호하지는 않습니다. 그래서 그 이름의 프로퍼티를 가지는 객체가 존재할 가능성도 있습니다. 그럴 경우에는 정확한 결과를 얻기 위해 외부의(external) hasOwnProperty 를 사용해야 할 필요가 있습니다.
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. 
01.var foo = {
02.    hasOwnProperty: function() {
03.        return false;
04.    },
05.    bar: 'Here be dragons'
06.};
07. 
08.foo.hasOwnProperty('bar'); // always returns false
09. 
10.// Use another Object's hasOwnProperty and call it with 'this' set to foo
11.({}).hasOwnProperty.call(foo, 'bar'); // true
In Conclusion

객체 상에 프로퍼티의 존재 여부를 확인하기 위해서는 hasOwnProperty 메소드를 사용하는 것이 유일한 방법입니다.
또한, 모든 for in loop 에서 hasOwnProperty 를 사용할 것을 권장드리는데 이것은 원시(native) 프로토타입(prototypes)을 확장함으로써 발생하는 오류를 피할 수 있을 것입니다.
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, this will avoid errors from extended native prototypes. 



The for in Loop

in 연산자와 마찬가지로 for in loop 역시 객체의 프로퍼티들를 반복하여 다루는 경우 프로토타입 체인을 순회하게 됩니다.
Just like the in operator, the for in loop also traverses the prototype chain when iterating over the properties of an object. 
1.// Poisoning Object.prototype
2.Object.prototype.bar = 1;
3. 
4.var foo = {moo: 2};
5.for(var i in foo) {
6.    console.log(i); // prints both bar and moo
7.}
for in loop 자체의 기능을 수정할 수는 없기 때문에 loop 의 안에서 원하지 않는 프로퍼티를 걸러줘야 하는데 이것은 Object.prototypehasOwnProperty 메소드를 사용하면 됩니다.
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 method of Object.prototype. 

Using hasOwnProperty for Filtering
1.// still the foo from above
2.for(var i in foo) {
3.    if (foo.hasOwnProperty(i)) {
4.        console.log(i);
5.    }
6.}
이렇게 사용해야지만이 정확한 결과를 얻을 수 있습니다. hasOwnProperty 를 사용했기 때문에 moo 만 출력이 될 것입니다. hasOwnProperty 를 사용하지 않으면 원시(native) 프로토타입- e.g. Object.prototype - 이 확장된 경우 코드에서 에러가 발생하기 쉽습니다.
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. 

널리 사용되는 프레임워크인 Prototype 이 이렇게 동작을 합니다. 이 프레임워크를 사용하면 hasOwnProperty 를 사용하지 않는 for in loop 에서 break(?)를 보장합니다.
One widely used framework which does this is Prototype. When this framework is included, for in loops that do not use hasOwnProperty are guaranteed to break. 

In Conclusion

항상 hasOwnProperty 를 사용하기를 권장합니다.
원시(native) 프로토타입의 확장 여부와 상관 없이 코드가 운영이 되는 환경에 대해 어떠한 가정도 해서는 안됩니다.
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. 



Functions


Function Declarations and Expressions

JavaScript 에서 함수(function)는 일급객체(first class object)입니다. 그것은 일반적인 다른 값들처럼 주변으로 전달이 될 수 있다는 것을 의미합니다. 이러한 특성이 주로 사용되는 것은 비동기(asynchronous) 함수와 같은 다른 함수에 콜백(callback)함수로써 익명(anonymous) 함수를 전달하는 것입니다.
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 asynchronous function. 

The function Declaration
1.function foo() {}
위 함수는 프로그램의 시작부가 실행되기 전에 위로 올려집니다(hoisted). 그래서, 함수가 선언되어 있는 범위(scope) 안에서는 어디서든지 접근이 가능하며, 심지어 소스에 실제 정의되기 전에 호출하는 것도 가능합니다.
The above function gets hoisted 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. 
1.foo(); // Works because foo was created before this code runs
2.function foo() {}
The function Expression
1.var foo = function() {};
이 예제는 이름이 없는 익명 함수를 변수 foo 에 할당하는 것입니다. 
This example assigns the unnamed and anonymous function to the variable foo. 
1.foo; // 'undefined'
2.foo(); // this raises a TypeError
3.var foo = function() {};
var 라는 키워드가 선언을 의미하여 코드의 시작부가 실제 실행되기 전에 foo 라는 변수명이 위로 올려지기(hoists) 때문에
foo 는 스크립트가 실행될때 이미 선언이 된 것입니다.
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. 

그러나, 할당은 실행시간(runtime) 시에만 이루어지기 때문에 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. 
1.var foo = function bar() {
2.    bar(); // Works
3.}
4.bar(); // ReferenceError
여기서 bar foo 에 할당되어 있는 함수이기 때문에 바깥쪽 범위에서는 접근할 수 없게 됩니다. 그러나, bar 안에서는 유효하며 이것이 JavaScript 에서 이름을 판단(name resolution) 하는 방법으로 함수의 이름은 함수 자신의 지역 범위 안에서는 항상 접근이 가능합니다.
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 에서는 this 라는 이 특별한 변수가 무엇을 참조하고 있는지에 대해 대부분의 다른 프로그래밍 언어와는 다른 개념을 가지고 있습니다. this 의 값이 바운딩되는 방법은 정확하게 다섯가지 방법이 있습니다.
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. 

The Global Scope
전역 범위에서 this 가 사용되면 전역 객체를 참조하게 됩니다.
When using this in global scope, it will simply refer to the global object. 

Calling a Function
여기에서도 this 는 적역 객체를 참조하게 됩니다.
Here this will again refer to the global object. 

Calling a Method
1.test.foo();
이 예제에서 this test 를 참조하게 됩니다.
In this example this will refer to test. 

Calling a Constructor
1.new foo();
new 키워드가 선행되어 함수가 호출되면 생성자(constructor)로써 동작을 하게 됩니다. 그 함수 안에서의 this 는 새롭게 생성된 객체(Object)를 참조하게 됩니다.
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
1.function foo(a, b, c) {}
2. 
3.var bar = {};
4.foo.apply(bar, [1, 2, 3]); // array will expand to the below
5.foo.call(bar, 1, 2, 3); // results in a = 1, b = 2, c = 3
Function.prototype call 또는 apply 메소드를 사용할 경우 호출된 함수 안에서의 this 의 값은 
해당 함수 호출 시의 첫번째 인수로 명시적으로 설정됩니다.
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. 

결국 위 예제는 메소드의 경우(method case, 위의 다섯가지 중 Calling a Method)가 적용되지 않고 foo 안에서의 this 로  bar 가 설정되게 됩니다.
As a result, the above example the method case does not apply, and this inside of foo will be set to bar. 

Common Pitfalls

이러한 경우들 대부분은 이해가 가지만 첫번째(The Global Scope)는 전혀 실용성이 없는 언어의 잘못된 설계라고 생각이 듭니다.
While most of these cases make sense, the first one is to be considered another mis-design of the language, as it never has any practical use. 
1.Foo.method = function() {
2.    function test() {
3.        // this is set to the global object
4.    }
5.    test();
6.}
위 소스의 경우 일반적으로 test 안의 this Foo 를 참조하고 있다고 잘못 생각하고 있습니다. 하지만 사실은 그렇지가 않습니다.
A common misconception is that this inside of test refers to Foo, while in fact it does not. 

test 안에서 Foo 에 접근하기 위해서는 메소드(method) 안에 Foo 를 참조하는 지역 변수를 생성해야 합니다.
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. 
1.Foo.method = function() {
2.    var that = this;
3.    function test() {
4.        // Use that instead of this here
5.    }
6.    test();
7.}

여기서 that 은 단지 평범한 변수명일뿐이지만 일반적으로 외부의 this 를 참조하기 위해 사용됩니다.
또한, this 의 값을 주변에 전달하기 위해 클로저(closure)와 함께 사용될 수도 있습니다.
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

JavaScript 에서 정상적으로 실행되지 않는 또 한가지가 있는데 그것은 함수에 이름을 다시 부여(function aliasing)하는 것입니다. 즉 변수에 메소드를 할당한다는 것입니다.
Another thing that does not work in JavaScript is function aliasing, that is, assigning a method to a variable. 
1.var test = someObject.methodTest;
2.test();
이제 test 는 일반적인 함수처럼 호출이 됩니다. 따라서 그 안에서의 this 는 더 이상 someObject 를 참조하지 않게 됩니다.
Due to the first case test now acts like a plain function call; therefore, this inside it will no longer refer to someObject. 

이러한 this 에 대한 늦은 바인딩이 처음에는 좋지 않은 아이디어로 보이지만 사실 이것이 프로토타입 기반의 상속(prototypal inheritance)을 가능하게 하는 것입니다.
While the late binding of this might seem like a bad idea at first, it is in fact what makes prototypal inheritance work. 
1.function Foo() {}
2.Foo.prototype.method = function() {};
3. 
4.function Bar() {}
5.Bar.prototype = Foo.prototype;
6. 
7.new Bar().method();
Bar 의 인스턴스가 method 를 호출하면 this 는 바로 그 인스턴스를 참조하게 됩니다.
When method gets called on a instance of Bar, this will now refer to that very instance. 



Closures and References

JavaScript 의 가장 강력한 특성 중에 하나가 클로저를 사용할 수 있다는 것입니다. 이것은 자신이 선언된 곳의 바깥 범위에 항상 접근이 가능하다는 것을 의미합니다. JavaScript 에서는 함수 유효 범위(function scope)만을 가지고 있기 때문에 기본적으로 모든 함수는 클로저로써 실행이 됩니다.
One of JavaScript's most powerful features is the availability of closures, this means that scopes always keep access to the outer scope they were defined in. Since the only scoping that JavaScript has is function scope, all functions, by default, act as closures. 

Emulating private variables
01.function Counter(start) {
02.    var count = start;
03.    return {
04.        increment: function() {
05.            count++;
06.        },
07. 
08.        get: function() {
09.            return count;
10.        }
11.    }
12.}
13. 
14.var foo = Counter(4);
15.foo.increment();
16.foo.get(); // 5
여기에서 Counter 는 두 가지의 클로저, 즉 increment 와 get 함수를 반환합니다.
이 두 가지 함수 모두 Counter 의 범위에 있는 참조를 유지하고 있으며 따라서 그 범위 안에서 선언된 count 변수에 항상 접근이 가능합니다.
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. 

Why Private Variables Work

JavaScript 에서는 범위에 대한 참조나 할당이 불가능하기 때문에 바깥 범위에서 count 변수를 접근할 수 있는 방법이 없습니다. 오직 두개의 클로저를 통해서만이 접근이 가능합니다.
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. 
1.var foo = new Counter(4);
2.foo.hack = function() {
3.    count = 1337;
4.};
위 코드에서 foo.hack 은 같은 범위에서 선언된 것이 아니기 때문에 Counter 의 범위 안에 있는 count 변수는 변하지 않게 됩니다. foo.hack 안의 count 변수는 오버라이드되는 것이 아니라 전역변수 count 가 생성되는 것입니다.
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

한가지 자주하는 실수는 마치 loop 의 인덱스(index) 변수를 복사하는 것처럼 loop 의 안에서 클로저를 사용한다는 것입니다.
One often made mistake is to use closures inside of loops, as if they were copying the value of the loops index variable. 
1.for(var i = 0; i < 10; i++) {
2.    setTimeout(function() {
3.        console.log(i); 
4.    }, 1000);
5.}
위의 결과는 숫자 0부터 9까지를 출력하지 않습니다. 단지 숫자 10이 열번 출력될 뿐입니다.
The above will not output the numbers 0 through 9, but will simply print the number 10 ten times. 

setTimeout 안의 익명 함수는 i 의 참조를 유지하고 있으며 console.log 가 호출되는 순간에는 이미 for loop 가 종료가 된 상태입니다. 그 때 i 의 값은 10으로 할당되어 있는 상태입니다.
The anonymous function keeps a reference to i and at the time console.log gets called, the for loop has already finished and the value of i as been set to 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

loop 의 인덱스 변수의 값을 복사하기 위해서는 익명의 랩퍼(anonymous wrapper)를 사용하는 것이 가장 좋습니다.
In order to copy the value of the loop's index variable, it is best to use an anonymous wrapper. 
1.for(var i = 0; i < 10; i++) {
2.    (function(e) {
3.        setTimeout(function() {
4.            console.log(e); 
5.        }, 1000);
6.    })(i);
7.}
바깥쪽의 익명 함수가 i 를 첫번째 인수로 하여 바로 즉시 호출이 되면 매개변수 e 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. 

setTimeout 에 전달된 익명 함수는 이제 loop 에 의해 바뀌지 않는 값인 e 를 참조하게 됩니다.
The anonymous function that gets passed to setTimeout now has a reference to e, whose value does not get changed by the loop. 

또 다른 방법은 익명의 랩퍼(anonymous wrapper)로부터 함수를 반환받는 것입니다. 이것은 위 코드와 동일한 기능을 수행하게 될 것입니다.
There is another possible way of achieving this; that is to return a function from the anonymous wrapper, that will then have the same behavior as the code above. 
1.for(var i = 0; i < 10; i++) {
2.    setTimeout((function(e) {
3.        return function() {
4.            console.log(e);
5.        }
6.    })(i), 1000)
7.}


The arguments Object

JavaScript 는 모든 함수 범위에서 arguments 라는 특별한 변수를 가지고 있습니다. 이 변수는 함수에 전달되는 모든 인수들의 목록을 가지고 있습니다.
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. 

arguments 객체는 배열(Array)은 아닙니다. length 라는 이름의 프로퍼티도 있는 것처럼 어느정도 배열의 의미를 가지고는 있지만 Array.prototype 을 상속받지 않는 사실은 객체(Object)일 뿐입니다.
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. 

그렇기 때문에 arguments 에는 push, pop, slice 와 같은 배열의 표준 메소드를 사용할 수 없는 것입니다. 보통의 for loop 를 사용하여 열거(반복)는 잘 되겠지만 배열(Array)의 표준 메소드를 사용하기 위해서는 실제 배열(Array)로 변환해야만 합니다.
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

아래의 코드는 arguments 객체의 모든 요소(element)를 포함한 새로운 배열(Array)을 반환하게 됩니다.
The code below will return a new Array containing all the elements of the arguments object. 
1.Array.prototype.slice.call(arguments);
이와 같은 변환 작업은 속도가 느려서 코드의 성능 임계지역(critical sections)에서 사용하는 것은 권장하지 않습니다.
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. 
1.function foo() {
2.    bar.apply(null, arguments);
3.}
4.function bar(a, b, c) {
5.    // do stuff here
6.}
또 다른 편법은 빠르고, 바운드되지 않는 랩퍼(wrapper) 를 생성하기 위해 call apply 를 함께 사용하는 것입니다.
Another trick is to use both call and apply together to create fast, unbound wrappers. 
01.function Foo() {}
02. 
03.Foo.prototype.method = function(a, b, c) {
04.    console.log(this, a, b, c);
05.};
06. 
07.// Create an unbound version of "method"
08.// It takes the parameters: this, arg1, arg2...argN
09.Foo.method = function() {
10. 
11.    // Result: Foo.prototype.method.call(this, arg1, arg2... argN)
12.    Function.call.apply(Foo.prototype.method, arguments);
13.};
Formal Parameters and Arguments Indices

arguments 객체는 함수의 공식적인(형식상의) 매개변수와 마찬가지로 자신의 프로퍼티에 대한 getter 와 setter 를 생성합니다.
The arguments object creates getter and setter functions for both its properties as well as the function's formal parameters.
 
결국 다시 말해서 공식적인 매개변수의 값이 변경되면 arguments 객체의 해당 프로퍼티의 값도 변경이 된다는 것입니다.
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. 
01.function foo(a, b, c) {
02.    arguments[0] = 2;
03.    a; // 2                                                          
04. 
05.    b = 4;
06.    arguments[1]; // 4
07. 
08.    var d = c;
09.    d = 9;
10.    c; // 3
11.}
12.foo(1, 2, 3);

Performance Myths and Truths

arguments 객체는 "arguments"를 함수 안에서 변수명으로 사용을 하거나 함수의 공식적인 매개변수명으로 사용하는 경우에만 예외를 발생시킵니다. 사용을 하든지 안 하든지는 문제가 되지 않습니다.
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. 

getter 와 setter 는 둘 다 항상 생성됩니다. 따라서 그것을 사용하는 것은 대개의 경우 성능에 아무런 영향을 끼치지 않습니다. 특히, 간단히 arguments 객체의 프로퍼티에 접근하는 것이 아닌 실제 코드에서는 더더욱 영향을 끼치지 않습니다.
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. 

그러나, 최근의 JavaScript 엔진에서는 성능이 급격하게 감소되는 경우가 하나 있는데 바로 arguments.callee 를 사용하는 경우입니다.
However, there is one case which will drastically reduce the performance in modern JavaScript engines. That case is the use of arguments.callee. 
01.function foo() {
02.    arguments.callee; // do something with this function object
03.    arguments.callee.caller; // and the calling function object
04.}
05. 
06.function bigLoop() {
07.    for(var i = 0; i < 100000; i++) {
08.        foo(); // Would normally be inlined...
09.    }
10.}
위 코드에서 foo 는 자기 자신과 자신의 호출자를 모두 알아야 하기 때문에 더 이상 inlining 의 대상이 될 수 없습니다.(?)
이것은 단지 inlining 으로부터 얻을 수 있는 성능상의 이점을 얻을 수 없게 하는 것 뿐만이 아니라 함수가 명시적인 호출문맥(calling context)상에 종속되어 버리기 때문에 캡슐화(encapsulation)에도 어긋나게 됩니다.
In the above code, foo can no longer be a subject to inlining since it needs to know about both itself and its caller. This not only defeats possible performance gains that would arise from inlining, it also breaks encapsulation since the function may now be dependent on a specific calling context. 

arguments.callee 나 그것의 어떠한 프로퍼티도 사용하지 말 것을 강력히 권장합니다.
It is highly recommended to never make use of arguments.callee or any of its properties. 



Constructors

JavaScript 에서 생성자(constructor)는 다른 많은 언어들과는 조금 다릅니다. new 키워드를 앞에 두고 어떤 함수를 호출하면 그 함수는 생성자로써 실행이 됩니다.
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. 

생성자를 호출하면 그 안의 this 의 값은 새로 생성된 객체(Object)를 참조하게 됩니다. 이 새로 생성된 객체의 prototype 에는 생성자로써 호출된 함수 객체의 prototype 이 할당됩니다.
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. 

호출된 함수가 명시적으로 return 구문을 사용하지 않았다면 암묵적으로 새로 생성된 객체인 this 를 반환하게 됩니다.
If the function that was called has no explicit return statement, then it implicitly returns the value of this - the new object. 
01.function Foo() {
02.    this.bla = 1;
03.}
04. 
05.Foo.prototype.test = function() {
06.    console.log(this.bla);
07.};
08. 
09.var test = new Foo();
위 코드는 생성자로 Foo 를 호출하고 새로 생성된 객체의 prototype Foo.prototype 를 할당합니다.
The above calls Foo as constructor and sets the prototype of the newly created object to Foo.prototype. 

명시적으로 return 구문을 사용한 경우에는 그 구문에서 지정한 값을 반환하게 되지만 그 반환값이 객체일때만 그렇습니다.
In case of an explicit return statement the function returns the value specified that statement, but only if the return value is an Object. 
01.function Bar() {
02.    return 2;
03.}
04.new Bar(); // a new object
05. 
06.function Test() {
07.    this.value = 2;
08. 
09.    return {
10.        foo: 1
11.    };
12.}
13.new Test(); // the returned object
new 키워드를 빠뜨리게 되면 함수는 새로운 객체를 반환하지 않게 됩니다.
When the new keyword is omitted, the function will not return a new object. 
1.function Foo() {
2.    this.bla = 1; // gets set on the global object
3.}
4.Foo(); // undefined
위 예제의 경우 정상적으로 수행은 되지만 this 의 값이 전역 객체가 됩니다.
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

new 키워드를 빠뜨릴 가능성에 대비하기 위해서는 생성자 함수에서 값을 명시적으로 반환해줘야 합니다.
In order to be able to omit the new keyword, the constructor function has to explicitly return a value. 
01.function Bar() {
02.    var value = 1;
03.    return {
04.        method: function() {
05.            return value;
06.        }
07.    }
08.}
09.Bar.prototype = {
10.    foo: function() {}
11.};
12. 
13.new Bar();
14.Bar();
위에서 두개의 Bar 호출은 정확히 똑같은 것을 반환하는데 그것은 method 라고 하는 프로퍼티를 가지고 있는 새로 생성된 객체이며 그것은 클로저(Closure)입니다.
Both calls to Bar return the exact same thing, a newly create object which has a property called method on it, that is a Closure. 

또한 주목해야 할 것은 new Bar() 의 호출은 반환되는 객체의 프로토타입에 영향을 끼치지 않는다는 것입니다. 그 프로토타입은 새로 생성된 객체에 할당될 것입니다. Bar 는 그 새로운 객체를 반환하는 것이 아닙니다.
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. 

위 예제에서는 new 키워드를 사용하든 안하든 기능적으로 차이가 없습니다.
In the above example, there is no functional difference between using and not using the new keyword. 

Creating New Objects via Factories

자주 권장되는 것은 빠뜨리면 버그를 유발할 수 있는 new 를 사용하지 않는 것입니다.
An often made recommendation is to not use new since forgetting its use may lead to bugs. 

새로운 객체를 생성하기 위해서는 차라리 하나의 팩토리를 사용하여 그 팩토리 안에서 새로운 객체를 구성하라는 것입니다.
In order to create new object, one should rather use a factory and construct a new object inside of that factory. 
01.function Foo() {
02.    var obj = {};
03.    obj.value = 'blub';
04. 
05.    var private = 2;
06.    obj.someMethod = function(value) {
07.        this.value = value;
08.    }
09. 
10.    obj.getPrivate = function() {
11.        return private;
12.    }
13.    return obj;
14.}
위 코드는 new 키워드의 실수에 대해 안전하고 private 변수의 사용을 확실히 쉽게 해주지만 반면에 몇가지 단점이 있습니다.
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. 상속을 하려면 그 팩토리는 다른 객체의 모든 메소드를 복사하거나 새로운 객체의 프로토타입에 그 객체를 할당해줘야만 합니다.
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. new 키워드를 빠뜨렸다고해서 프로토타입 체인이 끊어지게 되는 것은 어찌됐던간에 언어의 철학적인 면에도 위배됩니다.
Dropping the prototype chain just because of a left out new keyword somehow goes against the spirit of the language. 

In Conclusion

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 stick with it. 



Scopes and Namespaces

비록 JavaScript 가 블럭을 지정하기 위해 중괄호 두개의 쌍을 문법으로 사용하고 있지만 블럭 범위를 지원하지는 않습니다. 함수 범위만을 지원하고 있습니다.
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 is in the language is function scope. 
1.function test() { // a scope
2.    for(var i = 0; i < 10; i++) { // not a scope
3.        // count
4.    }
5.    console.log(i); // 10
6.}
또한 JavaScript 에서는 명확한 네임스페이스가 없는데 그것은 모든 것이 전역적으로 공유된 네임스페이스에서 정의된다는 것을 의미합니다.
There are also no distinct namespaces in JavaScript, that means that everything gets defined in one globally shared namespace. 

변수는 매순간 참조가 되는데 JavaScript 는 그 변수를 찾을 때까지 현재 범위에서 상위 범위로 올라가면서 모든 범위를 순회합니다. 그러다가 마지막 전역 범위에서도 요청한 변수명을 찾지 못하면 ReferenceError 를 발생시킵니다.
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
1.// script A
2.foo = '42';
3. 
4.// script B
5.var foo = '42'
위 두개의 스크립트는 같은 결과가 나오지 않습니다. 스크립트 A 는 전역 범위에 foo 라고 하는 변수를 선언하는 것이고
스크립트 B 는 현재 범위에 foo 를 선언하는 것입니다.
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. 

다시 말하지만 조금도 같은 결과가 나오지 않습니다. var 를 사용하지 않는 것은 중요한 의미를 내포할 수도 있는 것입니다.
Again, that is not at all the same effect, not using var can have major implications. 
1.// global scope
2.var foo = 42;
3.function test() {
4.    // local scope
5.    foo = 21;
6.}
7.test();
8.foo; // 21
test 함수 안에서 var 구문을 빠뜨리게 되면 foo 의 값을 오버라이드 하게 됩니다. 이것이 처음에는 큰 문제가 아닌 것 같지만 수천라인의 JavaScript 에서 var 를 사용하지 않게 되면 끔찍함을 선사하게 될 것이고 버그를 찾느라 힘들어지게 될 것입니다.
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 and hard to track down bugs. 
01.// global scope
02.var items = [/* some list */];
03.for(var i = 0; i < 10; i++) {
04.    subLoop();
05.}
06. 
07.function subLoop() {
08.    // scope of subLoop
09.    for(i = 0; i < 10; i++) { // missing var statement
10.        // do amazing stuff!
11.    }
12.}
subLoop 에서 전역변수 i 를 덮어써버리기 때문에 바깥쪽 loop 는 subLoop 를 처음 한번 호출한 후에 종료하게 됩니다. 두번째 for loop 에서 var 를 사용하면 이런 오류를 쉽게 피할 수 있습니다. 원하는 결과가 바깥 범위에 영향을 끼치는 것이 아니라면 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. 

Local Variables

JavaScript 에서는 함수(function)의 매개변수와 var 구문으로 선언된 변수만이 지역변수에 해당합니다.
The only source for local variables in JavaScript are function parameters and variables that were declared via the var statement. 
01.// global scope
02.var foo = 1;
03.var bar = 2;
04.var i = 2;
05. 
06.function test(i) {
07.    // local scope of the function test
08.    i = 5;
09. 
10.    var foo = 3;
11.    bar = 4;
12.}
13.test(10);
foo i test 함수 범위의 지역 변수인 반면에 bar 에 값을 할당한 것은 같은 이름의 전역 변수를 오버라이드하게 되는 것입니다.
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 는 선언문들을 위쪽으로 이동시킵니다. 이 말은 var 구문과 함수(function) 선언을 현재 유효 범위의 가장 상단으로 옮긴다는 것입니다.
JavaScript hoists declarations. This means that both var statements and function declarations will be moved to the top of their enclosing scope. 
01.bar();
02.var bar = function() {};
03.var someValue = 42;
04. 
05.test();
06.function test(data) {
07.    if (false) {
08.        goo = 1;
09. 
10.    } else {
11.        var goo = 2;
12.    }
13.    for(var i = 0; i < 100; i++) {
14.        var e = data[i];
15.    }
16.}
위 코드는 프로그램 실행 전에 변형이 됩니다. JavaScript 는 var 구문과 함수(function선언을 함께 현재 가장 가까이 둘러싸고 있는 범위에서 가장 상단으로 이동을 시킵니다.
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 nearest surrounding scope. 
01.// var statements got moved here
02.var bar, someValue; // default to 'undefined'
03. 
04.// the function declartion got moved up too
05.function test(data) {
06.    var goo, i, e; // missing block scope moves these here
07.    if (false) {
08.        goo = 1;
09. 
10.    } else {
11.        goo = 2;
12.    }
13.    for(i = 0; i < 100; i++) {
14.        e = data[i];
15.    }
16.}
17. 
18.bar(); // fails with a TypeError since bar is still 'undefined'
19.someValue = 42; // assignments are not affected by hoisting
20.bar = function() {};
21. 
22.test();
블럭 범위를 지원하지 않기 때문에 loop 바깥쪽의 var 구문뿐만 아니라 안쪽의 var 구문도 옮겨지게 됩니다. 또한 비직관적으로 구성된 if 구문에 대해 정확한 결과를 만들어줄 것입니다.
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. 

실제 코드에서 if 구문은 전역변수 goo 를 수정하는 것처럼 보이지만 실제로는 hoisting 이 적용된 후에 지역변수를 수정하게 됩니다.
In the original code the if statement seemed to modify the global variable goo, while actually it modifies the local variable - after hoisting has been applied. 

hoisting 에 대한 지식이 없다면 아래 코드는 ReferenceError 를 발생하는 것처럼 보입니다.
Without the knowledge about hoisting, below code might seem to raise a ReferenceError. 
1.// check whether SomeImportantThing has been initiliazed
2.if (!SomeImportantThing) {
3.    var SomeImportantThing = {};
4.}
하지만 당연하게도 var 구문이 전역 범위의 상단으로 이동하기 때문에 위 코드는 정상적으로 수행이 됩니다.
But of course, the above works due to the fact that the var statement is being moved to the top of the global scope. 
1.var SomeImportantThing;
2. 
3.// other code might initiliaze SomeImportantThing here, or not
4. 
5.// make sure it's there
6.if (!SomeImportantThing) {
7.    SomeImportantThing = {};
8.}
Name Resolution Order

JavaScript 는 전역 범위를 포함한 모든 범위에서 현재 객체를 참조하고 있는 특별한 이름의 this 를 가지고 있습니다.
All scopes in JavaScript, including the global scope, have the special name this defined in them, which refers to the current object. 

또한 함수 범위에는 그 함수에 전달되는 인수들을 포함하고 있는 arguments 를 가지고 있습니다.
Function scopes also have the name arguments defined in them which contains the arguments that were passed to a function. 

예를 들어 함수 범위내에서 foo 라는 이름의 변수를 접근하려고 하면 JavaScript 는 다음 순서에 따라 그 이름을 찾게 됩니다.
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: 

1. 현재 범위내에 var foo 구문이 있는 경우 그것을 사용합니다.
In case there is a var foo statement in the current scope use that. 
2. 함수의 매개변수 중 하나의 이름이 foo 라면 그것을 사용합니다.
If one of the function parameters is named foo use that. 
3. foo 를 호출한 함수가 자기 자신이라면 그것을 사용합니다.
If the function itself is called foo use that. 
4. 다음 바깥쪽 범위로 가서 1번부터 다시 수행합니다.
Go to the next outer scope and start with #1 again. 

Namespaces

하나의 전역 네임스페이스만을 가졌을때의 일반적인 문제는 변수명의 충돌이 있는 곳에서 문제가 발생한다는 것입니다. JavaScript 에서 이 문제는 익명의 랩퍼(anonymous wrapper)를 사용하여 쉽게 피할 수 있습니다.
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. 
1.(function() {
2.    // a self contained "namespace"
3. 
4.    window.foo = function() {
5.        // an exposed closure
6.    };
7. 
8.})(); // execute the function immediately
이름이 없는 함수는 신중히 고려되어야 할 표현식(expressions)입니다. 그래서 호출하기 위해서는 우선 평가가 되어야만 합니다.
Unnamed functions are considered expressions; so in order to being callable, they must first be evaluated. 
1.( // evaluate the function inside the paranthesis
2.function() {}
3.) // and return the function object
4.() // call the result of the evaluation
함수 표현식을 평가하고 호출하는 두가지 방법이 있는데 그것들은 문법은 다르지만 정확히 동일하게 실행됩니다.
There are other ways for evaluating and calling the function expression; which, while different in syntax, do behave the exact same way. 
1.// Two other ways
2.+function(){}();
3.(function(){}());
In Conclusion

자신만의 네임스페이스에서 코드를 캡슐화하기 위해서는 항상 익명의 랩퍼(anonymous wrapper)를 사용할 것을 권장합니다. 이것은 단지 변수명의 충돌에 대해서 코드를 보호하는 것 뿐만 아니라 프로그램에 더 나은 모듈화를 제공해주기도 합니다.
It is recommended to always use an anonymous wrapper for encapsulating code in its own namespace. This does not only protect code against name clashes, 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 Iteration and Properties

JavaScript 에서 배열은 객체이긴 하지만 그들을 열거하기 위해서 for in loop 를 사용해야 할 이유는 없습니다. 사실 for in 을 사용하지 말아야 할 많은 이유들이 있습니다.
Although arrays in JavaScript are objects, there are no good reasons to use the for in loop in for iteration on them. In fact there are a number of good reasons against the use of for in on arrays. 

for in loop 는 프로토타입 체인 상의 모든 프로퍼티를 열거하게 되며 그 프로퍼티를 제외할 수 있는 유일한 방법이 hasOwnProperty 을 사용하는 것이기 때문에 그것은 이미 일반적인 for loop 보다 스무배 정도는 더 늦게 됩니다.
Since the for in loop enumerates all the properties that are on the prototype chain and the only way to exclude those properties is to use hasOwnProperty, it is already up to twenty times slower than a normal for loop. 

Iteration

배열을 열거시킬때 가장 뛰어난 성능을 보이기 위해서 가장 좋은 방법은 전형적인 for loop 를 사용하는 것입니다.
In order to achieve the best performance when iterating over arrays, it is best to use the classic for loop. 
1.var list = [1, 2, 3, 4, 5, ...... 100000000];
2.for(var i = 0, l = list.length; i < l; i++) {
3.    console.log(list[i]);
4.}
위 예제에서 한가지 짚고 넘어가야 할 것이 있는데 그것은 l = list.length 와 같이 배열의 length 를 별도로 저장한다는 것입니다.
There is one extra catch in the above example, that is the caching of the length of the array via l = list.length. 

비록 length 가 배열 자체에 정의되어 있는 프로퍼티임에도 불구하고 loop 를 매번 반복할때는 검색을 수행하는데 overhead(성능상 비용)가 발생합니다. 물론 최근의 JavaScript 엔진의 경우 이런 경우 최적화를 시키긴 하지만 코드가 새로운 엔진에서 수행이 되는지 아닌지를 따질 것은 없습니다.
Although the length property is defined on the array itself, there is still an overhead for doing the lookup on each iteration of the loop. And while recent JavaScript engines may apply optimization in this case, there is no way of telling whether the code will run on one of these newer engines or not. 

사실 length 를 따로 저장을 하지 않으면 따로 저장하는 것에 비해서 속도가 반정도밖에는 나오지 않습니다.
In fact, leaving out the caching may result in the loop being only half as fast as with the cached length. 

The length Property

length 프로퍼티의 getter 는 단순히 배열이 포함하고 있는 요소의 갯수를 반환하는데 비해서 setter 는 배열을 비우는데에도 사용될 수가 있습니다.
While the getter of the length property simply returns the number of elements that are contained in the array, the setter can be used to truncate the array. 
1.var foo = [1, 2, 3, 4, 5, 6];
2.foo.length = 3;
3.foo; // [1, 2, 3]
4. 
5.foo.length = 6;
6.foo; // [1, 2, 3]
length 에 작은 수를 할당하면 배열을 비울 수는 있지만 length 를 증가시켜도 그 배열에는 아무런 영향도 없습니다.
Assigning a smaller length does truncate the array, but increasing the length does not have any effect on the array. 

In Conclusion

최고의 성능을 내기 위해서는 항상 일반적인 for loop 를 사용하고 length 프로퍼티를 따로 저장하는 것을 권장합니다. 배열에서 for in 을 사용하는 것은 버그와 좋지 않은 성능을 유발하는 안좋은 코드를 작성했다는 신호입니다.
For the best performance it is recommended to always use the plain for loop and cache the length property. The use of for in on an array is a sign of badly written code that is prone to bugs and bad performance. 



The Array Constructor

배열(Array생성자는 매개변수를 다루는 방법에 있어서 모호한 면이 있기 때문에 새로운 배열을 생성할때는 [ ] 구문을 쓰는 배열 리터럴을 사용할 것을 강력히 권장하고 있습니다.
Since the Array constructor is ambiguous in how it deals with its parameters, it is highly recommended to always use the array literals - [] notation - when creating new arrays. 
1.[1, 2, 3]; // Result: [1, 2, 3]
2.new Array(1, 2, 3); // Result: [1, 2, 3]
3. 
4.[3]; // Result: [3]
5.new Array(3); // Result: []
6.new Array('3') // Result: ['3']
배열(Array)의 생성자에 전달되는 인자가 하나뿐이고 그 인자가 숫자(Number)일 경우에는 그 생성자는 length 프러퍼티에 그 인자의 값을 할당한 비어있는 새 배열을 반환할 것입니다. 여기서 주목해야 할 점은 실제 배열의 색인값이 초기화되는 것이 아니라 단지 새 배열의 length 프로퍼티의 값만이 설정될 뿐이라는 것입니다.
In cases when there is only one argument passed to the Array constructor, and that argument is a Number, the constructor will return a new sparse array with the length property set to the value of the argument. It should be noted that only the length property of the new array will be set this way, the actual indexes of the array will not be initialized. 
1.var arr = new Array(3);
2.arr[1]; // undefined
3.1 in arr; // false, the index was not set
배열의 초기 length 값을 설정하는 일은 for loop 코드를 사용하지 않고 한 문자열을 반복하는 일과 같은 몇가지의 경우에만 유용할 뿐입니다.
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. 
1.new Array(count + 1).join(stringToRepeat);
In Conclusion

배열(Array)의 생성자를 사용하는 것은 가능한 피해야만 합니다. 리터럴을 사용하는 것이 확실히 더 좋은 방법입니다. 그것이 더 짧고 더 명확한 문법을 가지고 있습니다. 따라서, 그것은 코드의 가독성 또한 높이게 됩니다.
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. 



Types


Equality and Comparisons

JavaScript 는 object 의 값이 동등한지를 비교하는 두가지 다른 방법을 가지고 있습니다.
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 는 느슨한 타입 특성을 가지고 있는데 이것은 동등연산자가 그들을 비교하기 위해서 강제로 형변환을 한다는 것을 의미하기도 합니다.
JavaScript features weak typing. This means that the equality operator coerces types in order to compare them. 
01.""           ==   "0"           // false
02.0            ==   ""            // true
03.0            ==   "0"           // true
04.false        ==   "false"       // false
05.false        ==   "0"           // true
06.false        ==   undefined     // false
07.false        ==   null          // false
08.null         ==   undefined     // true
09." \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 exactly like the normal equality operator, except that strict equality operator does not perform type coercion between its operands. 
01.""           ===   "0"           // false
02.0            ===   ""            // false
03.0            ===   "0"           // false
04.false        ===   "false"       // false
05.false        ===   "0"           // false
06.false        ===   undefined     // false
07.false        ===   null          // false
08.null         ===   undefined     // false
09." \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

===== 둘 다 동등연산자로써 명시적이긴 하지만 피연산자들중 하나라도 객체(Object)인 경우에는 다르게 수행을 합니다.
While both == and === are stated as equality operators, they behave different when at least one of their operands happens to be an Object. 
1.{} === {};                   // false
2.new String('foo') === 'foo'; // false
3.new Number(10) === 10;       // false
4.var foo = {};
5.foo === foo;                 // true
여기에서는 두개의 피연산자가 동일한지를 비교하는데 결과는 동일하지 않는 것으로 나옵니다. 그것은 그 객체의 같은 인스턴스인지를 비교하게 되는 것인데 마치 Python 의 is 나 C 의 포인터 비교와 같습니다.
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

엄격한 동등연산자만을 사용할 것을 강력히 권장합니다. 강제 형변환이 필요한 곳인 경우라도 명시적으로(explicitly) 형변환을 해서 언어 자체의 복잡한 강제 변환 규칙을 남겨두어서는 안됩니다.
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

typeof 연산자는(instanceof 와 함께) 아마 JavaScript 에서 가장 큰 설계적 결함일 것입니다. 
The typeof operator (together with instanceof) is probably the biggest design flaw of JavaScript, as it is near of being completely broken. 

instanceof 는 아직 제한적이나마 사용을 하고 있지만 typeof 는 실제 사용하는 경우가 정말 한가지 뿐입니다. 그것은 객체의 타입이 체크가 되지 않는 경우입니다.
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 object. 

The JavaScript Type Table
01.Value               Class      Type
02.-------------------------------------
03."foo"               String     string
04.new String("foo")   String     object
05.1.2                 Number     number
06.new Number(1.2)     Number     object
07.true                Boolean    boolean
08.new Boolean(true)   Boolean    object
09.new Date()          Date       object
10.new Error()         Error      object
11.[1,2,3]             Array      object
12.new Array(1, 2, 3)  Array      object
13.new Function("")    Function   function
14./abc/g              RegExp     object (function in Nitro/V8)
15.new RegExp("meow")  RegExp     object (function in Nitro/V8)
16.{}                  Object     object
17.new Object()        Object     object
위 테이블에서 Type 은 typeof 연산자가 반환하는 그 값을 말합니다. 분명히 볼 수 있듯이 이 값은 무엇이 되던간에 일관성이 있습니다.
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. 

Class 는 객체의 내부 속성인 [[Class]] 의 값을 말합니다.
The Class refers to the value of the internal [[Class]] property of an object. 

[[Class]] 의 값을 얻기 위해서는 먼저 Object.prototypetoString 메소드를 사용해야만 합니다.
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

명세서(specification)에는 [[Class]] 의 값에 접근하기 위해서 Object.prototype.toString 을 사용하는 방법을 알려주고 있습니다.
The specification gives exactly one way of accessing the [[Class]] value, with the use of Object.prototype.toString. 
1.function is(type, obj) {
2.    var clas = Object.prototype.toString.call(obj).slice(8, -1);
3.    return obj !== undefined && obj !== null && clas === type;
4.}
5. 
6.is('String', 'test'); // true
7.is('String', new String('test')); // true
위의 예제에서는 Object.prototype.toStringthis 의 값과 함께 호출되는데 이 this 에는 찾고자 하는 [[Class]] 의 값을 가지고 있는 객체가 할당되어 있습니다.
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
1.typeof foo !== 'undefined'
위에서는 foo 가 실제 선언이 되었는지 아닌지를 체크하게 될 것입니다. 선언이 되지 않은 상태에서 foo 를 참조하게 되면 ReferenceError 를 발생시킵니다. 이것이 typeof 가 실제로 유용하게 쓰이는 유일한 한가지입니다.
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

객체의 타입을 체크하기 위해서는 Object.prototype.toString 을 사용할 것을 강력히 권장합니다. 이것이 신뢰할 수 있는 유일한 방법입니다. 위의 타입 테이블에서 보았던 것처럼 typeof 의 어떤 반환값들은 명세서에 정의되지 않은 것들도 있습니다. 따라서 그것들은 다양한 구현(엔진)마다 달라질 수 있습니다.
In order to check the type of an object, it is highly recommended to use Object.prototype.toString; as 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. 

변수가 선언되었는지 안되었는지의 체크 여부와 상관없이 어떤 희생을 치르더라도 typeof 는 피해야만 합니다.
Unless checking whether a variable is defined, typeof should be avoided at all costs. 



The instanceof Operator

instanceof 연산자는 두 피연산자의 생성자를 비교합니다. 이것이 유용한 경우는 사용자 정의 객체를 비교하는 경우뿐입니다. 내장타입(원시데이터)에 사용하는 것은 typeof 연산자와 마찬가지로 거의 쓸모가 없습니다.
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
01.function Foo() {}
02.function Bar() {}
03.Bar.prototype = new Foo();
04. 
05.new Bar() instanceof Bar; // true
06.new Bar() instanceof Foo; // true
07. 
08.// This just sets Bar.prototype to the function object Foo
09.// But not to an actual instance of Foo
10.Bar.prototype = Foo;
11.new Bar() instanceof Foo; // false
Using instanceof with Native Types
1.new String('foo') instanceof String; // true
2.new String('foo') instanceof Object; // true
3. 
4.'foo' instanceof String; // false
5.'foo' instanceof Object; // false
여기에서 주목해야 할 한가지 중요한 것은 instanceof 는 서로 다른 JavaScript 컨텍스트(예를 들어 웹 브라우저의 서로 다른 document)의 객체간에서는 작동이 되지 않는다는 것입니다. 그들의 생성자가 정확히 동일한 객체가 되지 않기 때문입니다.
One important thing to note here is, that instanceof does not work on objects that origin from different JavaScript contexts (e.g. different documents in a web browser), since their constructors will not be the exact same object. 

In Conclusion

instanceof 연산자는 같은 JavaScript 컨텍스트 상에 있는 사용자 정의 객체를 다룰 때에만 유용할 뿐입니다. typeof 연산자와 마찬가지로 다른 모든 곳에서의 사용은 피해야만 합니다.
The instanceof operator should only be used when dealing with custom made objects that origin from the same JavaScript context. Just like the typeof operator, every other use of it should be avoided. 



Type Casting

JavaScript 는 느슨한 타입의 언어입니다. 때문에 가능한 곳에서는 강제 형변환이 이루어집니다.
JavaScript is a weakly typed language, so it will apply type coercion wherever possible. 
01.// These are true
02.new Number(10) == 10; // Number.toString() is converted
03.                      // back to a number
04. 
05.10 == '10';           // Strings gets converted to Number
06.10 == '+10 ';         // More string madness
07.10 == '010';          // And more
08.isNaN(null) == false; // null converts to 0
09.                      // which of course is not NaN
10. 
11.// These are false
12.10 == 010;
13.10 == '-10';
위와 같은 상황을 피하기 위해서는 엄격한 동등연산자(strict equal operator)를 사용할 것을 강력히 권장드립니다. 물론 이것이 일반적인 함정들을 많은 부분 피해갈 수는 있다 하더라도 JavaScript 의 느슨한 타입 시스템으로 인해 발생하는 더 많은 이슈들은 여전히 존재합니다
In order to avoid the 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

Number String 과 같은 내장타입의 생성자들은 new 키워드가 있을때와 없을때가 서로 다르게 실행이 됩니다.
The constructors of the built in types like Number and String behave differently when being used with the new keyword and without it. 
1.new Number(10) === 10;     // False, Object and Number
2.Number(10) === 10;         // True, Number and Number
3.new Number(10) + 0 === 10; // True, due to implicit conversion
Number 같은 내장타입을 생성자로써 사용하면 새로운 Number 객체가 생성이 됩니다. 하지만 new 키워드를 빼먹게 되면 그냥 변환기처럼 Number 함수가 실행이 됩니다.
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. 

가장 좋은 방법은 세가지 가능한 타입 중 하나로 명시적인 변환을 하는 것입니다.
The best option is to cast to one of the three possible types explicitly. 

Casting to a String
1.'' + 10 === '10'; // true
앞에 빈 문자열을 붙여서 쉽게 string 으로 변환할 수 있습니다.
By prepending a empty string a value can easily be casted to a string. 

Casting to a Number
1.+'10' === 10; // true
+ 단항 연산자를 사용하여 number 로 변환할 수 있습니다.
Using the unary plus operator it is possible to cast to a number. 

Casting to a Boolean

not 연산자(!)를 두번 사용하여 boolean 으로 변환할 수 있습니다.
By using the not operator twice, a value can be converted a boolean. 
1.!!'foo';   // true
2.!!'';      // false
3.!!'0';     // true
4.!!'1';     // true
5.!!'-1'     // true
6.!!{};      // true
7.!!true;    // true


Core


Why Not to Use eval

eval 함수는 현재 지역 범위 안에서 JavaScript 코드로 된 문자열을 실행하게 합니다.
The eval function will execute a string of JavaScript code in the local scope. 
1.var foo = 1;
2.function test() {
3.    var foo = 2;
4.    eval('foo = 3');
5.    return foo;
6.}
7.test(); // 3
8.foo; // 1
그러나 eval 은 직접 호출될 때 그 지역 범위에서만 실행이 됩니다. 그리고 호출된 함수명이 실제로 eval 이어야만 실행이 됩니다.
But eval only executes in local scope when it is being called directly and the name of the called function is actually eval. 
01.var foo = 1;
02.function test() {
03.    var foo = 2;
04.    var bar = eval;
05.    bar('foo = 3');
06.    return foo;
07.}
08.test(); // 2
09.foo; // 3
어떻게 해서라도 eval 을 사용하는 것은 피해야만 합니다. 그것을 사용하는 99.9% 의 경우는 사용하지 않고도 뜻한바를 이룰 수 있습니다.
The use of eval should be avoided at all costs. 99.9% of its "uses" can be achieved without it. 

eval in Disguise

timeout functionsetTimeout setInterval 은 첫번째 인자로 문자열을 받을 수 있습니다. 이 문자열은 항상 전역 범위에서 실행이 되는데 그것은 이경우에 eval 이 직접 호출되는 것이 아니기 때문입니다.
The timeout functions setTimeout and setInterval can both take a string as their first argument. This string will always get executed in the global scope since eval is not being called directly in that case. 

Security Issues

또한 eval 은 주어진 어떠한 코드도 실행을 하게 됨으로써 보안 문제가 발생하게 됩니다. 알수 없는 문자열이나 출처를 신뢰할 수 없는 문자열들은 사용해서는 안됩니다.
eval also is a security problem as it executes any code given to it, it should never be used with strings of unknown or untrusted origins. 

In Conclusion

eval 은 실행중 성능이나 보안에 문제를 일으킬 수 있는 어떤 코드도 사용해서는 안됩니다. 프로그램 실행을 위해 eval 이 요구되는 경우라면 그렇게 설계한 것 자체가 문제인 것이므로 애초에 사용하지 말아야 합니다. 따라서 eval 의 사용이 요구되지 않는 더 나은 설계를 해야만 합니다.
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, its design is to be questioned and should not be used in the first place, a better design should be used, that does not require the use of eval. 



undefined and null

JavaScript 는 nothing 을 의미하는 별개의 두가지 값을 가지고 있습니다. 이들중 좀 더 유용한 것이 undefined 입니다.
JavaScript has two distinct values for nothing, the more useful of these two being undefined. 

The Value undefined

undefined 는 하나의 타입인데 이것은 정확히 undefined 라는 한가지 값만을 가지고 있습니다.
undefined is a type with exactly one value: undefined. 

또한 언어 차원에서 undefined 라는 값을 가진 전역변수를 정의해 놓고 있으며 이 변수명 또한 undefined 입니다. 그러나 이 변수는 상수가 아니며 또한 언어의 키워드도 아닙니다. 이것은 값을 쉽게 덮어쓸수 있다는 것을 의미합니다.
The language also defines a global variable that has the value of undefined, this variable is also called undefined. But this variable is not a constant, nor is it a keyword of the language. This means that its value can be easily overwritten. 

아래는 undefined 값을 반환하는 몇가지 예입니다.
Some examples for when the value undefined is returned: 

. (수정되지 않은) undefined 전역변수를 접근하는 경우
Accessing the (unmodified) global variable undefined. 
. 함수에서 return 구문을 빠뜨렸을 경우 암묵적으로 반환
Implicit returns of functions due to missing return statements. 
. return 구문에 반환할 어떠한 값도 명시하지 않았을 경우
return statements which do not explicitly return anything. 
. 존재하지 않는 프로퍼티를 찾는 경우
Lookups of non-existent properties. 
. 함수의 매개변수에 명시적으로 값을 전달하지 않은 경우
Function parameters which do not had any explicit value passed. 
. undefined 라는 값을 할당한 어떤 것이라도
Anything that has been set to the value of undefined. 

Handling Changes to the Value of undefined

전역변수 undefined 는 실제 undefined 라는 값을 복사해 넣은 것 뿐이기 때문에 새로운 값을 할당을 해도 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. 

여전히, undefined 의 값을 무엇인가에 비교하기 위해서는 먼저 undefined 의 값을 검색해야 할 필요가 있습니다.
Still, in order to compare something against the value of undefined it is necessary to retrieve the value of undefined first. 

undefined 변수를 덮어 쓸 가능성에 대해 코드를 보호하기 위해서 사용하는 일반적인 방법은 익명의 랩퍼(anonymous wrapper)를 사용하여 전달하지 않는 인자에 부가적인 매개변수를 추가하는 것입니다.
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, that gets no argument passed to it. 
1.var undefined = 123;
2.(function(something, foo, undefined) {
3.    // undefined in the local scope does
4.    // now again refer to the value
5. 
6.})('Hello World', 42);
같은 목적을 이루기 위한 다른 방법은 wrapper 안에서 선언을 하는 것입니다.
Another way to achieve the same effect would be to use a declaration inside the wrapper. 
1.var undefined = 123;
2.(function(something, foo) {
3.    var undefined;
4.    ...
5. 
6.})('Hello World', 42);
여기에서 유일하게 다른점이라고 한다면 코드가 최소화되어 있고 익명의 랩퍼(anonymous wrapper) 안에 다른 var 구문이 없는 경우 최소 4Byte 이상이 더 사용된다는 것입니다.
The only difference being here, 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

JavaScript 언어의 문맥에서 undefined 는 대부분 전통적인 null 의 의미로 사용되지만 실제 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. 

그것은 (Foo.prototype = null 의 설정으로 프로토타입 체인의 끝임을 선언하는 것과 같이) JavaScript 의 내부에서 사용되기도 하지만 대부분은 undefined 로 대체할 수 있습니다.
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. 



Automatic Semicolon Insertion

JavaScript 는 C언어 스타일의 문법을 따르기는 하지만 소스코드에 반드시 세미콜론(;)을 사용해야하는 것은 아닙니다. 세미콜론을 생략하는 것도 가능합니다.
Although JavaScript has C style syntax, it does not enforce the use of semicolons in the source code, it is possible to omit them. 

그렇다고 해서 JavaScript 가 세미콜론을 사용하지 않는 언어라는 것은 아닙니다. 사실 JavaScript 가 소스코드를 이해하기 위해서는 세미콜론이 필요합니다. 그래서 JavaScript 파서는 세미콜론을 빠뜨려서 발생하는 문법 에러를 만날 경우 세미콜론을 자동으로 삽입합니다.
But JavaScript is not a semicolon-less language, it in fact needs the semicolons in order to understand the source code. Therefore the JavaScript parser automatically inserts them whenever it encounters a parse error due to a missing semicolon. 
1.var foo = function() {
2.} // parse error, semicolon expected
3.test()
파서는 세미콜론을 자동으로 삽입한 후에 구문분석을 다시 시도합니다.
Insertion happens, and the parser tries again. 
1.var foo = function() {
2.}; // no error, parser continues
3.test()
이렇게 세미콜론이 자동으로 삽입되는 것은 코드의 동작이 바뀔수도 있는만큼 언어 설계의 가장 큰 결함중에 하나라고 고려됩니다.
The automatic insertion of semicolon is considered to be one of biggest design flaws in the language, as it can change the behavior of code. 

How it Works

아래 코드에는 세미콜론이 없기 때문에 세미콜론을 어디에 삽입할지의 결정은 파서에게 달려있습니다.
The code below has no semicolons in it, so it is up to the parser to decide where to insert them. 
01.(function(window, undefined) {
02.    function test(options) {
03.        log('testing!')
04. 
05.        (options.list || []).forEach(function(i) {
06. 
07.        })
08. 
09.        options.value.test(
10.            'long string to pass here',
11.            'and another long string to pass'
12.        )
13. 
14.        return
15.        {
16.            foo: function() {}
17.        }
18.    }
19.    window.test = test
20. 
21.})(window)
22. 
23.(function(window) {
24.    window.someLibrary = {}
25. 
26.})(window)
아래는 파서가 추론한 결과입니다.
Below is the result of the parser's "guessing" game. 
01.(function(window, undefined) {
02.    function test(options) {
03. 
04.        // Not inserted, lines got merged
05.        log('testing!')(options.list || []).forEach(function(i) {
06. 
07.        }); // <- inserted
08. 
09.        options.value.test(
10.            'long string to pass here',
11.            'and another long string to pass'
12.        ); // <- inserted
13. 
14.        return; // <- inserted, breaks the return statement
15.        { // treated as a block
16. 
17.            // a label and a single expression statement
18.            foo: function() {}
19.        }; // <- inserted
20.    }
21.    window.test = test; // <- inserted
22. 
23.// The lines got merged again
24.})(window)(function(window) {
25.    window.someLibrary = {}; // <- inserted
26. 
27.})(window); //<- inserted

위에서 파서는 코드의 동작을 과감하게 변경했지만 어떤 경우에는 잘못된 것(의도하지 않은)을 실행하게 됩니다.
The parser drastically changed the behavior of the code above, in certain cases it does the wrong thing. 

Leading Parenthesis

소괄호가 먼저 오는 경우 파서는 세미콜론을 삽입하지 않습니다.
In case of a leading parenthesis, the parser will not insert a semicolon. 
1.log('testing!')
2.(options.list || []).forEach(function(i) {})
이 코드는 한 라인으로 변환이 됩니다.
This code gets transformed into one line. 
1.log('testing!')(options.list || []).forEach(function(i) {})
log 는 함수를 반환하지 않을 가능성이 크기 때문에 위 코드는 undefined is not a function 라는 TypeError 를 발생하게 될 것입니다.
Chances are very high that log does not return a function; therefore, the above will yield a TypeError stating that undefined is not a function. 

In Conclusion

세미콜론을 빠뜨리지 말 것을 강력히 권장하며 또한 해당 문장과 같은 라인에서 중괄호를 사용하고 if / else 구문에서 한 라인이라도 세미콜론을 생략하지 말아야 합니다. 이 두가지 대책은 코드의 일관성을 향상시키는 것뿐만 아니라 코드의 동작이 변경되는 것으로부터 JavaScript 파서를 보호해 줄 것입니다.
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, they will also prevent the JavaScript parser from changing its behavior. 



Other


setTimeout and setInterval

JavaScript 는 비동기적이기 때문에 setTimeout setInterval  함수를 사용하여 함수의 실행을 스케줄링할 수 있습니다.
Since JavaScript is asynchronous, it is possible to schedule the execution of a function by using the setTimeout and setInterval functions. 
1.function foo() {}
2.var id = setTimeout(foo, 1000); // returns a Number > 0
setTimeout 이 호출되면 timeout 의 ID 를 반환하고 약 1000분의 1초 후에 foo 가 실행되도록 설정됩니다. 그리고 나서 foo 는 정확히 한번 실행이 됩니다.
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. 

이것은 코드가 실행이 되는 JavaScript 엔진의 타이머 해상도(resolution)에 의존적입니다. 또한 JavaScript 가 싱글 스레드이기 때문에 실행되는 다른 코드가 그 스레드를 블럭시킬지도 모릅니다. 그것은 setTimeout 호출 시 명시한 만큼 정확히 지연시킬 수 있을지는 확실하지만은 않다는 것입니다. 
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. 

첫번째 매개변수로 전달되는 함수는 전역객체에 의해 호출되게 됩니다. 이것은 호출된 함수 안에서 사용되는 this 가 바로 그 객체(전역객체)를 참조한다는 의미입니다.
The function that was passed as the first parameter will get called by the global object, that means, that this inside the called function refers to that very object. 
01.function Foo() {
02.    this.value = 42;
03.    this.method = function() {
04.        // this refers to the global object
05.        console.log(this.value); // will log undefined
06.    };
07.    setTimeout(this.method, 500);
08.}
09.new Foo();
Stacking Calls with setInterval

setTimeout 은 함수를 딱 한번 실행시키지만 setInterval 은 매번 X 밀리초마다 함수를 실행시키게 됩니다. 하지만 그것을 사용할 때면 낙담을 하게 만듭니다.
While setTimeout only runs the function once, setInterval - as the name suggests - will execute the function every X milliseconds. But its use is discouraged. 

실행중인 코드가 timeout 호출을 블럭시킬 때 setInterval 은 여전히 지정된 함수에 대해 더 많은 호출을 발생시킬 것입니다. 특히 짧은 간격일 경우 이것은 함수호출이 쌓이게 많들 것입니다.
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. 
1.function foo(){
2.    // something that blocks for 1 second
3.}
4.setInterval(foo, 100);
위 코드는 foo 가 한번 실행되면 1초간 블럭이 되게 됩니다.
In the above code foo will get called once and will then block for one second. 

foo 코드를 블럭시키고 있는 동안에도 setInterval 은 여전히 foo 에 대한 호출을 스케줄링할 것입니다. 그리고 드디어 foo 가 종료될 때면 이미 실행하기 위해 대기하고 있는 foo 에 대한 호출이 10개는 더 될 것입니다.
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

가장 쉽고 조절 가능한 해결책은 함수 안에서 setTimeout 을 사용하는 것입니다.
The easiest as well as most controllable solution, is to use setTimeout within the function itself. 
1.function foo(){
2.    // something that blocks for 1 second
3.    setTimeout(foo, 100);
4.}
5.foo();
이렇게 하면 setTimeout 호출을 캡슐화하는 것뿐만 아니라 호출이 쌓이는 것도 방지하고 추가적인 조절도 할 수 있습니다.
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 whether it wants to run again or not. 

Manually Clearing Timeouts

timeout 과 interval 을 삭제하려면 애초에 사용된 set 함수에 해당하는 각각의 ID 를 clearTimeout 또는 clearInterval 에 전달하면 됩니다.
Clearing timeouts and intervals works by passing the respective ID to clearTimeout or clearInterval, depending which set function was used in the first place. 
1.var id = setTimeout(foo, 1000);
2.clearTimeout(id);
Clearing all timeouts

모든 timeout 과 interval 을 삭제하기 위한 내장 메소드는 없기 때문에 이러한 기능을 구현하기 위해서는 강제로 다소 무식한 방법을 사용해야만 합니다.
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. 
1.// clear "all" timeouts
2.for(var i = 1; i < 1000; i++) {
3.    clearTimeout(i);
4.}
이렇게 임의의 숫자를 사용하게 되면 영향을 받지 않는 timeout 이 여전히 남아있을 수 있습니다. 따라서 그 대신에 모든 timeout ID 를 추적할 것을 권장합니다. 그러면 명확하게 모든 timeout 을 삭제할 수 있습니다.
There might still be timeouts that are unaffected by this arbitrary number; therefore, is is instead recommended to keep track of all the timeout IDs, so they can be cleared specifically. 

Hidden use of eval

setTimeout setInterval 은 첫번째 매개변수로 문자열을 받을 수도 있습니다. 이러한 특성은 내부적으로 eval 을 사용하는 것이기 때문에 사용을 하지 말아야 합니다.
setTimeout and setInterval can also take a string as their first parameter. This feature should never be used, since it internally makes use of eval. 
01.function foo() {
02.    // will get called
03.}
04. 
05.function bar() {
06.    function foo() {
07.        // never gets called
08.    }
09.    setTimeout('foo()', 1000);
10.}
11.bar();
이 경우 eval 은 직접(directly) 호출되는 것이 아니기 때문에 setTimeout 에 전달되는 문자열은 전역범위에서 실행이 되게 됩니다. 그래서 bar 의 범위에 있는 지역변수 foo 는 사용되지 않을 것입니다.
Since eval is not getting called directly in this case, the string passed to setTimeout will get executed in the global scope; thus, it will not use the local variable foo from the scope of bar. 

timeout 관련 함수에 의해 호출되는 함수의 첫번째 인자는 문자열을 사용하지 말 것을 더욱더 권장합니다.
It is further recommended to not use a string for passing arguments to the function that will get called by either of the timeout functions. 
01.function foo(a, b, c) {}
02. 
03.// NEVER use this
04.setTimeout('foo(1,2, 3)', 1000)
05. 
06.// Instead use an anonymous function
07.setTimeout(function() {
08.    foo(a, b, c);
09.}, 1000)
In Conclusion

setTimeout 이나 setInterval 의 매개변수로 문자열을 사용하지 말아야 합니다. 그것은 함수 호출 시 인자를 전달해야만 할 때 정말로 좋지 않은 코드임이 분명합니다. 실제로 호출이 될 익명 함수가 전달되어야만 합니다.
Never should a string 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. 

나아가서, setInterval 은 스케줄링이 JavaScript 실행에 의해 블럭되지 않기 때문에 사용을 피해야만 합니다.
Further, the use of setInterval should be avoided since its scheduler is not blocked by executing JavaScript. 

 
저작자 표시 비영리 변경 금지
Posted by JuHoi

댓글을 달아 주세요

  1. 나는 또한 당신이 우리 자녀가 웹 사이트를 확인 좋았는지 탁월한 만남 이해 드리고자합니다. 그녀는 그것이 많은 사람들이 완전하게 문제를 어려운 특정 배울 수 있도록 훌륭한 코칭 자연을 가지고 싶은 것을 포함 조각의 좋은 번호를 찾을 수 왔어요. 당신은 의심할 여지없이 내 욕망을 초과했습니다. Lizeth 수있는 주제에 등, 실질적인 신뢰할 수있는, 교육과 더불어 쉽게 생각을 제작 주셔서 감사합니다.

    2011/08/01 02:26 [ ADDR : EDIT/ DEL : REPLY ]
  2. 헤이, 우리 출판 blogposts 각 반드시 높은 귀하의 웹 사이트에 관해 조사하고 또한 확실히 냉각과 유사한 것으로 보인다 과거에 머무는 그냥 같은, 그럼에도 불구하고 어떤 차이를 한 부분이있을 수도 있습니다. 그들의 결정은 선택을 취소하여 개별 주제 장소를 실현하고는이 뜨거운 볼 수 있습니다. 우리는 어떤 높이 양질의 계획 설계에서 현재의 현대 제가 생각 효과적으로 징조 있도록 속이려 었죠 사이트 및 장소를 발생 했어요. 많은 bottomline에서 별도로이 위대한 사이트를 유지 알아낸 받기 것은 매우 점점 내용 좋아하고 또 다시 빨리 마​​음에 적있다는거다. 감사합니다.

    2011/08/18 02:50 [ ADDR : EDIT/ DEL : REPLY ]
  3. 나는 또한 당신이 우리 자녀가 웹 사이트를 확인 좋았는지 탁월한 만남 이해 드리고자합니다. 그녀는 그것이 많은 사람들이 완전하게 문제를 어려운 특정 배울 수 있도록 훌륭한 코칭 자연을 가지고 싶은 것을 포함 조각의 좋은 번호를 찾을 수 왔어요. 당신은 의심할 여지없이 내 욕망을 초과했습니다. Lizeth 수있는 주제에 등, 실질적인 신뢰할 수있는, 교육과 더불어 쉽게 생각을 제작 주셔서 감사합니다.

    2011/12/01 04:25 [ ADDR : EDIT/ DEL : REPLY ]

진하게 밑줄 기울림 인용문 그림 삽입 링크 걸기 색상 동영상  ? 

«이전  1 ... 2 3 4 5 6 7 8 9 10 ... 50  다음»