JavaScript의 함수는 일급 객체이며 private 변수 또는 메소드 뿐만 아니라
함수의 특징을 이용하여 public 속성과 메소드를 제공하며 JavaScript 모듈을 작성하는 좋은 도구이다.
또한 JavaScript의 가장 큰 문제점 중의 하나는 전역 스코프에 정의된 것은 코드 내의 어디서든지 접근 가능하다는 것이다.
이는 즉시실행함수를 통해 해결할 수 있다.
아래와 같은 조건을 충족시키는 객체만 일급 객체라 할 수 있다.
자바스크립트에서 함수를 정의하는 방법은 아래와 같이 크게 두가지로 나뉜다.
함수선언식으로 정의된 함수는 JavaScript 인터프리터가 스크립트가 로딩되는 시점에 바로 초기화하고
이를 변수 객체에 저장한다. 그렇기 때문에 함수 선언 위치와는 상관없이 소스 내 어느 곳에서든 호출이 가능하다.
// 함수선언식(function declaration)
function company() {
/* 실행코드 */
}
함수표현식으로 정의된 함수는 런타임시에 해석되고 실행이 된다.
// 기명 함수표현식(named function expression)
var company = function company() {
/* 실행코드 */
};
// 익명 함수표현식(anonymous function expression)
var company = function() {
/* 실행코드 */
};
// 기명 즉시실행함수(named immediately-invoked function expression)
(function company() {
/* 실행코드 */
}());
// 익명 즉시실행함수(immediately-invoked function expression)
// Javascript 대가이신 더글라스 클락포트의 권장 표기법
(function() {
/* 실행코드 */
}());
// 익명 즉시실행함수(immediately-invoked function expression)
(function() {
/* 실행코드 */
})();
외부에 공유되면 안되거나 공유될 필요가 없는 속성, 메소드 또는 다른 스크립트 파일 내에서
동일한 이름으로 명명된 변수나 함수가 있을 경우, 원치 않는 결과를 가져올 수 있는데
이러한 경우를 예방하고자 즉시실행함수를 사용한다.
// 함수표현식에 의한 명시적인 함수호출
var app = function() {
console.log('함수 호출'); // "함수 호출" 출력
};
app(); // "함수 호출"
함수표현식은 함수를 정의하고, 변수에 함수를 저장한 뒤 실행하는 일련의 과정을 거친다.
// 즉시실행함수
(function() {
console.log('함수 호출'); // "함수 호출" 출력
}()); // "함수 호출"
즉시실행함수는 위와 같은 과정을 거치지 않고 즉시 실행되지만 위 두개의 코드는 동일한 동작을 한다.
var app = (function() {
var privateVar = 'private';
return {
prop : privateVar
};
}());
console.log(app.prop); // "private"
위 코드는 변수를 선언하고 이 변수에 즉시실행함수를 할당한 것이다.
변수의 접근 범위가 함수 내부가 아닌 외부에서도 가능해진 것을 알 수 있다.
이와 같이, 즉시 실행함수는 변수의 스코프를 포함하는 데 사용되며 외부에서 함수 내의 변수 접근을 통제할 수 있다.
(function($) {
// 함수 스코프 내에서 $는 jQuery Object임.
console.log($);
}(jQuery));
$
를 글로벌 변수로 사용하는 라이브러리를 한개가 아닌 여러개를 같이 사용한다면 $
변수에 충돌이 생긴다.
하지만 위와 같이 파라미터를 전달하는 방법으로 $
변수에 대한 충돌을 예방할 수 있다.
이처럼 즉시실행함수는 코드 충돌 없이 구현할 수 있어 플러그인이나 라이브러리 등을 만들 때 많이 사용된다.
JavaScript는 언어 레벨에서 캡슐화를 위한 접근제어자(private, public 등), 모듈 간의 구분을 위한 패키지가 명시적으로 제공되지 않는다.
즉시실행함수는 작성한 코드 외에 함께 사용하는 외부 라이브러리와도 충돌없이 구동하는 샌드박스를 제공한다.
이 특징과 단위기능별로 작성된 코드를 분리된 개별 파일 형태로 유지한다면 앞서 언급한 모듈화를 위한 조건을 해결할 수 있다.
var clerk = (function() {
var name = 'Teo';
var sex = '남자';
var position = '수석 엔지니어';
// salary private
var salary = 2000;
var taxSalary = 200;
var totalBonus = 100;
var taxBonus = 10;
var payBonus = function() {
totalBonus = totalBonus - taxBonus;
return totalBonus;
};
var paySalary = function() {
return salary - taxSalary;
};
// Public 속성, 메소드
return {
name : name,
sex : sex,
position : position,
paySalary : paySalary,
payBonus : payBonus
};
}());
// name 속성은 public
console.log(clerk.name); // 'Teo'
// salary 변수는 즉시실행함수 내부 변수이므로 private
console.log(clerk.salary); // undefined
// paySalary 메소드는 public
console.log(clerk.paySalary()); // 1800
// payBonus 메소드는 public
console.log(clerk.payBonus()); // 90
console.log(clerk.payBonus()); // 80
즉시실행함수를 위와 같이 사용하면 언어 레벨에서 제공하지 못하는 모듈화 지원도구를 극복할 수 있으며
이렇게 작성된 코드를 분리된 파일로 구성하면 재사용성을 높일 수 있다.
// SPA 모듈 작성 순서 예시
var app = (function() {
// 1. 모듈 스코프 내에서 사용할 변수 작성
var scopeVar = {};
var utilMethod;
var manipulateDom;
var eventHandle;
var initModule;
// 2. 유틸리티 메소드 작성
utilMethod = function() {
// 실행코드
};
// 3. DOM 조작 메소드 작성
manipulateDom = function() {
// 실행코드
};
// 4. 이벤트 핸들러 작성
eventHandle = function() {
// 실행코드
};
// Public 메소드 작성
initModule = function() {
// 실행코드
};
return {
init : initModule
};
}());
아래는 라이브러리 모듈화를 위한 코딩 기법의 예시이며 크게 5가지로 나뉘어져 있다.
(function() {
'use strict';
var root = this;
var version = '1.0';
var Module1;
if(typeof exports !== 'undefined') {
Module1 = exports;
} else {
Module1 = root.Module1 = {};
}
Module1.getVersion = function() {
return version;
}
}).call(this);
console.log(Module1.getVersion());
(function(global) {
var root = global;
var version = '1.0';
var Module2;
if(typeof exports !== 'undefined') {
Module2 = exports;
} else {
Module2 = root.Module2 = {};
}
Module2.getVersion = function() {
return version;
}
}(this));
console.log(Module2.getVersion());
(function() {
var root = this;
var version = '1.0';
var Module3;
if(typeof exports !== 'undefined') {
Module3 = exports;
} else {
Module3 = root.Module3 = {};
}
Module3.getVersion = function() {
return version;
}
}());
console.log(Module3.getVersion());
/**
* Library 모듈화를 위한 코딩기법 4
* apply 함수 이용
*/
(function() {
var root = this;
var version = '1.0';
var Module4;
if(typeof exports !== 'undefined') {
Module4 = exports;
} else {
Module4 = root.Module4 = {};
}
Module4.getVersion = function() {
return version;
}
}).apply(this) ;
console.log(Module4.getVersion());
var Module5 = (function() {
var root = this;
var version = '1.0';
var Module;
if(typeof exports !== 'undefined') {
Module = exports;
} else {
Module = root.Module = {};
}
Module.getVersion = function() {
return version;
}
return Module;
}());
console.log(Module5.getVersion());
위 포스팅은 JavaScript - 함수을 보며 공부하고 정리한 내용입니다.