레이블이 JavaScript인 게시물을 표시합니다. 모든 게시물 표시
레이블이 JavaScript인 게시물을 표시합니다. 모든 게시물 표시

2015년 4월 2일 목요일

[JavaScript] 자바스크립트 this 키워드의 모든것

this 키워드를 이해하기 위해서는 Execution Context를 이해해야하니, 혹시 Execution Context를 모른다면 이 글(클릭하기)을 읽어 봐 주길 바란다.

자바스크립트에서는 매번 함수의 호출마다 새로운 Execution Context가 생성된다. 이 Execution Context는 Lexical Environment, Variable Environment, 그리고 ThisBinding에 대한 정보를 가지고 있는데, 바로 this 키워드가 이 이 thisbinding이라고 할 수 있겠다. this값은 해당 함수가 현재 어느 Execution Context에서 구동하고 있는지를 알려준다.

Context는 함수 호출에 의해 새로이 생성되며, thisBinding 값은 함수 호출시점에 정해지게 된다. 정확히 말하자면 ECMAScript 내부에서 Function call 발생할 때, 함수의 Arguments List와 thisArg라 불리는 두 객체를 전달하게 되는데, ECMAScript® Language Specification 10.4.3에 따르면 여기서 아래의 과정을 거친후 thisBinding의 값이 결정 된다.
  1. 만약 함수가 strict mode에서 정의된 함수인지를 확인한 후, thisBinding 값은 전달된 thisArg값이 된다.
  2. (strict mode에서 정의된 함수가 아니고) thisArg 값이 null 이나 undefined라면면,  thisBinding 값은 global object가 된다.
  3. 전달된 Type(thisArg) 연산으로 얻어진 thisArg 값의 Typeobject(객체)가 아니라면, thisBinding 값은 toObject(thisArg) 오퍼레이션을 통해 객체화된 객체가 된다.
    • Type() 함수는 ECMA스크립트 내부 함수로, 주어진 변수의 Type을 연산합니다.
    • toObjecT() 함수는 주어진 변수를 Boolean, Number, String, Object 형으로 변환 합니다
  4. 위 모든 과정에서 thisBinding 값이 정해지지 않았다면, 전달된 thisArgthisBinding이 된다.

참고로 funciton.prototype.call, function.prototype.apply 와 같은 this 값을 수정 가능케 하는 기능들은 모두 thisArg 값을 사용자가 전달할 수 있게 함으로써 가능한 기능들이다.

그렇다면, 일반적으로는 이 thisArg 값이 어떻게 결정 되는 것 일까? 이는 함수 호출(Function Call) 과정을 설명한 ECMAScript® Language Specification 11.2.3 에 잘 정의 되어 있다 - 6번과 7번에 주목하자.

*우선 이전에 몇가지 알아야 될것들이 있다

  • 함수가 저장된 주소인 reference 값은 base value, referenced name, strict reference flag, 이 3가지 요소로 이루어져 있다
    • referenced namestring 값으로 저장된 function identifier이다
    • strict reference flagboolean 값으로, strict mode 에서 실행되는 코드인지를 표시한다
    • base valuereference가 속한 context object를 가리킨다

thisArg값은 함수 호출(Function Call)의 6번째 과정에서에서 결정되며, 함수 호출의 전체 과정은 아래와 같다.

  1. 함수 객체의 이름(MemberExpression)을 해석해서 함수가 저장된 레퍼런스 값인 ref를 얻는다.
  2. GetValue(ref) 오퍼레이션을 이용, 함수 func을 불러온다.
  3. 주어진 arguments 들로 argList를 생성한다.
  4. Type(func) 오퍼레이션을 이용, 함수 func의 타입을 확인한후, 객체타입이 아니라면 TypeError Exception 을 발생시킨다.
  5. IsCallable(func) 오퍼레이션을이용, 함수 func의 호출이 가능한지를 확인한 후, 불가능하다면 TypeError Exception을 발생시킨다.
  6. Type(ref)를 이용, ref의 타입을 확인한 후, reference 타입이라면
    1. IsPropertyReference(ref) 오퍼레이션을 이용, ref가 object 또는 primitive wrapper object(String, Boolean, Number 등의 객체)에 속한 property 라면 thisArg값은 getBase(ref) 오퍼레이션에서 얻어진 해당 객체 인스턴스가 된다.
    2. 그 이외의 경우에는 ref가 속한 Environment Record(Variable Environment Object)라면 getBase(ref)에서 얻어진 값의 ImplicitThisValue()가 바로 thisArg가 된다.
  7. 만약 Type(ref)를 이용해 확인한 ref의 타입이 reference 가 아니라면, thisArg값은 undefined가 된다.
  8. Call 오퍼레이션을 이용, thisArg 값과 argList를 전달해 함수를 호출한 후 그 결과값을 리턴한다.

결국 각각의 경우에 따라 thisBinding의 값이 달라지니 좀 헷깔린다. 그래서 자주 보게되는 상황들을 Case By Case 로 설명을 해보려 한다.

* 참고로 this 키워드는 객체이기 대문에 '.'(Dot Notation) 또는 '[', ']'(Bracket Notation) 를 이용해서도 this 객체의 변수나 함수를 호출 할 수 있다.
* 위 과정을 읽었으면 알겠지만 strict 모드에서는 함수 호출시 thisArg값은 non-strict mode 일때와는 다르다.


1. Declaration environment record에 존재하는 함수 호출(Function Call)


  • 위의 6-2번 과정이다. ImplicitThisValue() 는 모든 declaration에 대해 undefined를 리턴한다
  • 이 때문에 this 키워드는 strict mode에서는 undefined 값을, non-strict mode에서는 global object(window object)값을 참조하게 된다.


function invokeFunction() {
    console.log("invokeFunction");
    console.log(this);//Window
    demo1();
    function demo1() {
 console.log("demo1");
 console.log(this);//Window

 var demo2 = function() {
     console.log("demo2");
     console.log(this);//Window

     var demo3 = function() {
  console.log("demo3");
  console.log(this);//Window
     };
     demo3();
 };
 demo2();
    }
}
console.log(this);//Window
invokeFunction();


2. new 키워드를 이용해 객체(object)로 인스턴스화 될 때, this 값은 언제나 인스턴스화된 객체를 참조한다.

  • 위 과정의 6-1번에 속하는 경우이다. 호출된 함수가 객체의 property인 경우이다


function thisObject(name, property) {
    this.name = name;
    this.property = property

    this.thisValue = this;

    this.f = function() {
 console.log("this in function f \n" + this); //object
    }
}

var demo = new thisObject("testObject", 0);
console.log("demo.thisvalue is " + demo.thisValue); //object demo


3. 객체의 메소드로써 호출될 때, this 값은 언제나 인스턴스화된 객체를 참조한다.


  • 메소드란 객체의 프로퍼티(property)로 존재하는 함수를 한다.
  • 이 경우 또한 위 과정의 6-1번의 경우가 되겠다.


var a = {
    test : function() {
 return this;
    }
};

a.test();// object 'a'

var b = {};
b.test = a.test;

b.test()// object 'b'


4. function.prototype.call 또는 function.prototype.apply 메소드를 이용해 호출될 때


  • thisArg의 값은 사용자에 의해 주어진다.


function test() {
    return this;
}
test();// windows

var a = {};
test.apply(a);// object 'a'

test.call(a);// object 'a'

2015년 3월 10일 화요일

[JavaScript] 자바스크립트 Array(배열)

자바스크립트는 여러가지 built-in Object를 내장하고 있는데, 그중 Array(배열) 개체은 사실상 가장 기초적이며 가장 다양하게 쓰이는 개체일 것 이다.
같은 타입(Type)의 자료를 저장해야하는 타 프로그래밍 언어와는 달리, 자바스크립트(ECMAScript)는 배열에 다른 자료형들을 저장하는게 가능하다. 즉, Array(배열) 1개에, boolean 값, string 값, number 값, 등을 모두 저장할 수 있다는 말이다. Array 자료형은 총 4294967295개의 데이터를 저장할 수 있다. 만약 이 이상을 저장하려 한다면 에러가 발생하게 될 것이다.

Array(배열)은 2가지 방식으로 선언될 수 있다.

// Array Constructor 를 이용하는 방법

var arrayConstructorDemo1 = new Array(); // empty Array를 생성
var arrayConstructorDemo2 = new Array(3); // 3의 크기를 가진 Array를 생성
var arrayConstructorDemo3 = new Array("test", true, 33); // 원하는 데이터로 생성

// Array Literal Notation을 사용하는 방법
var arrayLiteralDemo1 = []; // empty Array를 생성한다.
var arrayLiteralDemo2 = [ "test", true, 33 ];
// "test", true, 33 3개의 데이터를 가진
// 어레이를 생성 ArrayConstructorDemo3와 같은 결과

// 아래의 Array Literal Notation 사용은 작동하나, 브라우져 환경에 따라 에러를 생성할 수 있으니, 사용을 자제하도록하자.

var arrayLiteralDemo3 = [ 1, 2, 3, ]; 
// 1,2,3값을 가진 크기 3 또는 4(네번째는 undefined 값)의 배열을 생성한다.

var arrayLiteralDemo4 = [ , , , ]; 
// 3개 또는 4개의 undefined 값을 가진 array를 생성한다

Array(배열)의 선언 후에 내부 값에 접근(읽기/쓰기)하기 위해서는 [,] 사각괄호안에 접근하고 싶은 값의 index를 넣으면 된다.
참고로 배열의 index는 언제나 0 부터 시작하며, 배열의 크기는 length프로퍼티에 접근하여 알 수 있다.


var arrayConstructorDemo = new Array("test", true, 33);

console.log(arrayConstructorDemo[0]); //"test"
console.log(arrayConstructorDemo[1]); //true
console.log(arrayConstructorDemo[2]); //33

//같은 방식으로 값을 변경할 수 있다.

arrayConstructorDemo[0] = "complete";
arrayConstructorDemo[1] = 13;
arrayConstructorDemo[2] = false;

console.log(arrayConstructorDemo[0]); // complete
console.log(arrayConstructorDemo[1]); // 13
console.log(arrayConstructorDemo[2]); // false

console.log(arrayConstructorDemo.length);// 배열의 크기 확인

//배열의 new index에 새로운 값을 삽입한다.
arrayConstructorDemo[4] = "new Index"; // index 4에 새로운 값을 삽입한다
console.log(arrayConstructorDemo[4]); // new Index
console.log(arrayConstructorDemo.length);// 5

//배열의 크기를 2로 줄여보자.
arrayConstructorDemo.length = 2;
console.log(arrayConstructorDemo[4]); // undefined
console.log(arrayConstructorDemo[2]); // undefined

//다시 배열의 크기를 5로 늘릴경우
arrayConstructorDemo.length = 5;
console.log(arrayConstructorDemo[4]); // undefined
console.log(arrayConstructorDemo[3]); // undefined
console.log(arrayConstructorDemo[2]); // undefined

Array의 크기는 매우 동적이며, 만약 위의 코드처럼, 사이즈 3의 배열에 존재하지 않는 인덱스인 4에 새로운 값을 삽입하려 한다면, 자바스크립트 엔진은 자동으로 배열의 크기를 새로운 index에 알맞게 증가 시키고, 값을 삽입하게 된다.

length 프로퍼티는 read-only가 아니기 때문에, array의 크기를 조절하는데도 사용이 가능하다.
배열의 크기를 줄일 경우에는, 줄어든 배열에 포함되지 않는 index 값에 접근하게되면 언제나 undefined 값을 반환하게 된다.

배열의 크기를 늘리게 될 경우에도 마찬가지로 배열에 새로들어오게된 index들은 undefined 값을 가지게 된다.

Array.isArray() 메소드


Array.isArray() 메소드는 괄호안에 주어진 변수가 Array 개체인지를 확인하는 메소드 이다. 이 메소드는 ECMAScript 5에서부터 적용되기 시작했다. 이 메소드가 적용된 가장 큰 이유는 instanceof 연산자가 가지는 한계 때문이였는데, 1개의 global context를 전제하는 instanceof 연산자는 대부분 multi-frame DOM 환경에서 제대로 작동하지 않는다는 한계를 가지고 있었다. 이 때문에 총 2개의 global context를 가지는 경우에는, instanceof 연산자로 다른 global context의 Array 개채를 계산하게 되면, false 값을 얻게 된다. 이 한계를 넘기 위해 나온게 바로 Array.isArray 메소드 이다.

아래와 같이 사용할 수 있다.


if (Array.isArray(arrayConstructorDemo)) {
    console.log("This is Array");
}

Stack & Queue


자바스크립트 Array(배열)은 StackQueue 설정을 제공한다. 즉, 기본적으로 제공되는 메소드들로 배열을 Stack 또는 Queue로 사용하는게 가능하다. Stack 과 Queue는 LIFO, FIFO로 표현되는 자료 구조로, 그 컨셉을 자세히 알고 싶으면 앞의 링크를 클릭 해보도록 하자.

Stack

push 메소드를 이용해서 새로운 데이터를 삽입해 array 의 크기값을 반환하고, pop 메소드를 이용해서 가장 최근에 삽입된 데이터를 빼내온다.


var arrayStackDemo = new Array();

var size = arrayStackDemo.push("Demo1", "Demo2");

console.log(size);// 2

size = arrayStackDemo.push("Demo3");

console.log(size);// 3

var topStack = arrayStackDemo.pop();

console.log(topStack); // Demo3

console.log(arrayStackDemo.length); // 2


Queue

Stack과 같이 push 메소드를 이용해 배열의 끝에 새 데이터를 삽입한다.
원래 Queue의 값을 얻어오는 메소드도 이름이 "pop"이나 이미 Stack을 구현하는데 사용되버렸기 때문에 "shift"메소드를 이용해 배열에 값을 삽입힌다.
또한, "unshift" 메소드를 이용해 배열의 처음에 새 데이터를 삽입할 수도 있다


var arrayQueueDemo = new Array("Demo0");

var size = arrayQueueDemo.push("Demo1", "Demo2");

console.log(size);// 3

size = arrayQueueDemo.push("Demo3");

console.log(size);// 4

var firstQueue = arrayQueueDemo.shift();

console.log(firstQueue); // Demo0

console.log(arrayQueueDemo.length); // 3

size = arrayQueueDemo.unshift("newValue");

console.log(size);// 4

firstQueue = arrayQueueDemo.shift();

console.log(firstQueue); // newValue

Sort & Reverse


자바스크립트의 Array 개체는 기본적으로 배열을 재정렬할 수 있는 메소드들을 제공한다.

Reverse

Reverse 메소드는 이름에서도 알 수 있듯이, 배열을 뒤짚는 메소드 이다.


var a = [ 0, 1, 2, 3, 4, 5 ];
a.reverse();

console.log(a);// [ 5, 4, 3, 2, 1, 0 ]

Sort

Sort 메소드는 Array를 정렬한다. 하지만 기본적으로 Sort 메소드는 배열의 개체들이 String 타입이라 전제하에 정렬하기 때문에, 수의 경우에도 마찬가지로 문자열처럼 [1, 12, 13, 2] 정렬된다.


var a = [ 0, 1, 12, 13, 2 ];
a.sort();

console.log(a);// [ 0, 1, 12, 13, 2 ]

이를 해결하기 위해서 sort메소드의 파라미터로 비교함수를 넣어 줄 수 있다.
사용법은 아래와 같다.


function comparator(a, b) {
    if (a > b) {
 return 1;
    } else
 (a < b)
    {
 return -1;
    }
    return 0;
}

var a = [ 0, 1, 12, 13, 2, 13 ];
a.sort(comparator);

console.log(a);// [ 0, 1, 12, 13, 13, 2 ]

Concat


각기 다른 여러개의 Array를 합쳐 새로운 Array 개체를 생성한다


var a = [ "a", "b", "c" ];
var b = [ "d", "e", "f" ];

var c = a.concat(b, "g", [ "e", "f", "g" ])

console.log(a);// [ 'a', 'b', 'c' ]
console.log(b);// [ 'd', 'e', 'f' ]
console.log(c);// [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'e', 'f', 'g' ]

Splice


Array 개체에서 주어진 index의 데이터들을 가져와 새로운 Array를 생성한다. 새로운 Array를 생성하며 추가적으로 원래 Array에 새로운에에 데이터를 삽입할 수도 있다. 즉 원래 Array에서는 데이터를 삭제하며, 새로운 삭제된 데이터들로 새로운 Array를 생성한다.


array.splice(start, deletecount, items)

start에 삭제할 범위의 첫번째 index
deletecount에는 첫번째 index인 start를 포함해 삭제할 엘리맨트의 갯수
items에는 삭제후 삭제된 index에 삽입할 데이터 어레이, 또는 데이터.

var a = [ "a", "b", "c" ];
var b = [ "d", "e", "f" ];

var c = a.splice(0, 2);
b.splice(0, 2)

console.log(a);// [ 'c' ]
console.log(b);// [ 'f' ]
console.log(c);// [ 'a', 'b' ]

c.splice(0, 0, "new VAL");

console.log(c);// [ 'new VAL', 'a', 'b' ]

indexOf & lastIndexOf


indexOf와 lastIndexOf 메소드는 둘다 array에서 주어진 데이터를 검색 후, 그 데이터가 저장된 위치, 즉 index를 리턴한다. 아무것도 찾을 수 없을시에는 -1값을 리턴한다.

*indexOf는 배열의 처음(0)부터 검색하지만, lastIndexOf는 배열의 끝(length-1)부터 검색하게 된다.


var a = [ "a", "b", "c", "a" ];

console.log(a.indexOf("a"));// 0
console.log(a.lastIndexOf("a"));// 3
console.log(a.indexOf("t"));// -1

반복문(Iterative Method)


자바스크립의 Array는 기본적으로 5가지 함수 반복문을 제공한다.

  • foreach()
    • Array의 모든 엘리멘트를 파라미터로 주어진 함수에 따라 계산한다. 하지만 어떠한 값도 반환하지 않는다
  • every()
    • Array의 모든 엘리멘트를 파라미터로 주어진 함수에 따라 계산한다. 만약 모든 계산에서 true 값이 나왔다면 true 값을 리턴한다
  • some()
    • Array의 모든 엘리멘트를 파라미터로 주어진 함수에 따라 계산한다. 그 중 1개의  계산에서 true 값이 나왔다면 true 값을 리턴한다
  • filter()
    • Array의 모든 엘리멘트를 파라미터로 주어진 함수에 따라 계산한다. 계산에서 true 값을 리턴하는 엘리멘트의 배열을 리턴한다
  • map()
    • Array의 모든 엘리멘트를 파라미터로 주어진 함수에 따라 계산한다. 각각 계산의 결과값으로 만들어진 배열을 리턴한다

파라미터로 주어지는 함수의 시그니쳐는 언제나


function name(item(데이터값), index(인덱스), array(배열))

이며 사용법은 아래와 같다.


function func(item, index, array) {
    if (item % 2 == 0) {
 return true;
    }
    return false;
}

var a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
console.log(a);// [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]

var b = a.every(func);
console.log(b);// false

var c = a.filter(func);
console.log(c); // [ 2, 4, 6, 8, 10 ]

var d = a.some(func);
console.log(d);// true

var e = a.map(func);
console.log(e);// [ false, true, false, true, false, true, false, true, false, true ]

var f = a.forEach(func);
console.log(f);// undefined
//아무것도 반환하지 않기 때문에 f의 값은 undefined 이다.


Reduce & ReduceRight


Reduce 메소드란 ECMAScript 5에서 새로 추가된 기능으로 배열의 모든 데이터에 대해 파라미터로 주어진 함수를 반복해, 최종값을 얻어내는 메소드 이다.
Reduce 메소드는 Array의 처음부터 함수를 시작하며, ReduceRight 메소드는 Array의 끝부터 메소드를 시작한다.
Reduce 와 ReduceRight 메소드 둘 다 파라미터로 받는 함수는 다음과 같은 Function Signature를 가진다.


function func(prev, cur, index, array)
//prev 는 바로 전 반복문까지의 최종 값이며, cur 은 현재 반복문의 순서에 있는 배열내의 데이터값이다.
//index 는 현재 데이터값의 배열 인덱스를 의미하며, array는 현재 배열 개체를 의미한다.

사용법은 아래와 같다.


function func(prev, cur, index, array) {
    if (cur % 2 == 0) {
 return prev - cur;
    }
    return prev + cur;
}

var a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
console.log(a.reduce(func));// -5
// 위 reduce메소드의 계산과정은 아래와 같다.
// 1 - 2 - 1 + 3 + 2 - 4 - 2 + 5 + 3 - 6 - 3 + 7 + 4 - 8 - 4 + 9 + 5 - 10

console.log(a.reduceRight(func));// 15
// 위 reduceRight메소드의 계산과정은 아래와 같다.
// 10 + 9 + 19 - 8 + 11 + 7 + 18 - 6 + 12 + 5 + 17 - 4 + 13 + 3 + 16 - 2 + 14 + 1

2015년 3월 8일 일요일

[JavaScript] 실행 영역(Execution Context)과 스코프(Scope)

자바스크립트는 타 프로그래밍 언어에 비해 조금더 융통성있는 특별한 실행 영역(Execution Context)과 스코프(Scope)를 가지고 있다. 이로 인해 함수(Function)은 다양한 영역(Context)에서 호출될 수 있고, 그러한 스코프(Scope) 생성하고 유지할 수 있다. 이러한 컨셉은 "Closure"와 같은 특별한 디자인 패턴(Design Pattern)을 자바스크립트에서 구현 가능할 수 있게 만들었다

Execution Context(실행 영역)


흔히들 Context 라 부르기도 하는 Execution Context(실행 영역)는 스크립트가 실행되면서 생성(Global Context)되거나 Function Call에 의해 생성(Active Context) 되게 된다. 각각의 활동 컨텍스트(Active Context)들은 Function Call에 의해 생성되며 생성된 순서대로 Stack 메모리에 된삽입되게 되고, Stack의 FILO 원리대로 현재 실행중인 Context는 Stack의 최상위에 위치하게 된다. 각각의 Context는 언제나 1개의 변수 환경(Variable Environment), 1개의 Lexical Environment, 그리고 1개의 ThisBinding 속성, 총 3개의 부분으로 구성되 있다. 그리고 3 속성 모두 Object 형식으로 저장된다(자바스크립트의 Object 자료형으로 저장되는게 아니다. 그러니 사용자가 Access 할 방법은 전혀 없다).

Lexical Environment Object

한글로 번역(의역)하자면 "구성 환경 객체"이라고 할 수 있겠다. 해당 Context에서 서언된 변수/함수들의 Reference 값을 저장하는 객체이다.(내부 구성은 Variable Environment Object 에 저장된다). Identifiers(변수/함수이름)을 Reference(메모리 참조값)으로 변환할 때 사용된다. Execution Context의 생성 초기시점에는 아래에서 설명할 Variable Environment Object와 정확히 같은 값을 가지나, Context 내부에서 Scope Augmentation이 실행될 시, Variable Environment Object와는 달리 새로운 Identifier 와 그의 Reference 값이 추가된다.

Variable Environment Object

한글로 번역(의역)하자면 "변수 환경 객체"이라고 할 수 있다. 사실 변수 환경 또한 Lexical Environment(구성 환경)에 포함되는 개념이나, 위에서 설명한 Lexical Environment Object가 생성 후에 내부 값이 변할 수 있는 것과 달리
Variable Environment Object는 내부에서 선언된
  • 변수(Variables)
  • 함수 선언(Function Declarations)
  • 함수 매게 변수(Formal Parameters)
들을 저장하기 때문에 Hoisting등 this 키워드를 이용한 Expression에 의해 새로운 변수/함수가 등장하더라도 절대로 값이 변하지 않는다.

ThisBinding Object

ThisBinding 객체는 해당 Execution Context의 this 키워드의 반환 값을 저장한다.
Execution Context에서 사용자가 유일하게 접근(Access)가능한 부분이다. 참고로 this 키워드는 현재 Context가 참조하고 있는 객체를 가리키며 이 값은 어떻게 함수가 호출되었냐에 따라 갈린다

당연하겠지만, Execution Context 내부의 모든 코드가 실행이 완료된 후에는, Execution Context는 Stack에서 삭제되며, 그와 관련된 Lexical Environment Object, Variable Environment Object, ThisBinding Object 모든 구성 환경 값들 또한 삭제된다.

Global Context는 최상위이자 가장 밖의 Execution Context로 function 외부에서 선언된 모든 함수들과 변수들이 이에 포함된다.

웹 브라우져 환경에서 Global Context의 Variable Environment Object는 Window Object이며체, Global Context에서 선언된 함수들과 변수들은 모두 Window Object에 저장된다.이 Execution Context 내부의 모든 코드가 실행이 되고 난 후에는, Window Object에서 삭제되고, 그 안에 저장된 함수들과 변수들 또한 파괴된다.
Window Object 위의 Global Context는 웹페이지가 종료 되고 난 후에야 파괴된다.

