Blog

자바스크립트(Javascript) 여행자를 위한 간단한 언어 안내서

April 11, 2014

자바스크립트(Javascript) 여행자를 위한 간단한 언어 안내서

Javascript

자바스크립트를 처음 써 본건 작년 8월인데, 그 이후로 쭉 썼지만 그때 그때 구글링 해 가면서 쓴 것이라 언어 자체에 대한 이해가 부족하다는 생각을 항상 했다. 중간에 책도 좀 보면서, 아 자바스크립트는 이렇구나 하는것도 많이 배웠는데. 기록으로 남기지 않으면 잘 기억이 안나더라. 그리하여 간단하게 나마 정리하게 되었음!(이 글의 주된 레퍼런스는 여기)

Summary

이 포스팅은 다른 언어를 공부하다가 자바스크립트의 오묘한 비교, 타입체킹, NaN 등을 느끼고 오신 분들을 위한 것입니다. 우선 바쁘신 분들을 위한 서머리

– 자바스크립트는 변수와 함수를 따로 관리하지 않습니다. 따라서 이름이 같다면 덮어 쓸 수 있습니다.
– 자바스크립트는 약한 타입 언어(Weakly typed language) 입니다.
– 자바스크립트는 string, number, boolean, null, undefined 5개의 원시 타입을 지원합니다.
– 정의하지 않은 변수는 undefined 값을 가집니다.
false 로 평가되는건 0, '', 등 다양합니다. 그러나 nullundefined 는 아닙니다.
– 그러나 if 문에서 nullundefinedfalse 로 평가됩니다.
isNaN 함수는 믿을만 하지 못합니다. isNan("37")false 를 리턴합니다. 이 함수는 NaN 비교에만 사용하세요.

몇가지 퀴즈들
http://davidshariff.com/js-quiz/
http://perfectionkills.com/javascript-quiz/
http://javascript-puzzlers.herokuapp.com/

읽을 거리
http://www.techumber.com/2013/08/javascript-object-oriented-programming-tutorial.html

1. 자바스크립트도 컴파일 단계가 있다.

자바스크립트도 언어임을 고려하면 당연한건데, 이게 런타임에 타입체킹을 하다보니가 내가 지금 인터프리터를 쓰고 있는건가 하는 생각에 컴파일이 있다는 생각은 하기가 어려웠다. 하지만 아래 코드를 잠깐 보자.

var x = 0; 
function add(a, b) {
    var c = a+b;
    return c;
}

컴파일(파싱) 단계에서는 변수 x 가 메모리에 undefined 로 정의가 된다. 그리고 런타임에 0 이 할당이 된다. 함수 add 의 경우에는 컴파일 단계에서 함수 add 를 가리키는 변수 add 가 정의되고, 함수의 코드블록에 대한 참조가 할당된다. 그리고 실제 런타임에야 함수 코드 블록 내부로 들어가서 ca+b 값이 할당된다.

2. 자바스크립트는 함수와 변수를 따로 관리하지 않는다.

이전 포스트 Lisp1 vs Lisp2 에서 변수와 함수를 같은 심볼 테이블에 관리하는 것과 그렇지 않은 리습 구현체에 대해서 간단히 논했었는데, 자바스크립트는 lisp-1 와 비슷하다. , 다시 말해 심볼테이블이 1개여서 변수와 함수를 같은 공간에 관리한다. 따라서 덮어 쓸 수 있다. 아래 코드를 보고 먼저 출력 값을 예상 해 보자.

1: alert(squre(4));
2: var squre = 0;
3: 
4: function squre (x) {
5:     return x*x;
6: };
7: alert(squre);

정답은, 먼저 16 이 출력되고 두 번째로는 0 이 출력된다. 그 이유는 컴파일 단계에서 먼저 변수 squre 가 정의가 되지만, 뒤에 나온 함수 squre 에 의해서 덮어 씌워진다. 그리하여 런타임에 alert(squre(4)); 가 실행될 때 squre 은 함수다 이후에 alert(squre); 을 실행할때 squre 은 변수다 왜냐하면 런타임에 var squre = 0; 이 실행되어 squre 변수 에 0을 할당하기 때문이다.

3. 자바스크립트의 원시 타입(Primitive Value)은 5 개다.

명망 높은 MDN 에 의하면 자바스크립트는 5개의 원시 타입을 제공한다. 그 이외의 모든 것은 객체다.

– number
– boolean
– string
– null
– undefined

이들 중 number, boolean, string 은 Wrapper 클래스가 있다. 아래 코드를 보자.

typeof true; //"boolean"
typeof Boolean(true); //"boolean"
typeof new Boolean(true); //"object"
typeof (new Boolean(true)).valueOf(); //"boolean"

typeof "abc"; //"string"
typeof String("abc"); //"string"
typeof new String("abc"); //"object"
typeof (new String("abc")).valueOf(); //"string"

typeof 123; //"number"
typeof Number(123); //"number"
typeof new Number(123); //"object"
typeof (new Number(123)).valueOf(); //"number"

4. 정의하지 않은 변수는 undefined 다.


var x; // undefined
typeof x // "undefined"
typeof x === undefined // false
typeof x === "undefined"

4번째 라인은 중요한 부분인데, type 비교 는 스트링으로 출력되므로, 스트링으로 비교를 해야한다.

