페이지

2012년 1월 7일 토요일

Array.prototype.sort(comparefn)의 comparefn()

Array.prototype.sort()는 array의 요소들을 정렬할 때 사용한다. 정렬 함수는 comparefn()으로 정의할 수 있는데, 이 함수의 리턴값은 다음과 같다.

comparefn(x, y)

x < y : 음수 값
x = y : 0
x > y : 양수 값

따라서 이 조건에 맞춰서 comparefn() 함수를 정의하면 된다.

2012년 1월 5일 목요일

Google JavaScript Style Guide 요약

http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml

자바스크립트 언어 규칙

1. 항상 var 로 선언한다.
2. 상수는 NAMES_LIKE_THIS 처럼 한다.
3. 세미콜론은 항상 사용한다.
4. 중첩된(nested) 함수는 자유롭게 쓴다.
5. block 안에서 함수 선언은 하지 마라. 할거라면 변수를 써라.
6. 예외를 사용하라
7. 커스텀 예외를 사용하라
8. 비표준 보다는 표준을 사용하라
9. primitive type을 랩핑한 객체는 사용하지 마라. type casting은 허용한다.
10. 다단계 prototype 계층 구조는 선호하지 않는다
11. 메소드 정의는 이렇게. Foo.prototype.bar = function() { ... };
12. Closure는 사용해되 조심스럽게.
13. eval()은 deserialization 시에만 사용
14. with() {}는 사용하지 마라.
15. this는 객체의 생성자, 메소드 그리고 closure를 셋업하는 곳에서만 사용하라
16. for-in loop는 객체/맵/해시에 있는 키를 반복할때만 사용하라
17. Array를 맵/해시/Associative array로 사용하지 마라.
18. 멀티 라인 문자열은 \를 사용하지 말고 +를 사용하라
19. Array와 Object를 선언할때는 new Array(), new Object()를 쓰지말고 [] 또는 {}를 써라.
20. 내장 객체의 prototype은 변경하지 마라.
21. IE의 조건문 주석은 사용하지 마라.

자바스크립트 스타일 규칙

1. 네이밍
functionNamesLikeThis, variableNamesLikeThis, ClassNamesLikeThis, EnumNamesLikeThis, methodNamesLikeThis, and SYMBOLIC_CONSTANTS_LIKE_THIS

1.1 속성과 메소드
private 속성, 변수, 메소드는 _로 시작.
protected 속성, 변수, 메소드는  _를 붙이지 않음.

1.2 메소드와 함수의 파라미터
optional arguments는 opt_로 시작.
여러 개의 인자를 받는 함수의 마지막 인자느 var_args로 이름을 붙인다. var_args는 참조하지 않겠지만; arguments array를 사용해라.

1.3 Getter와 Setter
ECMAScript 5에서는 Getter 메소드, Setter 메소드를 속성으로 사용하지 않도록 하지만, 쓴다면 Getter 메소드는 관찰 가능한 상태를 바꾸지 말아야 한다.

1.4 Accessor function
Getter 메소드와 Setter 메소드를 굳이 쓴다면 getFoo(), setFoo()로 이름을 지어야 한다.(boolean getter라면 isFoo()가 좋다.)

2012년 1월 3일 화요일

Function.prototype.apply() 메소드란?

ECMAScript 5.1 Edition의 설명에 따르면 다음과 같다.


15.3.4.3 Function.prototype.apply (thisArg, argArray)

When the apply method is called on an object func with arguments thisArg and argArray, the following steps are taken:
1. If IsCallable(func) is false, then throw a TypeError exception.
2. If argArray is null or undefined, then
    a. Return the result of calling the [[Call]] internal method of func, providing thisArg as the this value and an empty list of arguments.
3. If Type(argArray) is not Object, then throw a TypeError exception.
4. Let len be the result of calling the [[Get]] internal method of argArray with argument "length".
5. Let n be ToUint32(len).
6. Let argList be an empty List.
7. Let index be 0.
8. Repeat while index < n
    a. Let indexName be ToString(index).
    b. Let nextArg be the result of calling the [[Get]] internal method of argArray with indexName as the argument.
    c. Append nextArg as the last element of argList.
    d. Set index to index + 1.
9. Return the result of calling the [[Call]] internal method of func, providing thisArg as the this value and argList as the list of arguments.
The length property of the apply method is 2.

NOTE     The thisArg value is passed without modification as the this value. This is a change from Edition 3, where a undefined or null thisArg is replaced with the global object and ToObject is applied to all other values and that result is passed as the this value.





위 설명을 하나씩 따라가보자

func라는 객체가 있다고 가정하고, IsCallable(func)가 true가 되려면 func 객체가 [[Call]]이라는 내부 메소드를 가지고 있어야 한다. 즉, 함수 콜 표현식으로 호출될 수 있어야 한다는 뜻이다. IsCallable(func)가 false라면 더 이상 단계가 진행되지 않고 TypeError를 발생시킨다.


var TestObj = {
x: 1,
y: 2
};


// TypeError가 발생한다.
TestObj.apply(this, [3, 4]);    


apply()는 thisArg와 argArray 두 개의 인자를 받게 되는데, argArray가 null이거나 undefined이면 this 값과 비어있는 인자 리스트를 제공하는 func 내부 메소드 [[Call]]의 호출 결과를 리턴한다.


function test_func(a, b) {
document.writeln(arguments.length + "<br>");
this.result = a + b;
return this;
}


var TestObj = {
x: 1,
y: 2
};


// arguments.length는 0이다.
var result = test_func.apply(TestObj, null);   
// TestObj를 리턴하였기 때문에 1,2가 출력된다
document.writeln(result.x + ", " + result.y + "<br>");  


argArray의 타입이 Object가 아니면 TypeError가 발생한다.


function test_func(a, b) {
this.result = a + b;
return this;
}


var TestObj = {
x: 1,
y: 2
};


var a = 1;


// TypeError가 발생한다.
var result = test_func.apply(TestObj, a);   



len에는 arrayArray["length"]가 대입된다.
n에는 len을 부호없는 32비트 정수로 변환하여 대입된다.
argList는 비어있는 리스트가 된다.
index에는 0이 대입된다.
index < n 일 동안 다음을 반복한다.
    a. indexName에는 index를 문자열로 변환하여 대입한다.
    b. nextArg에는 argArray[indexName]을 대입한다.
    c. argList의 마지막 요소로 nextArg를 추가한다.
    d. index에 1을 더하여 index에 대입한다.
인자 리스트인 argListthis 값인 thisArg를 제공하는 func의 내부 메소드 [[Call]]을 호출한 결과를 리턴한다.



function test_func(a, b) {
this.result = a + b;
return this;
}


var TestObj = {
x: 1,
y: 2
};
var tmp_array = [2, 3];
test_func.apply(TestObj, tmp_array);
document.writeln(TestObj.result);  // 5


TestObj에는 원래 없었던 result 속성이 추가되었다.


정리하면,

func.apply(thisArg, argArray)에서 argArray는 func()의 인자로 사용되고, 그 결과는 thisArg에 추가된다.