Execution Context의 Variable Environment Object는 아래와 같은 형식으로 저장된다.


var a = "글로벌";
var b = 33;

function demo(x) {
  var c = "함수 컨텍스트";
};

demo(20);


위와 같은 자바스크립트 코드는 아래와 같은 Variable Object(변수 객체)를 가지게 된다.


// Variable object of the global context
변수객체(Global Context, 글로벌 컨텍스트) = {
//(웹브라우져 환경에서는 Global Context의 변수 객체가 Window Object이다)
  a: "글로벌",
  b: 33,
  demo: -> demo 함수가 저장된 메모리 주소
};
  
// Variable object of the "test" function context
VO(demo Function Context, 함수 내부의 컨텍스트) = {
  x: 20,
  c: "함수 컨텍스트"
};


Variable Scope(변수 스코프)


흔히들 스코프라 부르는게 바로 Variable Scope이다. Variable Scope는 변수에 접근이 가능한 유효 범위를 뜻한다. 즉 Variable(변수), Function(함수), 그리고 formal parameter(매게 변수)의 접근성과 생존 기간를 말하는 개념이다. Scope 은 Execution Context와 Execution Context의 Lexical Environment 개념과 긴밀한 관계에 있기 때문에, 위의 Execution Context를 잘 이해했다면 Scope도 쉽게 이해할 수 있다.

Scope은 크게 Global Scope 과 Local Scope, 두가지 종류로 나뉘는데, 이 중 Global Scope은 스크립트 실행시 생성되는 Execution Context의 Scope이고, local scope은 function 호출시 생성되는 Execution Context의 scope이다. 참고로 Scope은 if, for 문 같은 블럭에서는 생성되지 않고 오직 function 단위로만 생성된다. 하지만 with 문, 또는 try-catch 문으로 scope을 변경 할 수 있다.


function calculation() {
    var numToAdd = 3;
    var numToSubtract = 1;

    add();
    subtract();

    function add() {
 number = number + numToAdd;
    }

    function subtract() {
 number = number - numToSubtract;
    }
}

var number = 0;

calculation();

console.log(number); // 2
console.log(numToAdd); // 에러
console.log(numToSubtract); // 에러


위의 예제를 보자. 위 코드에서 함수 calculation()은 총 2개의 Variable Environment Object에 접근이 가능하다. 바로 본인의 context 와 연관된 variable environment object와, 본인의 상위 context인 global context의 variable environment object. 그리고 calculation() 함수 내부에서 선언된 함수들인 add 와 subtract는 각각 3개의 Variable Environment Object에 접근이 가능하다. 본인의 것, 그리고 2개의 상위 context의 것들.

이러한 이유로, number 라는 변수, numToAdd, numToSubtract라는 변수는 calculation 함수 내부뿐만이 아니라, add와 subtract함수에서도 접근이 가능해진다. 하지만 calculation 함수의 실행이 끝난 후, 즉 함수에서 벗어난 이후에는 함수의 context의 variable environment object에 접근이 불가능하다. 이러한 이유로 우리는 calculation 함수의 실행이 끝난후에 numToAdd 와 numToSubtract 함수에 접근할 수가 없게 된다.

반대로 함수의 실행이 끝나기 전이나 가장 최근 호출된 함수가 계속 사용될 경우, 즉 함수가 자신의 상위 Execution Context를 참조하고 있는 동안에는 Execution Context는 절대로 파기되지 않는다. 바로 이 점을 이용해 자바스크립트에서 Closure라는 기법을 사용할 수 있게 된다.

이게 바로 Variable Scope, 변수 유효 범위이다.

2015년 3월 3일 화요일

[JavaScript] 자바스크립트의 객체와 원시자료형, 그리고 함수의 매개변수(Function Argument)

자바스크립트(ECMAScript)의 변수는 타 프로그래밍 언어에 비해 매우 자유로운 선언과 사용이 가능하다. C#이 .Net Framework 3.5에서야 구현한 Var 키워들 자바스크립트(ECMAScript)는 태생부터 가지고 있었고, 이로 인해 var 키워드 하나로 각기 다른 타입의 데이터들을 쉽고 간단하게 다룰 수 있게 만들었다.
변수에 대해 잠시 다뤄보자. 우리가 선언하는 변수(Variable)들은 선언과 초기화시 특정 메모리(RAM) 영역을 가리키게 된다. 말인즉,


var a = 1;
var b = "TEST";


위와 같이 변수 a 와 b 를 선언할 때, 메모리 영역에서는 ECMAScript 코어 엔진이 사용되지 않는 영역에 1과 "TEST"라는 값을 저장하게 되고, a 와 b 같은 변수 이름은 그져 그 메모리 영역을 가리키는데 사용될 뿐인 것이다. 이 때문에 변수의 값과 또는 타입은 스크립트가 실행되는 와중에도 언제든 변경이 가능하게 되는것이다.

여기서 문제는, RAM 메모리가 무한하지 않다는 것인데, 그렇기 때문에 메모리가 할당되기만 하고 할당된 메모리를 다시 풀어주지 않는다면 스크립트가 실행되고 새로운 변수가 선언될 때마다 메모리가 서서히 차버리고 결국에는 "Out of Memory"가 생기고 실행중인 프로그램이 크래쉬 되버릴게 분명하다. 여기서 바로 Scope(변수 영역)의 개념이 등장하게 된다. 변수 영역(Scope)이란 변수가 사용되는 영역을 가리킨다, 즉 이러한 영역의 스크립트 실행이 모두 끝나게 되면, 당연하게도 그 변수는 더 이상 사용되지 않게되니, 할당된 메모리를 풀 수 있게 된다.

다시 자바스크립트로 돌아가자. 자바스크립트(ECMAScript)의 Data Type은 크게 2가지 종류로 나뉜다, Primitive Data Type(원시 자료형)과 Composite/Reference Data Type(객체). Primitive Data Type 에는 String(문자열), Number(숫자), Undefined, Null, Boolean, 이렇게 총 5개의 자료형이 존재한느데 이 자료형들의 공통점은 모두 다 변수 선언(Declaration), 초기화(Initialization), 어싸인(Assign)시 값이 저장된 메모리 영역에 직접적으로 접근한다는건데, 즉 변수에 새 값이 어싸인 될 시에 변수에 할당된 메모리 블럭에 저장된 값을 바로 변경한다는 뜻이다, 이 때문에 이런 Primitive Data Type 들은 Access By Value의 속성을 가지게 된다. 아래 코드를 보자


var a = 33;
var b = a;
b = 44;

console.log(a); // 33
console.log(b); // 44


위의 코드에서는 총 3개의 변수가 선언됬다. a, b, 그리고 c. 자바스크립트에서의 메모리 할당은 변수 초기화(Initialization)시 일어나게 된다. 즉 = 이라는 키워드가 변수에 처음 사용될 때만 메모리가 할당된다는 말이다. 우선 a 라는 변수에 33이라는 숫자를 저장했다. 이는 a 라는 변수에 할당된 메모리에 바로 저장되게 된다.

그렇다면 b 라는 변수는 어떨까, "var b = a" 구문은
b라는 변수가 a 라는 변수를 저장하게 된다고 말하고 있다. 하지만 실제로 변수 b는 자신에게 할당된 메모리 블럭에 변수 a(또는 변수 a가 저장된 메모리 블럭 주소)를 저장하는것이 아닌 변수 a의 메모리 블럭에 저장된 값을 저장한다. 즉 변수 a 에게 할당된 메모리 블럭을 복사해서 자신의 메모리 블럭에 덮어 씌운다는 말이다.

이때문에 b = 44 라는 구문을 이용해서 b에 새로운 값을 어싸인 해주거나, a 의 값을 변경하더라도 다른 변수의 값은 변하지 않게 된다. 즉 변수 a 와 변수 b를 저장하는데 2개의 메모리 블럭이 할당 된것이다.

하지만 Composite/Reference Data Type, 주로 객체라 불리는 이 자료형은 어떻게 될까?

Primitive Data Type 과 Composite/Reference Data Type의 가장 큰 차이는 바로 Primitive Data Type 이 변수의 값을 저장할 때, Composite/Reference Data Type은 변수의 값이 저장된 힙(Heap) 메모리의 주소값을 저장한다는 것이다. 즉 Primitive Data Type이 변수에 할당된 메모리 블럭과 바로 연결되있다면, Composite/Reference Data Type은 변수의 값이 저장된 메모리 블럭의 주소를 가지고 있고, 자바스크립트 엔진이 변수가 가지고 있는 메모리 주소를 이용해서 변수의 값에 접근한다는 뜻이다. 이렇한 이유로, Composite/Reference Data Type은 Access By Reference 의 속성을 가지고 있다.


var a = {
 name : "Object a",
 message : "This is Object a"
};
var b = a;
b.name = "Object a changed to Obejct b";

console.log(a);
// { name: 'Object a changed to Object b',
//  message: 'This Object is changed to b' }
console.log(b);
// { name: 'Object a changed to Object b',
//  message: 'This Object is changed to b' }


변수 a 는 초기화(Initialization)시 Heap 메모리에 생성된 객체의 메모리 주소를 저장하게 된다. 그리고 var b = a 라는 구문에서, 변수 a 초기화시 생성된 객체를 변수 b 에 복사하는게 아닌, a가 가진 메모리 주소, 즉 그 객체를 가리키는 메모리 주소를 복사하게 되는 것 이다.
이 때문에 변수 a 와 b 는 모두 같은 메모리 위치를 가리키게 된다, 즉 둘다 같은 객체를 가리키게 되는 것이다. 이 때문에 변수 a 에 적용되는 변화나, b 에 적용되는 변화는, 모두 같은 객체에 적용되게 된다.

이러한 자료형의 속성은 함수(Function)으로 아규먼트(Argument)를 넘겨줄 때 두드러지게 되는데

위에서 다룬것 처럼, Primitive Data 는 Value 를 넘겨주게 되고, Object는 Reference, 메모리 주소를 넘겨주게 된다.
그렇기 때문에 아래의 코드와 같은 결과가 나오게 된다.


function test(a, b) {
    a = 44;
    b.name = "name changed to c";
}

var a = 33;
var b = {
    name : "test object"
};

test(a, b);

console.log(a); // 33
console.log(b); // { name: 'name changed to c' }


이 차이를 잘 기억하도록 해, 후에 Argument passing 을 제대로 못해서 잘못된 스크립트를 적는 일이 없도록 하자

2015년 2월 26일 목요일

[JavaScript] Hoisting(호이스팅) 이란?

부제 : 함수 선언과 함수 표현의 차이
Function Declaration vs Function Expression


함수 선언과 함수 표현의 가장 큰 차이는 바로 Hoisting이다.
이걸 제대로 이해하기 위해서는 Execution Context에 대한 이해가 필수이니 이 글(클릭하기)를 읽고 와주길 바란다.

우선 Hoisting에 대해 간단히 말하자면, 후선언된 변수나, 함수들이 해당 Scope에서 최상위에 위치하는걸 뜻한다.
자바스크립트엔진은 해당 Execution Context의 생성시, 즉 Runtime 시점에서 변수선언문이나 함수선언문을 읽기 전에 선언된 변수와 함수들을 다른 무엇보다도 먼져 읽어 Scope의 최상위에 위치시킨다. 이 덕에, 훨씬 뒤에서 선언된 함수들과 변수들을 그 전에 사용이 가능하다.

*참고로 변수의 경우에는 변수 선언(Variable Declaration)만 Hoisting 된다, 즉 Variable Initialization이 있다면 변수가 선언은 되나, 변수에 어떤 값도 들어가지 않는다는 뜻.

*또한 함수의 Execution Context의 생성은 함수 호출시 이뤄지므로, 함수 내부에서 선언된 변수들은 함수 호출시에서야 Hoisting 된다.


console.log(internalFunction);// 함수가 Hoisting 됐을뿐, 아직 Execution Context는 생성되지 않았으므로, 에러가 발생한다.

functionDeclaration();// 함수가 성공적으로 호출되며 Function Declaration가 프린트 된다.

console.log();// Undefined 가 프린트 된다. 변수에 "vart"라는 값이 어싸인되는것은 아래 코드가 읽히는 시점에서기 때문.

function functionDeclaration() {
    console.log("Function Declaration");
    
    function internalFunction(){
    }
}

var t = "vart";