5. Javascript 에서 False 로 평가되는건 매우 많다.

아래 코드들은 Javascript 에서 false 로 평가되는 식들과 그렇지 않은 것들을 모아놓은 부분이다. 흥미로운 사실은 nullundefinedfalse 가 아니라는 사실이다. 더 자세한 내용은 여기를 참조하자.

false == 0           // true
false == '0'         // true
false == ''          // true
false == []          // true
false == [[]]        // true
false == [0]         // true
false == 000         // true
false == '000'       // true
false == false       // true
false == null        // false
false == undefined   // false

0 == ''    // true
'' == 0    // true
'0' == ''  // false
'' == '0'  // false

그러나 많은 것들이 false 와 동등하다고 평가될지라도, 우리가 if 에 사용할 수 있는건 몇개 없다. 0, '', null, undefined 정도만 기억하자.

if (0)         //false
if ('')        //false
if (000)       //false
if (null)      //false
if (undefined) // false

if ('0')    //true
if ([])     //true
if ([[]])   //true
if ([0])    //true
if ('000')  //true

바로 아래서 다루겠지만, == 는 피연산자의 타입이 서로 다를 경우 타입 변환을 시도한다. 반대로 === 는 타입이 다르면 false 로 평가한다. 따라서 === 를 이용해 false 를 얻고싶다면 false 와 비교하는 방법밖에는 없다.

false === false      //true

false === 0          //false
false === '0'        //false
false === ''         //false
false === []         //false
false === [[]]       //false
false === [0]        //false
false === 000        //false
false === '000'      //false
false === null       //false
false === undefined  //false

6. equality(==) operator 는 타입 변환을 시도한다.

자바스크립트는 흥미롭게도, 비교 연산자를 두 개나 가지고 있다. 하나는 == (equality operator), 다른 하나는 === (identity operator) 다. == 는 비교할 때 좌측과 우측 피연산자가 타입이 다르면, 타입 변환을 시도한 후 비교하고, === 는 타입이 다르면 false 를 리턴한다. 기본적인 아이디어는 아래 코드를 보면 바로 이해할 수 있다.

1 == true     //    true
true == true  //    true
1 === true    //    false
true === true //    true

아래는 스택오버플로우 에서 가져온 몇 가지 흥미로운 샘플들.

'0' == ''           // false
'' == '0'           // false
0 == ''             // true
0 == '0'            // true

false == 'false'    // false
false == '0'        // true

false == undefined  // false
false == null       // false
null == undefined   // true

' \t\r\n ' == 0     // true

"abc" == new String("abc")    // true
"abc" === new String("abc")   // false

7. 알수 없는 그대, NaN

자바스크립트에는 Not a number 란 뜻으로 NaN 이란 친구가 있다. 숫자가 아니란건데, 애석하게도 그 자신은 숫자다.

typeof NaN // "number"

그리고 이 친구는 신기하게도, 자기 자신과 비교할 수 없다.

NaN === NaN // false
NAN !== NaN // true

그래서 자바스크립트에서는 isNaN 이란 함수를 제공하긴 하는데 이것도 문제가 좀 있다. 아래 코드를 보자.

isNaN(NaN);       // true
isNaN(undefined); // true
isNaN({});        // true

isNaN(true);      // false
isNaN(null);      // false
isNaN(37);        // false

// strings
isNaN("37");      // false: "37" is converted to the number 37 which is not NaN
isNaN("37.37");   // false: "37.37" is converted to the number 37.37 which is not NaN
isNaN("");        // false: the empty string is converted to 0 which is not NaN
isNaN(" ");       // false: a string with spaces is converted to 0 which is not NaN

// dates
isNaN(new Date());                // false
isNaN(new Date().toString());     // true

문자열은 숫자로 형변환해서 판단하므로 "37" 은 숫자 37이 아니라 문자열 37임에도 불구하고 false 를 돌려준다. 이게 자바스크립트 표준위원회가 의도한건진 잘 모르겠지만 내가 볼 땐 상당히 혼란스럽다. 그래서 스택오버플로우 에서는 parseFloat() 함수를 사용하길 추천한다.

isNaN(parseFloat("37")); // true

사실 내 생각에 parseFloat() 를 사용하는 것보다는 차라리 isNaN()NaN 비교에만 사용하고 숫자가 아닌지를 판별해 주는 함수를 여기에 포스팅된 것처럼 만들어 사용하는게 훨씬 나은 방법이라고 생각한다.

function isNumber(value) {
    return typeof value === "number" && isFinite(value);
}

References

  1. http://javascriptweblog.wordpress.com/2010/09/27/the-secret-life-of-javascript-primitives/
  2. http://msdn.microsoft.com/en-us/library/7wkd9z69(v=vs.94).aspx
  3. http://stackoverflow.com/questions/359494/does-it-matter-which-equals-operator-vs-i-use-in-javascript-comparisons
  4. http://blog.falafel.com/blogs/basememara/basem-emara/2014/03/14/the-truth-about-false-in-javascript
  5. http://appletree.or.kr/blog/web-development/javascript/javascript%EC%9D%98-%EC%9D%B4%EB%9F%B0-%EC%A0%90%EC%9D%B4-%EB%92%A4%ED%86%B5%EC%88%98%EB%A5%BC-%EB%95%8C%EB%A6%AC%EB%8D%94%EB%9D%BC/
  6. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN