인사이드 자바스크립트를 공부하며 정리하는 포스팅입니다.



1.함수 생성


자바스크립트에서 함수를 생성하는 방법은 3가지가 있습니다

1)함수 리터럴

아래 코드에서 add에 해당하는 함수 이름은 생략 가능합니다.


function add(x, y){

return x + y;

}


2)함수 선언문

함수명이 반드시 정의되어 있어야 합니다.


function add(x, y){

return x + y;

}


3)함수 표현식(추천!! 이유는 2번 함수 호이스팅에서 설명하겠습니다.)

아래와 같이 함수에 이름을 만들지 않고 변수에 할당하는 방식을 익명 함수 표현식이라 합니다.

함수 내부에서 재귀적으로 호출할 필요가 있을 때에는 함수에 이름을 붙여주면 됩니다.

여기서 add는 함수 이름이 아닌 익명함수를 참조하는 변수입니다. //함수변수


var add = function (x, y){

return x + y;

};


함수 표현식으로 함수를 생성하는 경우에는 세미콜론을 필수로 사용해야합니다.

이유는 다음과 같은 오류가 발생할 수 있기 때문입니다.


var func = function() {
return 42;
}
(function(){
return 24;
})();


위와 같은 코드가 있을 때 func 함수 표현문 끝에 세미콜론이 없기 때문에 자바스크립트 엔진은 중괄호에서 끝났다고 인식하지 못하고 ()로 감싸진 익명함수 생성 리터럴을 무시하고 ()로 func를 실행하게됩니다.

때문에 그 뒤에 있는 ()는 func의 리턴 값인 42()와 같이 인식하게 되어 오류가 발생합니다.




2.함수 호이스팅


앞에서 함수를 생성하는 여러가지 방법에 대해서 나왔는데 이들 사이에는 동작 방식이 약간 차이가 있습니다.

그중의 하나가 바로 함수 호이스팅(Function Hoisting)입니다. 


add(3, 5);

function add(x, y){
return x + y;
};

add(3, 4);


맨 위에 add(3, 5); 같은 경우에는 아직 함수가 선언되지 않았는대도 불구하고 호출이 가능합니다. 

함수가 위치한 위치에 상관없이 함수 선언문 형태로 정의한 함수의 유효 범위는 코드의 맨 처음부터 시작한다. 

이것을 함수 호이스팅이라고 합니다.


함수 표현식으로 함수를 생성하면 이러한 함수 호이스팅이 일어나지 않는다. 


3.함수도 객체다.


자바스크립트에서는 함수를 일급객체라고 부른다.


1) 프로퍼티를 가질 수 있다.


2) 자바스크립트에서 함수는 값으로 취급된다.

- 리터럴에 의해 생성

- 변수나 배열의 요소, 객체의 프로퍼티 등에 할당 가능

- 함수의 인자로 전달 가능

- 함수의 리턴값으로 리턴 가능

- 동적으로 프로퍼티를 생성 및 할당 가능

*위와 같은 자바스크립트 함수의 특성들을 가지고 있는 객체를 일급객체라고 한다.


3) 함수 객체의 기본 프로퍼티

함수는 객체이므로 함수 객체만의 표준 프로퍼티가 정의되어 있습니다.

대표적으로 arguments, caller, length, name, apply, call, bind이 있습니다.

이들 프로퍼티들은 Function.prototype 객체로 부터 받은 것입니다.


- arguemnts

함수로 전달된 인자값들

- length

인자의 수

- caller

자신을 호출한 함수

- name

함수의 이름

- prototype

prototype 프로퍼티는 _proto_와 다릅니다.

* _proto_ : 자신의 부모 역할을 하는 프로토타입 객체를 가리킨다.


prototype 프로퍼티는 함수가 생성될 때 만들어지며 단지 constructor 프로퍼티 하나만 있는 객체를 가리킵니다.

그리고 prototype 프로퍼티가 가리키는 프로토타입 객체의 constructor 프로퍼티는 자신과 연결된 함수를 가리킵니다.


즉, 자바스크립트에서는 함수를 생성할 때, 함수 자신과 연결된 프로토타입 객체를 동시에 생성하며

이 둘은 prototype 과 constructor라는 프로퍼티로 서로를 가리킵니다.




그러니까 예를들어 func 함수는 생성될 때 프로토타입 객체가 동시에 생성되고 이 객체를 prototype 프로퍼티로 참조합니다. 이 프로토타입 객체는 constructor라는 프로퍼티를 가지고 있고, 이 또한 객체이므로 _proto_ 프로퍼티도 가지고 있습니다.




prototype 프로퍼티가 가리키고 있는 func의 프로토타입객체는 constructor 프로퍼티로 func 함수를 가리킵니다.




