전역변수와 지역변수가 왜 중요한가?
모듈화의 근간이 되기 때문이다. 프로그램을 개발할 때 다양한 사람이 함께 협업하다보면 변수명, 변수의 사용범위 등이 충돌할 수 있기 때문에 변수의 유효범위(scope)에 신경써야한다.
유효범위(Scope)는 변수의 수명을 의미한다.
var vscope = 'global';
function fscope(){
alert(vscope);
}
fscope();
전역변수와 지역변수 중 어떤 변수를 사용하는 것이 좋을까?
프로그래밍 = 작은 것에서 큰 것으로, 간단한 것에서 복잡한 것으로 발전하기 때문에 그 과정에서 생겨나는 변수는 지역변수를 사용하는 것이 좋다. 전역변수를 쓰게 되면 의미가 달라지거나, 의도대로 사용되지 않는 경우가 생길 수 있어 꼭 전역변수를 써야하는 상황이 아니라면 지역변수를 쓰도록 하자.
전역변수는 '디렉토리'의 역할을 해주기도 한다.
여러 파일을 관리하면서, 같은 이름의 파일들은 기존의 파일을 덮어쓰게 되는 문제가 생겨 대부분의 프로그램에서 이런 문제점을 해결하기 위해 여러 방법을 고안했다. 그 중 하나가 전역변수와 지역변수, 그리고 객체라고 할 수 있다.
전역변수가 디렉토리처럼 사용되는 예제를 확인해보자.
MYAPP = {}
MYAPP.calculator = {
'left' : null,
'right' : null
}
MYAPP.coordinate = {
'left' : null,
'right' : null
}
MYAPP.calculator.left = 10;
MYAPP.calculator.right = 20;
function sum(){
return MYAPP.calculator.left + MYAPP.calculator.right;
}
document.write(sum());
이때 MYAPP은 전역변수로써 하나의 디렉토리 역할을 하는 것이며, 이 안에서 calculator와 coordinate라는 디렉토리를 하나 더 만들어 그 안에서 지역변수를 사용할 수 있게 되는 것이다. 이러한 방식은 같은 이름의 변수들을 헷갈리지 않고 관리할 수 있도록 해주는 이점이 있다.
(function(){
var MYAPP = {}
MYAPP.calculator = {
'left' : null,
'right' : null
}
MYAPP.coordinate = {
'left' : null,
'right' : null
}
MYAPP.calculator.left = 10;
MYAPP.calculator.right = 20;
function sum(){
return MYAPP.calculator.left + MYAPP.calculator.right;
}
document.write(sum());
}())
전역변수를 사용하고 싶지 않다면 위와 같이 익명함수를 사용하여 호출하지 않아도 실행되도록 작성할 수 있다.
다른 언어에서는 {} 블록 단위로 변수의 유효범위가 정해진다.
예를 들어 자바는
for(int i = 0; i < 10; i++){
String name = "egoing";
}
System.out.println(name);
이때 name이 for문의 {}블록 안에 정의되어 있기 때문에 블록 밖에서 name을 호출하면 에러를 발생시킨다.
그러나, 자바스크립트에서는 함수 외에 다른 블록 안에서 정의한 변수는 블록 밖에서도 사용할 수 있는 특징이 있다.
for(var i = 0; i < 1; i++){
var name = 'coding everybody';
}
alert(name);
이렇게 for문 안에서 선언한 변수를 for문 밖에서 사용할 수 있다.
자바스크립트에서 함수는 값, 즉 객체이다.
따라서 함수를 아래와 같이 두가지 방법으로 표현할 수 있다.
function a (){}
===
var a = function() {}
객체로 나타낸 함수는 다음과 같다.
a {
b: function() {}
}
이 때, 객체의 속성(key)의 value로 나타난 함수를 메소드(method)라고 한다.
first-class란 다양하게 사용되는 것에 붙는 이름이다.
함수는 값이기 때문에 함수의 매개변수로 다른 함수를 부를 수 있다.
function cal(func, num){
retrun func(num);
}
리턴값으로 사용되는 함수
function cal(mode){
var funcs = {
'plus' : function(left, right){return left + right},
'minus' : function(left, right){return left - right}
}
return funcs[mode];
}
alert(cal('plus')(2,1));
alert(cal('minus')(2,1));
배열 안에서 사용되는 함수
var process = [
function(input){ return input + 10;},
function(input){ return input * input;},
function(input){ return input / 2;}
];
var input = 1;
for(var i = 0; i < process.length; i++){
input = process[i](input);
}
alert(input);
function sortNumber(a,b){
// 위의 예제와 비교해서 a와 b의 순서를 바꾸면 정렬순서가 반대가 된다.
return b-a;
}
var numbers = [20, 10, 9,8,7,6,5,4,3,2,1];
alert(numbers.sort(sortNumber)); // array, [20,10,9,8,7,6,5,4,3,2,1]
객체.내장메소드() 형태에서 괄호 안, 즉 함수의 인자로 또다른 함수를 부르는 것을 콜백이라고 한다.
function outter(){
var title = 'coding everybody';
function inner(){
alert(title);
}
inner();
}
outter();
여기서 outter라는 외부함수 안에 있는 inner 내부함수에서는 외부함수에서 정의한 지역변수(이 예제에서 title)에 접근할 수 있다.
function factory_movie(title){
return {
get_title : function (){
return title;
},
set_title : function(_title){
title = _title
}
}
}
ghost = factory_movie('Ghost in the shell');
matrix = factory_movie('Matrix');
alert(ghost.get_title());
alert(matrix.get_title());
ghost.set_title('공각기동대');
alert(ghost.get_title());
alert(matrix.get_title());
이 예제에서 ghost는 get_title과 set_title을 속성(key)으로 갖는 객체가 되는데, 이때 value로써의 함수에서 사용되는 title은 외부함수 factory_movie의 매개변수를 의미한다. 여기서 이 title은 내부함수의 get_title, set_title을 통해서만 접근할 수 있는 private variable이다.
규모가 큰 프로그램을 짤 때 변수 사용을 용이하게 하기 위해 사용되는 방법이기도 하다.
자바스크립트에서는 인자의 개수를 많이, 혹은 적게 작성해도 에러를 내지 않는다.
function sum(){
var i, _sum = 0;
for(i = 0; i < arguments.length; i++){
document.write(i+' : '+arguments[i]+'<br />');
_sum += arguments[i];
}
return _sum;
}
document.write('result : ' + sum(1,2,3,4));
함수 sum의 지정된 매개변수는 없지만, 인자로 1,2,3,4를 주었을 때, arguments를 통해 접근할 수 있다.
함수의 정의부분에서 인자에 대한 구현이 없음에도 인자를 전달 할 수 있는 것은 왜 그럴까? 그것은 arguments라는 특수한 배열이 있기 때문이다.
arguments.length : 실제 인자로 전달된 매개변수의 수를 알 수 있다.
함수.length : 함수에서 설정한 매개변수의 수
함수의 내장메소드 .apply()를 통해 함수를 호출할 수도 있다.
function sum(arg1, arg2){
return arg1+arg2;
}
alert(sum.apply(null, [1,2]))
함수 sum은 Function 객체의 인스턴스다. 그렇기 때문에 객체 Function 의 메소드 apply를 호출 할 수 있다.
o1 = {val1:1, val2:2, val3:3}
o2 = {v1:10, v2:50, v3:100, v4:25}
function sum(){
var _sum = 0;
for(name in this){
_sum += this[name];
}
return _sum;
}
alert(sum.apply(o1)) // 6
alert(sum.apply(o2)) // 185
위 예제에서 this는 결국 함수에서 호출하는 객체 o1, o2를 가르킨다.
따라서 다음과 같다고 볼 수 있다.
o1 = {val1:1, val2:2, val3:3, sum:sum}
o2 = {v1:10, v2:50, v3:100, v4:25, sum:sum}
alert(o1.sum());
alert(o2.sum());
그런데 이때는 this에서 sum 자체 (함수 자체) 또한 취하기 때문에 해당 함수 안에 this가 function type이 아닐 때만 더한다는 조건을 부여해줘야한다.
참고
인프런-생활코딩 자바스크립트(JavaScript) 기본
https://opentutorials.org/course/743/4650