functionExpression(); // 에러가 발생

console.log(novalue); // Context에서 선언된적 없는 변수인 novalue를 호출할 수가 없어 에러가 발생

var functionExpression = function() {
    console.log("Function Expression");
}


그럼 이제 Hoisting을 제대로 이해했는지 확인도 할겸 아래 코드의 결과를 알아 맞춰보자.


function test1() {
    function internalFunction() {
 return true;
    }

    return internalFunction();

    function internalFunction() {
 return false;
    }
}

console.log(test1());

function test2() {
    var internalFunction = function() {
 return true;
    }

    return internalFunction();

    var internalFunction = function() {
 return false;
    }
}

console.log(test2());

function test3() {
    return internalFunction();

    var internalFunction = function() {
 return true;
    }

    var internalFunction = function() {
 return false;
    }
}

console.log(test3());

function test4() {
    var internalFunction = function() {
 return true;
    }

    return internalFunction();

    function internalFunction() {
 return false;
    }
}

console.log(test4());






정답은


  • test1 = false
  • test2 = true
  • test3 = TypeError: undefined is not a function
  • test4 = true
    • 참고로 test4는 hoisting 되었던 함수가 변수 표현문으로 다시 정의되어 true값을 반환하게 된다.
    • 기억하자, 자바스크립트에서는 함수 또한 객체에 불과하다. 그러니 재정의될 수 있다.

2015년 2월 23일 월요일

[JavaScript] 자바스크립트의 Function(함수)

타 프로그래밍 언어와 같이 자바스크립트(ECMAScript)의 함수(Function)는 Statement들을 언제 어디서든 실행할 수 있게 그 Statement들을 캡슐화(Encapsulation)하기 때문에 매우 중요한 기능을 하는 요소 중 하나 이다. 참고로 Function도 자바스크립트의 Object(객체) 자료형에 포함된다.
즉, 자바스크립트의 모든 함수(Function)들은 Object(객체)의 하위 개체인 Function 타입에 속하고, 우리가 프로그래밍시 함수(Function)에 부여하는 함수 이름은 다른 reference type의 경우처럼, 메모리에 저장된 함수 객체를 가리킬 뿐이다. 그렇기 때문에 함수(Function)은 일반 변수처럼(function expression) 선언이 가능하며, 코드상에 이름이 같은 함수 2개가 존재해도 Exception이 발생하지 않으며, 객체(Object)가 자신 내부에 또 다른 객체(Object)를 저장하는 것 처럼, 함수(Function)안에도 또 다른 함수를 선언할 수 있고, 하나의 함수를 여러가지 변수로 호출 할 수도 있다.

  • 참고로 Strict Mode에서 함수 선언시 함수 이름이나 함수 파라미터에 "eval" 또는 "arguments"라는 단어를 쓰지 못한다, 이는 좀 이따가 다루도록 하겠다
  • 자바스크립트(ECMAScript)에서 함수로 전달되는 Arguments는 언제나 Pass By Value이다. 즉 함수에서 전달된 Argument의 값을 변경해도 원래의 Argument 변수에는 영향이 가지 않는다.

함수(Function)의 선언


함수(Function)는 아래와 같이 정의가 가능하다.
정확히 말하자면 함수 정의는 2가지 방법으로 가능하다.
Function Declaration(함수 선언)Function Expression(함수 표현).
이 두가지 방법의 차이에 대해서는 다른 글(클릭하기)에서 좀 더 자세히 다뤄보도록 하겠다.


// Function Declaration
function functionIdentifier(arg1, arg2, arg3){
console.log("Demo Function Argument 1" + arg1);
console.log("Demo Function Argument 2" + arg2);
console.log("Demo Function Argument 3" + arg3);
// Statement를 여기에 적으면 된다.
}
// functionIdentifier 자리에는 함수의 이름이 오게되고
// 그 옆의 괄호안에는 함수 파라미터(Formal Parameter)가 오면 된다.

// 또는 아래와 같이 var 키워드를 이용 할 수도 있다. -Function Expression
// 알아야 할것은, 함수 표현식에서 정의되는 함수들 중, 
// function identifier가 정의되지 않은 함수들은
// 모두 anonymous function 또는 lambda function으로 불리며, 
// 이런 함수들은 이름(Function Identifier)를 가지지 않는다.
// 이 때문에 함수 객체의 "name" 프로퍼티는 공백의 문자열(empty string)이 된다.
// 즉, 해당 변수가 정의된 함수 객체를 참조할 뿐인것이다.
var functionExpressionExample1 = function functionIdentifier(arg1,arg2){
console.log("This is Function Expression1");
};

var functionExpressionExample2 = function(arg1,arg2){
console.log("This is Function Expression2");
};

// Self executing function이라 불리는 기법
// 함수 호출이 없이 함수가 실행된다.
(function(arg1,arg2){
console.log("This is Self executing function");
})();

//여러 변수들이 한개의 함수를 가리키게 할 수도 있다.
var func0 = functionName(arg1, arg2, arg3);
var func1 = functionName(arg1, arg2, arg3);
var func2 = functionExpressionExample1;


함수(Function)의 호출


함수(Function)은 언제 어디서든 함수 이름과, 아규먼트(Argument)를 괄호()에 포함해 호출이 가능하다.

//파라미터로 주어진 두 변수의 합(두 변수가 숫자일 경우), 또는 문자열의 합을 반환하는 함수
function addition(arg1, arg2){
return arg1 + arg2;
}

console.log(addition(3,4));//7


타 프로그래밍 언어와 달리, ECMAScript 함수는 주어지는 Argument의 갯수가 Formal Parameter의 갯수와 일치하지 않아도 함수 호출이 가능하다. 말인즉, 이름이 같은 함수 A가 Formal Parameter로 2개의 변수를 받을 때, 3개 또는 0개의 Argument로도 함수 A를 호출 할 수 있다는 뜻 이다. 이는 자바스크립트가 함수(Function)에 Argument 를 전달할 때 Array 객체로 전달하기 때문이다. 다른 프로그래밍 언어(특히 Java)와는 궤를 달리하는 방식인데, 이러한 이유 때문에, Java 또는 C#에서 가능한 method polymorphism이 Javascript(ECMAScript)에서는 구현이 불가능 하다.
참고로 Argument 값이 주어지지 않는 Parameter는 언제나 Undefined 값을 가지게 된다.


//파라미터로 주어진 두 변수의 합(두 변수가 숫자일 경우), 또는다 문자열의 합을 반환하는 함수
function addition(arg1, arg2){
return arg1 + arg2;
}

console.log(addition(3,4));//7
console.log(addition(3));//NaN 이 경우에는 arg2에 undefined 값이 어싸인 된다.
console.log(addition(3,4,6));//7 이 경우에는 세번째 아규먼트는 사용되지 않는다.


이게 가능한 이유는 Array(배열)형식으로 전달된 Arguments들과, 함수의 실행시 전달된 Argument Array의 사이즈를 확인하지 않는 자바스크립트(ECMAScript)의 특성 때문이다. 이러한 특수한 이유 때문에 자바스크립트(ECMAScript)의 함수에서 배열에 접근하듯 Array Bracket Notation([] 사각 괄호안에 인덱스를 넣어 배열에 접근하는 방법)을 이용해서 함수에 주어진 Argument에 접근할 수 있다.
  • 참고로 배열의 이름은 "Arguments" 이다, 이 때문에 Strict 모드에서 "Arguments"라는 단어를 함수 이름이나 함수 파라미터의 이름으로 사용할 수가 없다.


//파라미터로 주어진 두 변수의 합(두 변수가 숫자일 경우), 또는 문자열의 합을 반환하는 함수
function addition(arg1, arg2) {
 if (arguments[2] == undefined) {
  return arg1 + arg2;
 } else {
  return arg1 + arg2 + arguments[2]
 }
}
console.log(addition(3,4));//7
console.log(addition(3));//NaN
console.log(addition(3,4,6));// 13


위의 코드에서 arg1, arg2는 각각 arguments 배열의 인덱스 0과 1에 위치하고, 3번째 Argument는 인덱스 2에 위치하게 된다.
그렇기 때문에 3번째 Argument, 즉 인덱스 2에 위치한 변수가 undefined 값을 가진 경우에는 첫번째 두번째 변수의 합을 반환하지만, 반대의 경우에는 주어진 3개의 변수들 모두의 합을 반환하게 된다. 또는 아래와 같은 사용도 가능하다.


function demoConcatString() {
    var t = "";
    for (var i = 0; i < arguments.length; i++) {
 t = t + arguments[i] + " ";
    }
    return t;
}

console.log(demoConcatString("This", "is", "demo"))// This is demo;


함수의 Arguments 배열은 매게 변수들을 제외하고도 callee 라는 프로퍼티를 가지고 있는데, Arguments 배열과 관계된 함수를 가리킨다.


function demo() {
    console.log(arguments.callee);
}

demo();// [Function: demo]


arguments.callee 가 호출 된 함수를 가리킨다면, function.caller 는 호출 한 함수를 가리킨다. 만약 global context에서 호출됬다면 null 값을 가진다.


function demo() {
    console.log(demo.caller);
}

function caller() {
    demo();
}

demo();// null, global 컨텍스트에서 호출 됬을 때는 null

caller();// [Function: caller]


함수 오버로딩(Function Overloading)


위에서 잠깐 이야기 했듯, 자바스크립트의 함수는 객체에 불과하며 Arguments 들이 배열(Array) 형식으로 전달되기 때문에 사실상 Function Signature를 가지지 않는다. 이러한 이유 때문에 자바(Java)나 C# 등에서 사용되는 Method Overloading은 구현이 불가능하다. 만약 같은 이름의 함수를 여러개 선언했다면, 가장 마지막에 선언된 함수가 실행될 것이니 이러한 실수는 피하도록 하자.


function demoConcatString(arg1) {
    var t = "";
    for (var i = 0; i < arguments.length; i++) {
 t = t + arguments[i] + " ";
    }
    return t + "1";
}
function demoConcatString(arg1, arg2) {
    var t = "";
    for (var i = 0; i < arguments.length; i++) {
 t = t + arguments[i] + " ";
    }
    return t + "2";
}
function demoConcatString(arg1, arg2, arg3) {
    var t = "";
    for (var i = 0; i < arguments.length; i++) {
 t = t + arguments[i] + " ";
    }
    return t + "3";
}

console.log(demoConcatString("This", "is", "demo")); //This is demo 3, 가장 마지막의 함수가 호출된다.

2015년 2월 17일 화요일

[JavaScript] 자바스크립트 Object(객체)

자바스크립트의 Object 데이터 타입

자바스크립트(ECMAScript)의 Object 데이터 타입은 다른 프로그래밍 언어의 Object 와 같이 여러개의 자료(Data)들과 함수(Function)들의 집합이다(자바스크립트도 객체지향프로그래밍언어(Object Oriented Programming language)이다). 주로 객체라 불리며 자바스크립트의 유일한 Composite/Reference Data Type 이다(다른 reference data type은 모두 object 타입의 하위 타입).

참고로 자바스크립트에서 Primitive Data Type들을 제외한 모든것들이 다, 심지어는 함수까지 모든게 Object 타입이다. 또한 Primitive Data Type 마져 접근될시에는 자바스크립트 VM에의해서 Object 타입으로 변환되어 사용된다. 즉 모든게 Object 타입이라 할 수는 없지만 모든게 Object 타입처럼 작동한다고 할 수 있다.
이러한 이유로 Object(객체) 자료형은 모든 자료형의 최상위 타입이라고 할 수 있다. 객체 자료형을 포함 하위 타입의 자료형들은 총 7개의 함수들과 속성들을 가진다.