이해하기 힘든 개념일 수 있습니다. 이후 프로토타입과 프로토타입 체이닝에 대해서 자세히 포스팅할 예정이니 이정도 책 내용 정도로만 이해하시고 넘어가시면 될 것 같습니다.



4.함수의 다양한 형태


1) 콜백함수

함수를 명시적으로 호출하는 것이 아니라 개발자는 함수를 등록하고, 특정 이벤트가 발생하거나 특정 시점에 도달하였을 때 시스템에서 호출하는 함수를 말합니다.


대표적인 콜백 함수의 사용 예가 자바스크립트에서의 이벤트 핸들러 처리입니다. 웹페이지가 로드 되거나, 키보드 입력되는 등 DOM이벤트가 발생할 경우 브라우저는 정의된 DOM 이벤트에 해당하는 이벤트 핸들러를 실행시킵니다. 개발자가 만약 해당하는 이벤트 핸들러에 콜백 함수를 등록했다면 이벤트가 발생할 때마다 브라우저에 의해 실행되게 됩니다.



2) 즉시 실행 함수

함수를 정의함과 동시에 바로 실행하는 함수를 즉시 실행 함수(immediate functions)라 합니다.

함수가 선언되자마자 실행되게 만든 즉시 실행 함수의 경우 같은 함수를 다시 호출할 수 없습니다. 따라서 최초 한 번의 실행만을 필요로 하는 초기화 코드에 사용할 수 있습니다.

예를 들어 아래와 같은 형태로 사용하실 수 있습니다.

(function(name){
//initialize 함수
console.log("Init");
InitFrame();
InitModel();
InitMain();
user.name = name;
})("song");

그리고 jQuery와 같은 자바스크립트 라이브러리나 프레임워크 소스들에서 사용되니 알아두면 좋습니다.

jQuery에서 즉시 실행 함수를 사용하는 이유는 함수 유효 범위 때문입니다.

*자바스크립트에서 변수는 전역 유효 범위를 가진다. 그러나 함수 내부의 변수(var)는 함수 유효 범위를 가진다.



따라서 라이브러리 코드를 즉시 실행 함수 내부에 정의해두면, 라이브러리 내의 변수들에 외부에서 접근할 수 없습니다. 따라서 즉시 실행 함수 내에 라이브러리 코드를 추가하면 전역 네임스페이스를 더럽히지 않고, 다른 라이브러리들이 동시에 로드 되더라도 라이브러리간 변수 이름 충돌을 방지할 수 있습니다.

3) 내부 함수

함수 내부에 정의된 함수를 내부 함수라고 부릅니다. 내부 함수는 클로저를 생성하거나 부모 함수 코드에서 외부에서의 접근을 막고 독립적인 헬퍼 함수를 구현하는 용도로 사용합니다.


내부 함수의 특징은 다음과 같습니다.

- 내부 함수에서는 자신을 둘러싼 부모 함수의 변수에 접근이 가능하다.

C++과 같은 언어를 사용하셨던 분들은 낯설게 느끼실 수 있습니다. 이러한 것이 가능한 이유는 자바스크립트의 스코프 체이닝 때문입니다.  


*클로저, 스코프 체이닝은 따로 포스팅하겠습니다. ^^



- 내부 함수는 일반적으로 자신이 정의된 부모 함수 내부에서만 호출이 가능하다.


5. 함수 리턴


1) 일반 함수나 메서드는 리턴값을 지정하지 않을 경우, undefined 값이 리턴된다.

2) 생성자 함수에서 리턴값을 지정하지 않을 경우 생성된 객체가 리턴된다.

3) 생성자 함수에서 리턴값을 명시적으로 특정 객체로 지정한 경우 지정된 객체가 리턴된다.

그러나 만약 객체가 아닌 value값을 리턴 하려한다면 무시하고 this로 바인딩된 객체가 리턴됩니다.


다음번 포스팅은 함수와 this에 대한 내용입니다.



인사이드 자바스크립트를 공부하며 정리하는 포스팅입니다.



참조 타입(객체)


자바스크립트에서 기본 타입을 제외한 모든 값은 객체다.

따라서 배열, 함수, 정규표현식 등도 결국 자바스크립트 객체로 표현된다.

자바스크립트에서 객체는 단순 key : value 형태의 프로퍼티들을 저장하는 컨터이너로써, Hash와 유사하다. 
프로퍼티에는 기본 타입, 참조 타입(객체), 함수등 모든 타입을 포함할 수 있다.



1. 객체 프로퍼티 접근


객체 프로퍼티를 읽고, 쓰고, 갱신하기 위해 접근하는 방법은 두 가지가 있습니다.