자바스크립트(ECMAScript)의 Object 타입은 모든 다른 객체들이 파생된 Base Type 이다. Object 타입은 기본적으로 총 7개의 프로퍼티(Property)들과 메소드(Method)들을 가진다.
  • constructor
    • Object를 생성하는 생성자
  • hasOwnProperty(속성이름)
    • 객체에 주어진 속성이 있는지를 확인하는 메소드
  • isPrototypeof(Object)
    • 객체가 파라미터로 주어진 Object 의 Prototype 인지를 확인하는 메소드
  • propertyIsEnumerable( 속성이름)
    • 객체의 속성들이 for-in 구문으로 Enumerated(열거) 될 수 있는지
  • toLocaleString()
    • 객체를 실행 환경에 알맞은 형태의 String으로 표현한다
  • toString()
    • 객체를 String으로 표현한다
  • valueOf()
    • object 의 primitive value(원시 값)을 반환한다. 
    • 즉 객체에 가장 알맞는 표현을 string, number, boolean 값 중 1개로 반환한다.

    자바스크립트(ECMAScript)에서의 Object(객체)는 자바처럼 new 연산자를 이용해서 선언거나 Object Literal Notation을 이용해서 선언 될 수 있다. 그리고 개발자들은 새로운 객체를 선언하면서 또는 선언한 후, 속성과 기능(메소드)들을 추가함으로써 자신만의 객체를 만들 수가 있다.

    
    //New 연산자를 사용해서 선언
    var objectVariable = new Object();//이게 표준
    var improperObjectDeclaration = new Object;//괄호가 없어도 되지만 되도록이면 괄호를 붙이도록 하자.
    var demoObject1 = new Object();
    demoObject1.name = "Demo Object 1";//속성(Property) 부여
    demoObject1.message = "This is Demo Object";//속성(Property) 부여
    
    //Object Literal Notation을 이용해서 선언
    var demoObject2 = {
     name : "Demo Object 2",
     message : "This is Demo Object 2"
    };
    
    var demoObject3 = {
     "name" : "Demo Object 2",
     "message" : "This is Demo Object 3",
     3 : "Three", //숫자를 속성 이름에 사용할 수도 있다. 이 경우에는 이름이 자동으로 String 형으로 변환된 후 저장된다
            "This is" : 7798 //속성 이름에 스페이스가 들어갈 수도 있다.
    };
    
    var demoObject4 = {}; // new Object() 와 같다
    demoObject4.name = "Demo Object 4";
    demoObject4.message = "This is Demo Object 4";
    

    위와 같이 선언된 객체의 속성들은 Dot Notation 을 통하거나 Bracket Notation을 이용해서 접근이 가능하다
    단 Dot Notation을 이용할 경우에는 숫자로 이름 지어진 속성이나 이름에 스페이스가 들어가는 속성에는 접근이 불가능하다. 이는 JavaScript의 문법(Syntax)적 한계이니, 이러한 경우에는 Bracket Notation을 이용하면 된다

    
    // Dot Notation
    console.log(demoObject3.name);
    console.log(demoObject3.message);
    console.log(demoObject3.3); // Syntax 에러
    console.log(demoObject3.This is); // Syntax 에러
    demoObject3.message = "New Message";
    
    // Bracket Notation
    console.log(demoObject3["name"]);
    console.log(demoObject3["message"]);
    console.log(demoObject3["3"]);
    console.log(demoObject3["This is"]); 
    // Bracket Notation의 경우에는 이런식의 접근도 가능하다
    var propertyName = "name";
    console.log(demoObject3[propertyName]);
    demoObject3[propertyName] = "new Demo Object";
    


    2015년 1월 28일 수요일

    [JavaScript] 자바스크립트 String(문자열) 자료형

    자바스크립트 String 데이터 타입

    16bit 유니코드 문자들로 이루어지는 String(문자열) 데이터 타입 이다. 이 또한 다른 프로그래밍 언어에서도 볼 수 있는 흔한 타입이다. 자바스크립트(ECMA 스크립트)에서 String 타입은 쌍따옴표(")와 단따옴표(') 로 문자열을 감쌈으로써 선언이 가능하다. 단 문자열을 감싸는 따옴표가 같은 따옴표여야 한다.

    
    var stringVar1 = "StringTest1";
    var stringVar2 = 'StringTest2';
    var stringVar3 = "StringTest2';//에러가 나게된다.
    
    

    String 데이터 타입의 메모리 관리


    사실 String(문자열) 타입은 따로 특별히 다룰게 없는데, String 데이터 타입의 메모리 매니지먼트는 알아두는게 좋다. Number, Boolean 등 다른 Primitive Data Type(원시 자료형)들이 변수 값의 수정시 추가적인 메모리 할당을 하지 않는 것에 반해, String 자료형은 변수값이 변경될 때마다 새로운 메모리를 할당해줘야한다. 물론 이건 자바스크립트 엔진이 할 일이니 코딩시 개발자들이 따로 특별한 코드를 부가해야하는 것은 아니다. 이런 일들이 벌어지게되는 이유는 바로 String(문자열) 데이터 타입이 이름에서도 잘 알 수 있듯 "문자들의 열"로 이루어져있기 때문이다. 16bit 유니코드 문자들의 열로 이루어진 ECMAScript 의 String 자료형은 문자 1개당 2바이트의 메모리를 소모하게 되다. 그렇다면 한번 생각해보자.

    ABCDEFGH 라는 스트링을 저장해야한다고 할 때

    [A][B][C][D][E][F][G][H]
    처럼 16 바이트의 연속되는 메모리를 할당하는게 좋을까?

    아니면

    [A][ ][ ][ ][ ][ ]
    [ ][B][C][D][ ][ ]
    [ ][ ][F][G][ ][E]
    [ ][ ][ ][H][ ][ ]
    처럼 각기 떨어져있는 메모리들을 할당하는게 좋을까?

    물론 당연히 전자의 경우가 훨씬 효과적일 것이다. 전자의 경우에는 메모리가 서로 연속되있어, RAM에 엑세스할시에 후자에 비해 훨씬 빠른속도로 전체 엑세스가 가능하다. 하지만 후자의 경우에는 각기 떨어져있는 메모리에 엑세스하느라 전자에 비해서는 느리게 읽게될것이다. 물론 이는 매우 미세한 차이지만, 메모리 관리의 효율성 관점으로 보았을 때, 후자의 경우대로 관리해서는 절대로 안될 것이다.

    어쨋든 이게 String 값이 변경될 때 새로운 메모리를 할당해야된다는 것과 무슨 관련이 있나면,
    스트링 변수에 주어진 메모리 바로 옆에 새로운 값이 할당되는것과 같은 아래의 경우와 같은 일이 발생할 수도 있다는건데

    [A][B][C][D][E][F][G][H][0][N][E][W][V][A][L][U][E]

    만약 이 경우에 새로운 메모리블록을 할당하지 않고 ABCDEFGH라는 스트링 값에 IJK를 추가해야 한다면, 아마 [0][N][E][W]가 저장된 메모리와 그 뒤의 메모리들이 순차적으로 뒤로 밀려나거나(매우 비효율적인 방법), [0][N][E][W]라는 메모리를 그냥 무시하고 [I][J][K][0]로 그냥 덮어 씌울 수도 있겠다. 하지만 이 경우에는 결국 NEWVALUE라는 값이 저장된 변수를 훼손하게 된다. 이런 이유 때문에 스트링값의 변경이 있을시에 새로운 메모리 블락을 할당해주고, 그 전 블락을 풀어주게 되는건데, 코드로 보자.

    
    var stringVar1 = "ABCDEFGH";//[A][B][C][D][E][F][G][H]
    var stringVar2 = 'NEWVALUE';//[A][B][C][D][E][F][G][H][0][N][E][W][V][A][L][U][E]
    var stringVar1 = stringVar1 + "IJK";
    
    

    위의 코드가 실행되면 메모리 할당은 아래와같이 바뀌게 된다

    [ ][ ][ ][ ][ ][ ][ ][ ][ ][N][E][W][V][A][L][U][E]
    [ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]
    [A][B][C][D][E][F][G][H][I][J][K][ ][ ][ ][ ][ ][ ]

    이 모든게 개발자들이 보는 모니터 뒤에서 일어나는 일이기는 하지만, 이 때문에 자바스크립트 엔진 String 데이터 타입 관리에 따라서, String Concatenation(문자열 연결) 작업에 걸리는 시간이 좌지우지 되고, 나아가선 자바스크립트 엔진의 성능차이가 발생하는 원인이 되기도 한다.

    String(문자열) 타입의 자동 타입 변환


    타 자료형의 String 타입으로의 변환은 toString() 함수나, String() 함수로 손 쉽게 가능하다.
    그리고 코드 작성시 보게되는 텍스트를 그대로 스트링타입으로 변환하니, 변환 불가능한 값이 없다고 말할 수 있다

    
    var boolTrue = true;
    var stringVar1 = boolTrue.toString(); //"true"
    
    //toString()함수는 파라미터로 radix를 넣어서 2, 8, 10, 16진수로 변환 할 수도 있다.
    var var1 = 33;
    var stringVar1 = var1.toString(2); //"100001"
    var stringVar2 = var1.toString(8); //"41"
    var stringVar3 = var1.toString(16); //"21"
    
    //단 null 이나 undefined 값은 toString() 함수로 변환하기가 불가능하다. 
    //그렇기 때문에 필요한 경우에는 될 수 있으면 String() 함수를 이용해주자
    
    var stringVar4 = String(null); //"null"
    var stringVar5 = String(undefined); //"undefined"
    var stringVar6 = String(2); //"2"
    
    //또 따옴표를 이용할 수도 있다
    var stringVar7 = '\"' + var1 + '\"'; //"33"
    
    

    2015년 1월 27일 화요일

    [JavaScript] 자바스크립트 Boolean 자료형

    자바스크립트의 Boolean 데이터 타입

    어떤 프로그래밍 언어에도 존재하는 자료형, 값이 true 또는 false, 총 2개밖에 존재하지 않는 자료형, 바로 Boolean 자료형이다. Boolean 자료형은 아래와 같이 선언된다.

    
    var trueVariable = true;
    var falseVariable = false;
    
    //대소문자를 가리니, True 나 False 를 어싸인할시에는 에러가 뜬다
    
    var trueVariable0 = True;
    var falseVariable0 = False;
    

    Number 자료형이 Number() 함수, parseInt() 함수를 사용해서 자료형을 변환할 수 있는 것처럼 Boolean 자료형도 Boolean 함수를 이용해서 다른 자료형을 Boolean 자료형으로 변환이 가능하다.

    
    var booleanVar1 = Boolean("String");
    var booleanVar2 = Boolean(null);
    var booleanVar3 = Boolean(undefined);
    var booleanVar4 = Boolean(4);
    var booleanVar5 = Boolean(true);
    

    자바스크립트 Boolean() 함수 자료형 변환 표


    자료형
    변환시 Boolean 값
    truefalse
    Booleantruefalse
    String공을 제외한 모든 스트링 값스트링이 "" 처럼 공일때
    Number0 보다 큰 모든 수들0 or NaN
    Objectnull 을 제외한 모든 object 들null
    Undefined해당 사항 없음undefined
    Null해당 사항 없음null

    [JavaScript] 자바스크립트 Number 자료형

    자바스크립트의 Number 데이터 타입

    ECMAScript 에서 Number 자료형은 정수형(Integer Value)이든 소수형(Floating Point Value)이든 상관없이 IEEE-754 형식을 이용해서 저장한다. IEEE-754가 뭔지 잠시 짚고 넘어가자면

    IEEE-754는 전기 전자 기술자 협회(IEEE)에서 개발한 컴퓨터에서 부동소수점를 표현하는 가장 널리 쓰이는 표준이다. ±0 등의 수와 무한, NaN 등의 기호를 표시하는 법과 이러한 수에 대한 연산을 정의하고 있다.

    간단히 말하자면 0 과 1, 즉 이진법으로 이루어진 컴퓨터 연산체계에서 0 과 1 이상의 수들을 표현하는 표준 방식이라고 할 수 있다. IEEE-754 체계에서는 가장 첫번째 비트가 +,-인지를, 즉 그 수가 음수인지 양수인지를 나타내는데, 이러한 이유로 ECMAScript 에서는 0과 -0이 둘다 존재할 수 있다. 물론 0 == -0이라는 조건은 true(참)이다.

    정수형


    IEEE 32bits Single Precision 형식
    IEEE 32bits Single Precision 형식

    ECMAScript 는 굉장한 유연성과 높은 자유도를 가졌는데, 이러한 이유로 다양한 정수형 수들(8진수, 16진수)을 표현하기위한 다양한 문법들이 존재한다.
    참고로 정수형 수들을 저장할 때는 32bits single precision 형식으로 저장된다는걸 기억하자. 즉 어떤 정수 값이든간에, 32비트 형식으로 저장된다는 것 이다. 위의 그림에 나와있는 방식으로 저장된다 생각하면 된다.

    
    var integerNumber = 35; //integer 값을 선언할 때
    
    //8진수를 표현할 때는 첫번째 자리의 숫자가 무조건 0 이여야 한다.
    var octalNumber1 = 07; //8진수 07, 10진수로 환산하면 7
    var octalNumber2 = 017; //8진수 017, 10진수로 환산하면 15
    var octalNumber3 = 019; //3번째 자리의 수가 8진수에 없는 숫자인 9라 일반 10진수로 받들여지게 된다.
    //하지만 8진수의 사용은, strict 모드에서 에러를 발생시키고, 몇몇 브라우져에서는 제대로 실행되지 않으므로 사용을 자제하자.
    
    //16진수를 표현할 때에는 숫자 앞에 무조건 0x 를 붙인다.
    var hexaNumber1 = 0x7; //16진수 07, 10진수로 환산하면 7
    var hexaNumber2 = 0xA7; //16진수 A7, 10진수로 환산하면 167
    var hexaNumber3 = 0xB35; //16진수 B35, 10진수로 환산하면 2869
    
    

    하지만 결국 16진수나 8진수로 선언된 변수들도 연산시에는 다 10진수로 변환되니, 별다른 특별한 이유가 없으면 10진수를 사용하도록 하자.

    소수형


    IEEE 64bits Double Precision 형식
    IEEE 64bits Double Precision 형식

    ECAMScript에서의 소수형은 정수형과는 달리 64bits double precision 형식으로 저장된다. 바로 위의 그림과 같은 형식이다. 소수형 수들은 아래와 같이 선언되는데

    
    var floatingNumber1 = 0.3; 
    var floatingNumber2 = 1.47;
    var floatingNumber3 = .7;//안 좋은 예제 1
    var floatingNumber3 = 3.;//안 좋은 예제 2, 결국 3으로 자동 변환되 저장됨
    var floatingNumber3 = 4.0;//안 좋은 예제 3, 4가 정수형으로 인식되서 32bit 형식으로 저장됨
    var floatingNumber3 = 4.572e3;// = 4572, 많이 작거나 큰 숫자의 경우에는 e-notation을 이용 10의 몇 승으로 표현할 수 있다.
    var floatingNumber3 = 4.572e-3;// = 0.04572
    //ECMASCript 는 소수점아래로 0이 5개보다 많을 시에 무조건 e-notation을 이용한 표기법으로 수를 표현한다.
    var testFloat = 0.0000006533;
    console.log(testFloat); //6.533e-7
    
    

    위와 같이 다양한 방식으로 선언되고 어싸인될 수 있는데, 몇가지 피해야할 방식들이 있다. ECMAScript에서 정수형은 32bits로 소수형은 64bits 로 표현되는 만큼, 소수형을 표현하는데는 정수형의 2배에 달하는 메모리를 사용해야 한다. 이러한 이유로 ECMAScript는 제대로된 형식이 아닌 소수형 수들은 무조건 integer로 인식 32bits 형식으로 저장하게 된다.

    우선 안 좋은 예제 1은 작동은 하나, 최대한 피해야할 방법이다. 몇몇 Javascript 엔진에 따라서는 에러가 뜰 수도, 또는 0이나 1로 변환되서 저장될 수도 있다.
    안 좋은 예제 2 같은 경우는 제대로 완성되지 않은 숫자라, 3으로 자동 변환되서 저장된다.
    안 좋은 예제 3 같은 경우에는 숫자 4.0가 정수형으로 변환되서 32bit 형식으로 저장된다.

    소수형을 이용한 연산을 할 때 조심해야할건, 무슨 일이 있어도 var1 + var2 = 0.6 같은 소수형 비교는 하면 안된다는건데, 이 이유는 IEEE-754의 정확성에 있다.

    IEEE-754 방식은 그냥 일반 수를 표현할 때는 소수점 아래로 17번째 자릿수까지 완벽하게 정확하지만, 사칙연산시에 그 결과값의 정확성이 매우 떨어지기 때문이다.

    
    var var1= 0.2; //Double Precision시에 0.20000000298023224라는 값으로 저장된다.
    
    var var2= 0.4; //Double Precision시에 0.4000000059604645라는 값으로 저장된다.
    
    console.log(var1 + var2 == 0.6); //false값이 프린트된다
    
    var var3= 0.6; //Double Precision시에 0.6000000238418579라는 값으로 저장된다.
    
    console.log(var1 + var2 == var3); //false값이 프린트된다
    
    

    위와 같은 경우
    var1 + var2 는 0.6000000089406967라는 결과를 도출하게되고, 0.6이라는 값(메모리내에는 0.6000000238418579라는 값으로 저장) 과 일치하나는 조건에서 false(거짓)값을 가지게 된다.
    그러니 소수형 수의 연산값을 이용한 조건문은 절대로 쓰지 않도록 하자.

    표현할 수 있는 수의 범위와 무한(Infinity) 값

    ECMAScript에서 Number 자료형을 표현할 때 사용하는 비트수에 제한이 있다보니, 표현할 수 있는 수가 무한하지가 않다. 
    최대로 표현가능한 수와 최소수는 아래와 같이 확인이 가능하다.

    
    console.log(Number.MAX_VALUE); //양수의 최대값 
    console.log(Number.MIN_VALUE); //양수의 최소값
    
    

    만약 이에서 더 커지거나 작아지면 IEEE-754로 표현하는 한계를 넘으면 그 수는 Infinity 로 표현된다

    
    console.log(Number.MAX_VALUE + Number.MAX_VALUE); //Infinity
    console.log(- Number.MAX_VALUE - Number.MAX_VALUE); //-Infinity
    
    

    그리고 Infinity 값은 Infinity를 제외한 다른 수와의 어떤 연산에서도 Infinity 값을 결과로 도출한다.
    참고로 Infinity 값은 아래와 같이 불러올 수 있다.

    
    console.log(Number.NEGATIVE_INFINITY + Number.POSITIVE_INFINITY); //NaN
    console.log(Number.NEGATIVE_INFINITY + Number.MAX_VALUE); //-Infinity
    console.log(Number.POSITIVE_INFINITY - Number.MAX_VALUE); //Infinity
    
    

    NaN 값 이란?


    간단하다. Not a Number 의 약자로 연산의 결과가 수가 아닐때 사용된다.
    -Infinity + Infinity, 3/0 와 같이 결과가 숫자로 도출될 수 없을 떄 사용된다.

    
    console.log(Number.NEGATIVE_INFINITY + Number.POSITIVE_INFINITY); //NaN
    console.log(NaN + 3);//NaN이 포함된 연산은 언제나 결과가 NaN이다.
    
    console.log(NaN == NaN); //false
    //NaN값은 본인을 포함한 어떠한 값과도 Equal하지 않는다. 이러한 이유로 ECMAScript 에는 isNaN이라는 function이 있다
    
    console.log(isNaN(NaN)); //true
    
    

    이 isNaN() function 은 주어진 파라미터를 Number 자료형으로 변환 시도를 해서, 성공적으로 변환이 되면 false 를 아니라면 true 값을 리턴하는 함수이다.
    그러니 ECMAScript 의 자동변환으로 Number 자료형으로 변환될 수 있는 경우에는 false 값이 리턴된다.

    
    console.log(isNaN(NaN)); //true 
    console.log(isNaN(1)); //false 
    console.log(isNaN("1")); //false 
    console.log(isNaN("test")); //true
    console.log(isNaN(true)); //false
    
    

    타 자료형을 Number 자료형으로 변환시 

    자바스크립트(ECMAScript)는 Number(), parseInt(), parseFloat() 함수등을 이용해 타 자료형을 Number 자료형으로 변환 할 수가 있다. 변환 값은 아래 표를 참고하자

    Number() 함수를 사용해 타 자료형을 변환시


    
    var num1 = Number("String");
    var num2 = Number(true);
    var num3 = Number(null);
    var num4 = Number(undefined);
    var num5 = Number(NaN);
    var num6 = Number(new Object());
    
    

    자료형
    변환시 Number 값
    01NaN숫자
    Booleanfalsetrue해당 사항 없음해당 사항 없음
    Undefined해당 사항 없음해당 사항 없음undefined해당 사항 없음
    Nullnull해당 사항 없음해당 사항 없음해당 사항 없음
    Number01NaN모든 숫자들
    String"0" or """1","01""TEST", "0Tx34",등 다른 조건에 부합하지 않을 때따옴표 사이에 숫자밖에 없을 때 자동으로 수로 변환(16진수도 10진수로)
    Object해당 사항 없음해당 사항 없음모든 object 타입해당 사항 없음


    String 자료형의 Number 자료형으로의 변환에 대해 짧게 설명하자면, 

    "0", "11", "055" 와 같이 스트링의 따옴표 사이에 숫자 밖에 없다면, 무조건 동일한 Number 값으로 변형된다. 숫자의 맨 앞에오는 0은 생략되고, 만약 따옴표안에 "0xAB"와 같이 16진수 수가 있다면 자동으로 10진수로 변환된다. 

    Empty String, 빈 스트링 값 같은 경우에는 무조건 0으로 변환되고, 이를 제외한 모든 상횡에서는 다 NaN값으로 변환된다.

    parseInt() 함수를 사용해 타 자료형을 변환시

    parseInt() 함수는 Number 함수와 String 자료형 변환을 제외하고는 모두 똑같은 변환값을 가진다. 하지만 String 값의 경우에 캐릭터가 들어간 모든 String을 NaN 값 으로 변환하는 Number와 달리 첫자리가 숫자라면, 이어지는 숫자들까지 모두 Number 자료형(정수)으로 변환한다. 또한, 파라미터에 radix 를 설정해줄 경우에, 주어진 스트링을 2진수, 8진수, 16진수, 10진수로 인식하는것을 설정할 수도 있다

    var num1 = parseInt("String");
    var num1 = parseInt(true);
    var num2 = parseInt(null);
    var num3 = parseInt(undefined);
    var num4 = parseInt(NaN);
    var num5 = parseInt(new Object());
    var num6 = parseInt("1110",2); //1110을 2진수로 인식, 10진수 14로 변환한다
    var num7 = parseInt("17",8); //17을 8진수로 인식, 10진수 15로 변환한다
    var num8 = parseInt("A3",16); //A3을 16진수로 인식, 10진수 163으로 변환한다
    var num9 = parseInt("333",10); //10진수로 인식한다
    
    

    자료형
    변환시 Number 값
    01NaN기타
    Booleanfalsetrue해당 사항 없음해당 사항 없음
    Undefined해당 사항 없음해당 사항 없음undefined해당 사항 없음
    Nullnull해당 사항 없음해당 사항 없음해당 사항 없음
    Number01NaN모든 숫자들,(소수일때 정수자리만 변환)
    String"0" or """1","01""TEST", "Tx34",등 다른 조건에 부합하지 않을 때앞자리들이 숫자일 때는 앞자리들을 수로 변환("43TX8" -> 43)
    만약 16진수라면 10진수로 변환("0xApp" -> 10)
    Object해당 사항 없음해당 사항 없음모든 object 타입해당 사항 없음



    parseFloat() 함수를 이용해 타 자료형을 변환시

    parseFloat() 함수는 parseInt() 함수와 모든게 같으나, 32bits 정수형으로 변환하는 parseInt()함수와 달리 String 자료형 변환에서 소수형 수를 발견할 때 64bits 소수형으로 변환한다. 만약 정수형수라면 32bits 정수형으로 변환

    var num1 = parseInt("String");
    var num1 = parseFloat("0.44TQG"); //0.44
    var num2 = parseInt("32BB"); //32(O), 32.0(X)
    
    

    2015년 1월 26일 월요일

    [JavaScript] 자바스크립트 Undefined 와 Null의 차이

    Undefined Type


    자바스크립트의 Undefined 타입은 값이 1개밖에 없다. 바로 'Undefined' 단 하나이다.
    이 Undefined 라는 값은 변수가 정의되지 않았다는것을 의미하는데, 가장 쉽게 이 값을 얻는 방법은 var 키워드를 이용해 변수를 선언하고 초기화 하지(값이 어싸인되지 않았을 때) 않는 것 이다.

    
    var testVar;
    console.log(testVar);//undefined 가 프린트 될 것이다.
    console.log(typeof testVar);//undefined 가 프린트 될 것이다.
    
    

    ECMAScript 는 Primitive Data Type(원시 자료형) 5개, Composite/Reference Data Type(객체) 1개, 총 6개의 자료형을 가지고 있는데 undefined 는 Primitive Data Type 중 하나 이며, 저 5개의 Primitive Data Type(원시 자료형)에 포함되지 않는 값을 나올 때 있을 때 자동으로 undefined 값이 된다.
    물론 변수에 undefined 값을 어싸인해주는 것도 가능하다

    
    var undefinedVar = undefined;
    console.log(undefinedVar);//undefined 가 프린트 될 것이다.
    console.log(typeof undefinedVar);//undefined 가 프린트 될 것이다.
    
    

    하지만 ECMAScript에 undefined 라는 자료형이 추가된 것은 단순히 변수 값들의 비교 작업을 수월히 하기 위해서이니, 위와 같이 변수 값에 undefined를 어싸인해주는 것은 자제하도록 하자.
    그리고 또 하나 알아둬야 할 것은, 자바스크립트에서 변수생성은 변수 선언(Variable Declaration)에 의해 이루어지니 선언된적 않은 변수들은 절대로 undefined 값을 가지지 않는다.

    
    var undefinedVar;//세미콜론(;)으로 선언을 완료했다.
    console.log(undefinedVar);//undefined 가 프린트 될 것이다.
    console.log(undeclaredVar);//Uncaught ReferenceError: undeclaredVar is not defined 에러를 보게될것이다
    
    

    Null Type


    Null 타입은 Undefined 타입과 같이 값이 null 1개 밖에 없다. Null 타입과 Undefined 타입의 차이점은 undefined 타입이 Primitive Data Type(원시 자료형)에 사용되는 자료형이고, null 타입은 Complex Data Type(복합 자료형), 즉 Ojbect(오브젝트)에 사용되는 자료형이라는건데... 즉 이론적으로 Null 타입은 Empty Object를 가리키는 포인터인데, 이 때문에 null 값을 가진 변수나 null 값에 typeof 연산자를 사용하게 되면, object 라는 결과가 나온다.

    
    var t = null;
    console.log(typeof t);//object 가 프린트 될 것이다
    console.log(typeof null);//object 가 프린트 될 것이다
    
    

    참고로 undefined 값은 null 값의 하위 타입이라 == 연산자를 이용해 비교하게되면, true 값이 나온다.

    
    
    console.log(undefined==null);//true 값이 나온다.
    
    
    

    그렇다면 이 null이라는 자료형을 어디에 써먹어야 하는가, 간단하다.
    추후에 필요한 object 타입의 변수를 미리 생성해 놓아야할 때

    
    var t = null;
    if(t==null){
    t = loadbook();
    }
    
    

    또는 Empty Object 가 필요한 작업에

    
    var book = null;
    book = loadBook()
    if(book==null){
    alert("책을 로드하는데 실패했습니다.");
    }
    
    

    요렇게들 사용하면 된다.

    2015년 1월 24일 토요일

    [Eclipse] 이클립스에서 Node.js 개발 환경 세팅하기

    Node.js 로고
    Node.js 로고
    자바스크립트(JavaScript) 개발을 하다 보면 제대로 된 디버거가 없어서 alert 나 console 을 사용해서 웹브라우져의 개발자 도구 콘솔에 프린트 하거나 팝업을 띄우기 마련인데, 이런 방식은 쉴틈없이 새로고침을 해줘야 해서 귀찮기 마련이다. 그러니 이클립스Node.js 를 이용해서 이클립스에 자바스크립트 콘솔을 세팅해보도록 하자.

    우선 Eclipse 를 켜서 하고 메뉴에서 Help->Install New Software를 클릭하면 아래와 같은 창을 보게 될 것이다.

    이클립스 부가 소프트웨어 설치 스크린
    이클립스 부가 소프트웨어 설치 스크린

    노란색으로 강조해 놓은 옵션 박스에서, 본인의 이클립스 버젼을 선택한 후에, 아래의 이클립스 확장들을 설치해 준다.
    • JavaScript Development Tools 
    • Eclipse Web Developer Tools 

    그리고 이곳[http://nodejs.org/]에서 Node.js 인스톨러를 다운 받아 설치해준다.
    설치 후에 시스템 속성에 들어가 환경변수 설정에서 시스템 변수를 등록 해주자.

    Node.js 윈도우 환경 변수 등록

    나 같은 경우는 위와 같이 등록해줬다. node.js 설치시 기본값으로 설치했다면 변수 값을 나와 같이 하면 된다. 그리고 본인의 변수 이름을 잘 기억하도록 하자.

    그리고 다시 Eclipse 로 돌아가서 메뉴에서

    Run -> External Tools -> External Tools Configuration
    외부 도구 설정으로 들어가자


    Eclipse 외부 도구 설정

    위의 이미지에 1 Javascript라 적힌건 무시하자, 내가 이미 설정해 놓은게 있어서 저렇게 나오는거니까.

    그리고나서 저걸 클릭하면 요런 창을 보게 되는데



    노란색으로 칠해놓은 새로만들기 버튼을 누르면




    이런 창을 보게 된다. 여기서 Location, Working Directory, Arguments를 저렇게 적어주자.

    만약 환경변수 설정시에 변수 이름을 node 로 하지 않았다면 Arguments의

    /c "node ${resource_loc}" /c "환경변수이름 ${resource_loc}"

    이렇게 적어주면 된다.

    그리고나서 자바스크립트 프로젝트를 생성하고  console.log 를 이용 스크립트 작성 후 아래와 같이 External Tool을 클릭해서 방금 우리가 만든 설정을 이용하면





    이렇게 이클립스 콘솔에 프린트 된다. 

    2015년 1월 23일 금요일

    [JavaScript] Keyword 들과 Reserve Words 란?

    자바스크립트의 Keyword(키워드)란?


    ECMA Script 는 Statement 를 시작하거나 끝낼 때, 특수한 기능을 수행할 때 등 특수한 목적을 위한 Keyword들을 가지고 있는데 이러한 키워드들은 특수한 목적을 두고 있으니 사용이 제약된다. 특히 keyword 는 코드 작성시 변수 이름이나 함수 이름, 그리고 property 이름에 사용할 수 없으니 피해 가도록 하자. 만약 사용할 경우에는 'Identifier Expected' 라는 에러를 보게 될 것이다.

    do
    break 
    do 
    instanceof 
    typeof 
    case 
    else 
    new 
    var 
    catch 
    finally 
    return 
    void 
    continue 
    for 
    switch 
    while 
    debugger
    function
    this
    with
    default
    if
    throw
    delete
    in
    try
    
    

    자바스크립트의 Reserve Word(예약 키워드)란?


    위에서 설명한 단어들이 현재 사용되고 있는 키워드라면 Reserve Word는 미래에, 즉 다음 ECMA Script 버젼에 사용될 확율이 높아 사용하지 않는게 좋은 키워드들 이다. 이 또한 변수 이름이나 함수 이름에 사용하지 말도록 하자. Reserve word 같은 경우에는 변수/함수 이름에 사용하는거에 제약이 있으나, property 이름에 사용하는데는 제약이 없다. 하지만 추후 코드 관리를 위해서 사용을 최대한 피하도록 하자

    
    //Non-Strict 모드(일반 모드)에서도 사용시 에러를 보게되는 키워드들
    class
    enum
    extends
    super
    const
    export
    import
    
    //Strict 모드에서 사용이 제한되는 키워드들
    implements
    package 
    public
    interface
    private
    static
    let
    protected
    yield
    
    

    2015년 1월 22일 목요일

    [JavaScript] Strict Mode를 사용해야 하는 이유

    JavaScript 의 모체인 ECMAScript 는 C와 C를 이은 언어들, JAVA, C++ 등의 문법적인 요소들을 많이 이어 받아 비슷한 점들이 매우 많다. 하지만 그와 다른점이 있다면 몇몇 문법적인 요소들을 사용자의 자유에 맞기고 그리 철저하게 강요하지 않는다는건데, 만약 제대로된 문법을 지키지 않고, 단지 에러가 나지 않는다는 이유로 엉망진창인 프로그래밍하게되면 ECMAScript Core 가 새 버젼으로 바뀌게 될 경우에 큰 문제를 마주치게 될 수도 있다.

    ECMA 스크립트는 버젼이 바뀌면서 새로운 기능들과 요소들을 추가하게 되는데 만약 당신이 이러한 요소들을을 고려하지 않고 미래에 쓰일 Identifier들이나 키워드들을 지금 당장의 편의를 위해서 사용해버리면 추후에 많은 에러를 양산하게 될 수도 있고 결국 이는 모든 코드의 재 검사, 재 작성으로 이어지게 된다.

    또한, 웹브라우져들은 각각 다른 내장 자바스크립트 엔진을 사용하는데
    Mozila Firefox = SpiderMonkey
    Google Chrome = V8
    Internet Explorer = Chakra
    이런 엔진에 따라 인터넷 익스플로러에서 작동하는 코드가 다른 브라우져에서 작동하지 않는 경우가 발생할 수도 있다. 문제는 개발환경이 매우 다양한 자바스크립트 개발과정에서 이러한 기준을 정한채 개발하는게 초보 개발자들에게는 어렵다는건데,

    이러한 이유에서인지 ECMAScript 5에 들어서 Strict mode 라는게 생겼다. 이 Strict Mode는 코드 컴파일시 ECMA Script의 문법 요소들과 Reserved Keyword 들의 미사용을 철저하게 강요해 일반 실행 모드보다 더 많은 예외(Exception)들을 발생시키게하여 궁극적으로는 안전한 자바스크립트 코드를 작성하는데 목적을 두고 있다.

    Strict Mode 는 아래와 같이 실행이 가능하다.

    "use strict";//이 컨텍스트에서 스트릭트 모드를 사용한다
    
    function testFunction()
    {
    
    "use strict";
    //이 컨텍스트에서 스트릭트 모드를 사용한다. 후에 이 function 실행이 종료되면 strict mode도 종료된다.
    
    alert("STRICT MODE");
    
    }
    
    
    아래는 브라우져들의 Strict Mode를 지원 현황이다.  초록색으로 표시된 버젼들이 모두 지원하는 버젼들이니, 거의 대부분의 브라우져들이 지원한다고 보면 된다. 클릭하면 크게 볼 수 있다

    출처: http://caniuse.com/#search=strict%20mode


    Strict Mode는 거의 대부분의 브라우져들이 지원하니 코드 작성시에 strict mode 를 사용해서 안전한 자바스크립트 코드를 작성하자.

    2015년 1월 19일 월요일

    [JavaScript] HTML의 Script 태그, 그리고 Async와 Defer 속성

    부제 : Script 태그의 Async 와 Defer 속성

    HTML 파일에 자바스크립트를 삽입하는 유일한 방법은 아래와 같이 HTML의 스크립트 태그를 이용하는거다. 자바스크립트를 시작하기 전에 Script 태그에 대해서 좀 자세하게 다뤄볼까 한다.

    우선 Script 태그는 아래와 같이 사용된다

    <html>
    <head>
    <script>
    alert("Script Tag");
    </script>
    </head>
    <body>
    This is Body
    Body End
    <script src = "www.example.com/js/script.js"></script>
    </body>
    </html>

    위와 같이 Script 태그는 어디든지 배치 될 수 있으며 위에서 아래로 HTML 문서를 읽는 브라우져들의 특성상, head 태그에 외부 스크립트가 배치 될 경우에는 페이지 렌더링(rendering)이 시작되기 전에 head 태그에 배치된 스크립트가 다운로드되고, 파싱(Parsing)되고 실행되게 된다. 만약 상당히 큰 스크립트 파일을 head 태그에 배치하게 될 경우에, body 렌더링이 시작되기전에 스크립트를 실행하는데 많은 시간을 할애 할 수 있다. 하지만 body 태그의 마지막에 스크립트 태그를 배치하게 되면, html 페이지의 body 내용이 다 렌더링(rendering)된 후에으로써 스크립트를 다운받기 시작하니 사용자 입장에서 보이는 페이지 로딩시간을 줄일 수 있다.

    주의할 점
    위에서 아래로 읽히는 HTML 문서의 특성상 스크립트 태그 안에 "</script>", 스크립트 엔드 태그가 존재할 경우에 태그를 닫게 된다. 아래 예제를 보자

    <html>
    <head>
    <script>
    var a = "</script> end tag test";//스크립트가 여기서 끝나게 되버려 alert 가 실행되지 않는다
    alert(a);
    </script>
    </head>
    <body>
    This is Body
    <script>
    var t = "<\/script>";// '/'(Slash)를 표시하는 escaped character 인 '\/'를 이용하자
    alert(t);
    </script>
    </body>
    </html>
    

    위와 같이 자바스크립트에서 스크립트 언어에 사용되는 기호들을 String 값으로 표현할 때, Escape Character 를 이용하여 표시한다. Slash(/) 를 표시하는 기호인 '\/'를 이용해서 "</script>"를 스트링값으로 저장할 수 있다.

    Script 태그의 Attribute

    Script 태그는 총 5개의 Attribute 를 가진다. 필수적인 Attribute 은 가지지 않는다

    • async
      • 외부 스크립트의 다운로드가  페이지 파싱이나 다른 스크립트 다운로드 프로세스와 동시에 진행된다. 그리고 스크립트 다운로드가 완료되는 즉시 바로 실행된다
    • charset
      • UTF-8, euc-kr 과 같은 스크립트의 Character set를 지정한다
    • defer
      • 외부 스크립트의 다운로드가  페이지 파싱이나 다른 스크립트 다운로드 프로세스와 동시에 진행된다. HTML 페이지 파싱이 완료된 후에서야 스크립트가 실행된다
    • src
      • 외부 스크립트를 다운로드할 주소
    • type
      • 스크립트의 종류
      • javascript 의 경우에는 type = "text/javascript"로 적는다.

    async 속성과 defer 속성

    위에 잠시 이야기했듯이, 기본적으로 웹 브라우져는 html 코드를 위에서 아래로 파싱(Parsing)한다. 이 때문에 큰 스크립트 파일같은 경우에, 그 배치 위치에 따라 사용자 입장에서의 페이지 로딩 타임이 길어질 수도, 짧아질 수도 있는데, 이를 조정하기 위해서 나온게 async 와 defer 속성이다.

    아래와 같이 쓰인다

    <html>
    <head>
    <script async src = "www.example.com/js/script.js"></script>
    <script defer src = "www.example.com/js/script.js"></script>
    </head>
    <body>
    This is Body
    Body End
    </body>
    </html>


    Script 태그 async 속성과 defer 속성
    Script 태그 async 속성과 defer 속성

    위의 이미지를 보자

    일반적인 스크립트 태그 같은 경우에는  html 파싱(Parsing) 중, 스크립트 태그를 읽게 되면 잠시 파싱을 멈추고 스크립트를 다운받아 실행한 후에 다시 파싱 작업을 이어간다. 이 경우에, html 태그의  앞부분에 스크립트 태그를 배치하게되면(특히나 헤드 태그 내에) 페이지 렌더링이 시작되기도 전에(페이지 렌더링은 body 태그의 시작과 함께 시작된다) 스크립트를 다운로드하고 실행하는데 시간을 할애하게 된다. 사용자의 입장에서 생각해봤을 때, 당신의 웹 페이지를 보는 사용자는 스크립트가 다운로드 되는 동안 텅빈 하얀 페이지를 보고만 있어야 한다. 물론 짧은 스크립트일 때는 이 시간은 극히 짧으니 그리 신경 쓸 필요가 없다, 그렇지만 만약에 인터넷 커넥션이 느리거나 사이즈가 큰 스크립트를 다운받는다면 아마 사용자는 긴 시간동안 페이지 로딩을 기다려야 할 것이다. 이러한 문제들을 해결하기 위해서 HTML5 에 들어 async 속성과 defer 속성이 추가되었다

    Async 속성을 가진 스크립트 태그 같은 경우에는 HTML 파싱과 동시에 스크립트 다운로드가 진행된다. 그리고 스크립트 다운로드가 완료되는 순간 HTML 파싱을 잠시 멈추고 스크립트를 실행한다. 이러한 특성 때문에 순서대로 다운로드가 시작된 스크립트라도 순서대로 실행되지는 않는다. 아래 예제를 보자

    <html>
    <head>
    <script async src = "www.example.com/js/script1.js"></script>
    <script async src = "www.example.com/js/script2.js"></script>
    //script2가 script1 보다 먼져 실행될 수도 있다.
    </head>
    <body>
    This is Body
    Body End
    </body>
    </html>

    이러한 이유로 DOM(Document Object Model)을 수정하는 스크립트 같은 경우에는 async 속성을 사용하지 않는게 좋다.

    Defer 속성을 가진 스크립트 태그 같은 경우에는 HTML 파싱과 동시에 스크립트 다운로드가 진행된다. 그러나 async 속성과는 달리 HTML 파싱이 완료된(</html> 태그를 읽은 후) 후에야 스크립트가 실행된다.  아래의 예제를 보자

    <html>
    <head>
    <script defer src = "www.example.com/js/script1.js"></script>
    <script defer src = "www.example.com/js/script2.js"></script>
    //script1가 script2 보다 먼져 실행된다
    </head>
    <body>
    This is Body
    Body End
    </body>
    </html>

    스크립트 태그가 헤드 태그 내에 위치해 있으나 HTML 파싱을 멈추지 않고 바로 다운로드가 진행된다. 그리고 </html> 엔드 태그를 읽은 후에야 스크립트를 실행하게 된다. 그리고 async 태그와는 달리 스크립트는 HTML 문서 내에 위치한 순서대로 실행 된다. 그러니 위의 예제에서는 html 문서 파싱이 완료된 후에 script1.js 가 실행되고 그 후에야 script2.js 가 실행된다.

    async 속성이나 defer 속성이든 둘다 외부 스크립트 파일에만 적용이 가능한 속성이니 내부 스크립트에 쓰는 일은 없도록 하자

    noscript 태그

    요즘은 자바 스크립트를 지원하지 않는 웹 브라우져를 찾을 수가 없지만, 초기에만 해도 자바스크립트가 지원되지 않던 브라우져들이 존재 했었다. 그럴 경우를 위해서 나온게 바로 noscript 태그 이다. 사용법은 간단하다. 

    <html>
    <head>
    <title>NOSCRIPT TAG EXAMPLE</title>
    </head>
    <body>
    <script src = "www.example.com/script.js"></script>
    <noscript>
    <h1>자바스크립트 기능을 활성화 해 주세요</h1>
    </noscript>
    </body>
    </html>
    
    

    만약 자바스크립트 실행이 비활성화 되있다면(또는 자바스크립트 기능이 없거나) noscript 태그 내의 html이 파싱된다. 웹브라우져 개발자 도구를 들어가서 자바스크립트를 비활성화 시킨 다면 "자바스크립트 기능을 활성화 해 주세요" 구문을 보게 될 것이다

    2015년 1월 12일 월요일

    [JavaScript] 자바스크립트란 무엇인가?

    부제 : ECMAScript와 자바스크립트


    비공식 자바스크립트(Javascript) 로고


    자바스크립트(Javascript)는 1995년 넷스케이프(Netscape) 웹 브라우져에서 웹페이지에 동적인 요소를 구현하기 위해서 발명 되었다. 그 후 많은 다른 웹 브라우져들 또한 이 언어를 탑재하기 시작했고, 그 결과로 현대의 웹 어플리케이션의 구현을 가능하게 만든 언어이다. 이 언어로 인해 웹 어플리케이션에서 더 이상 사용자가 페이지 새로고침 또는 페이지를 새로 불러오지 않고도 웹과 직접적인 연결이 가능하게 되었다.


    우선 자바스크립트(Javascript)를 시작하기 전에 처음 알아야 할 것은 이 자바스크립트(Javascript)라는 언어는 Sun System이 개발하여 지금은 Oracle에서 관리되고있는 자바(Java)라는 프로그래밍 언어와는 전혀 관계가 없다는 것이다. 둘다 자바(Java) 라는 단어를 이름에 가지고 있으니 비슷해 보일 수도 있겠지만, 전혀 그렇지 않다. 몇몇 소스들에 따르면 이 자바스크립트(Javascript)라는 이름은 자바(Java)의 유명세를 등에 업기 위해서 이리 이름 지어졌다고도 한다. 자바스크립트(Javascript)가 처음 나왔을 때는 1995년, 바로 자바(Java)라는 프로그래밍 언어가 유명세를 타며 세상을 휩쓸고 있을 때였다. 아마 이 유명세를 등에 업으려 그렇게 한게 아닐까?


    어쨋든, 자바스크립트(Javascript)가 넷스케이프(Netscape) 브라우져만이 아니라 다른 웹 브라우져들의 지원까지 받기 시작하면서 다양한 웹 브라우져에서 자바스크립트(Javascript)가 공통되게 잘 작동하기 위해서 표준 규격이 필요해졌는데, 이 때문에, ECMA 국제 기구에서 "ECMAScript Standard"라 불리는 스크립트 표준이 만들어지게 된다. 자바스크립트와 비슷한 뜻으로 많이 들어본 사람들이 있을텐데, Javascript는 ECMAScript와 BOM(Browser Object Model) 와 DOM(Document Object Model)이라는 1개의 코어와, 2개의 모델로 이루어져 있다. ECMAScript 와 Javascript 는 비슷한 뜻으로 자주 쓰이나 작은 차이를 가지고 있다는 걸 알아두자.

    앞서 말했듯 흔히 우리가 자바스크립트(Javascript)라 부르는 것은 정확히 말하면 3가지가 합쳐서 만들어진것인데 그것들은 바로 ECMAScript 와 DOM(Document Object Model) 와 BOM(Browser Object Model) 이다.

    ECMAScript는 자바 스크립트를 이루는 코어(Core) 스크립트 언어로, 웹 환경에서만 호스트 되는 언어가 아니다. 웹 환경은 ECMA 스크립트가 호스트되는 환경들 중 하나일 뿐이다. EMCA 스크립트 호스트 환경은 ECMA 스크립트 실행 환경이 구현되있고, 각각 그 환경에 알맞는 확장성을 가지고 있다. 예를들어 웹 브라우져 환경에서는 BOM(Browser Object Model)과 DOM(Document Object Model)이 그 확장성이 되겠다. 이러한 확장성들은 EMCA 스크립트의 문법과 기능에 맞춰 기능의 확장을 가능게 한다. 자바스크립트의 document 객체가 좋은 예이다. 다른 호스트 환경으로는 node.js, Adobe Flash, MongoDB, CouchDB  등이 있다

    ECMA 스크립트는 기본적으로 언어의
    • 문법(Syntax)
    • 데이터 타입(Type)
    • 구문(조건문, 반복문 등)(Statement)
    • 키워드(Keyword)
    • 예정 키워드(Reserved Word)
    • 연산자(Operator)
    • 객체(Object)
    등을 규정짓는다. 이는 어떤 ECMA 스크립트 호스트 환경에서든 동일하다.

    자바스크립트(Javascript)의 코어 스크립트인 ECMAScript 에는 몇가지 버젼들이 있는데, 2000년부터 2010년까지는 "ECMAScript 버젼 3"이 가장 대중적으로 지원되었다. 그리고 이 동안 언어에 근본적인 변화, 발전, 그리고 확장을 꾀한다는 야심을 가지고 "ECMAScript 버젼 4"의 개발이 진행되었다. 매우 대중적으로 쓰이고, 거의 모든 웹에서 쓰이는 언어를 바꾼다는게 쉽지는 않았는지, 원래 2008년 발표로 계획되었던 "ECMAScript 버젼 4"는 2008년에 엎어져 버렸고(ECMAScript Harmony(버젼 6)라는 다른 프로젝트로 이름을 바꿨다, 현재 진행 중), "ECMAScript 버젼 5"라는 이름으로 원래 계획된 거에는 미치지 못하지만 그래도 작은 발전을 가진 다섯번째 ECMAScript 에디션이 발표되었다. 참고로 내가 앞으로 포스트 할 자바스크립트가 바로 요즘 잘 쓰이고 있는 "ECMAScript 버젼 5"이다. 현재 "ECMAScript 버젼 6", 즉 버젼 4에서 엎어졌던 기능들을 이어가는 "ECMAScript Harmony" 프로젝트가 거의 완성단계에 있으며, 몇몇 웹 브라우져들은 미리 발표된 기능들을 지원하기도 한다.  어쨋든  "ECMAScript 버젼 6"은  2015년 6월 발표를 앞두고 계속 개발되고 있는 중이다.

    이 ECMAScript 언어는 다른 언어에 비해 매우 높은 자유도를 가졌는데. 이는 왜냐하면 초기 자바스크립트(Javascript)가 초심자들의 접근을 용이하게, 더 쉽게 하는데 목적을 두고 개발된 언어이기 때문이다. 하지만 실제 개발 상황에서는, 시스템이 문제가 뭔지 제대로 알려주지 않아 개발을 더 어렵게 만들기도 한다. 그렇지만 이런 자유도에 따라오는 몇가지 장점들이 있는데, 그건 바로 자유도가 낮은 다른 프로그래밍 언어들이 구현하기 거의 불가능한 기능들을 자바스크립트(Javascript)로 구현할 수 있다는것이다. 이러한 이유에서 ECMA 스크립트는 몇년전 부터 소프트웨어 산업에서 많은 관심을 받고 있다.