- 대괄호([]) 표기법

- 마침표(.) 표기법


일반적으로는 C++, Java등의 언어와 유사하게 마침표 표기법을 많이 사용하지만 대괄호 표기법만을 사용해야하는 경우가 있습니다.

1) 프로퍼티 이름이 표현식인 경우 // foo['full-name'] = 'foo song';

2) 프로퍼티 이름이 예약어인 경우 




2. for in 문


for in 문을 사용하면, 객체에 포함된 모든 프로퍼티에 대해 루프를 수행할 수 있습니다.

var objA = {

val : 40

};



var objB = objA;



console.log(objA.val); // 40

console.log(objB.val); // 40



objB.val = 50;



console.log(objA.val); // 50

console.log(objB.val); // 50
for in 문을 수행하면서 변수에 객체의 프로퍼티가 하나씩 String 타입으로 할당됩니다.



3. 객체 프로퍼티 삭제


자바스크립트에서는 객체의 프로퍼티를 delete 연산자를 이용해 즉시 삭제할 수 있습니다.


delete foo.name;


4. 참조 타입의 특성


자바스크립트에서 객체는 참조 타입입니다. 

말그대로 객체의 모든 연산이 실제 값이 아닌 참조값으로 처리되기 때문입니다.

var objA = {

val : 40

};



var objB = objA;



console.log(objA.val); // 40

console.log(objB.val); // 40



objB.val = 50;



console.log(objA.val); // 50

console.log(objB.val); // 50

objB의 프로퍼티를 수정해도 objA의 프로퍼티가 같이 수정됩니다. 따라서 두 객체는 같은 객체를 가리키고 있다는 것을 알 수 있습니다.


var objA = {}; 


위와 같이 객체를 생성되면 objA 자체의 값이 객체인 것이 아니라 생성된 객체를 가리키는 참조값을 저장하고 있는 것입니다.

 

객체비교도 마찬가지 입니다.

var objA = {

val : 40

};



var objB = {

val : 40

};



var objC = objB;



console.log(objA == objB); // false

console.log(objB == objC); // true

변수는 객체의 값이 아닌 객체의 참조값을 가지고 있기 때문에 모든 값이 동일한 objA와 objB는 다른 객체이고, 참조값이 같은 objB와 objC는 같습니다.


* 다음 포스팅에 깊은복사와 객체간 값 비교를 통해 비교하는 함수를 만들어 보도록 하겠습니다. 



4. 참조에 의한 호출 방식 (call by reference)


기본 타입과 참조 타입의 경우는 함수 호출 방식도 다릅니다. 기본 타입의 경우는 call by value/ 참조 타입은 call by reference 입니다.


call by value: 함수를 호출할 때 인자로 복사된 값을 전달한다. 즉, 함수내에서 매개변수의 값을 변경해도 실제 값은 변경되지 않는다.

call by reference: 함수를 호출할 때 인자로 객체의 참조값이 전달된다. 즉, 함수내에서 매개변수의 값을 변경하면 실제 값이 변경된다.


위에서 4. 참조 타입의 특성으로 보면 알 수 있듯이 참조 타입은 값 자체가 아닌 가리키고 있는 참조값입니다. 때문에 함수 내에서 인자로 받은 객체의 프로퍼티를 수정하면 원본 객체의 프로퍼티가 수정됩니다.


c++을 하셨던 분들은 포인터를 생각하시면 이해가 빠를듯 합니다. 변수에 할당된 것은 값이 아니고 주소이고, 그 주소에 있는 값을 변경하는 것이라고 생각하시면 됩니다.



5. 프로토타입


자바스크립트의 모든 객체는 자신의 부모 역할을 하는 객체와 연결되어 있습니다. 마치 객체지향의 상속과 유사하게 부모 객체의 프로퍼티를 자신의 것처럼 사용할 수 있습니다. 자바스크립트에서는 이러한 부모 객체를 프로토타입이라고 부릅니다. 


ECMAScript 명세서에는 자바스크립트의 모든 객체는 자신의 프로토타입을 가르키는 [[Prototype]]이라는 숨겨진 프로퍼티를 가진다고 설명합니다. 이를 크롬 브라우저에서는 _proto_라 되어있습니다.



foo 객체의 프로토타입 객체는 Object.prototype 객체입니다. (객체의 최상위 프로토타입) 따라서 foo 객체는 Object.prototype에 정의된 프로퍼티들을 사용할 수 있습니다.


자바스크립트에서 굉장히 중요한 개념입니다. 이후에 따로 프로토타입, 프로토타입 체이닝, 상속에 관하여 심도있게 포스팅을 작성해볼 예정입니다^^.