[JavaScript] 함수지향

이예지·2023년 9월 18일

JavaScript

목록 보기
3/4

✅ 전역변수와 지역변수

전역변수와 지역변수가 왜 중요한가?

모듈화의 근간이 되기 때문이다. 프로그램을 개발할 때 다양한 사람이 함께 협업하다보면 변수명, 변수의 사용범위 등이 충돌할 수 있기 때문에 변수의 유효범위(scope)에 신경써야한다.

유효범위(Scope)는 변수의 수명을 의미한다.

var vscope = 'global';
function fscope(){
    alert(vscope);
}
fscope();

🆚 전역변수 vs 지역변수

전역변수와 지역변수 중 어떤 변수를 사용하는 것이 좋을까?
프로그래밍 = 작은 것에서 큰 것으로, 간단한 것에서 복잡한 것으로 발전하기 때문에 그 과정에서 생겨나는 변수는 지역변수를 사용하는 것이 좋다. 전역변수를 쓰게 되면 의미가 달라지거나, 의도대로 사용되지 않는 경우가 생길 수 있어 꼭 전역변수를 써야하는 상황이 아니라면 지역변수를 쓰도록 하자.


💡 전역변수의 활용

전역변수는 '디렉토리'의 역할을 해주기도 한다.
여러 파일을 관리하면서, 같은 이름의 파일들은 기존의 파일을 덮어쓰게 되는 문제가 생겨 대부분의 프로그램에서 이런 문제점을 해결하기 위해 여러 방법을 고안했다. 그 중 하나가 전역변수와 지역변수, 그리고 객체라고 할 수 있다.

전역변수가 디렉토리처럼 사용되는 예제를 확인해보자.

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 object 로써의 함수의 사용

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]

객체.내장메소드() 형태에서 괄호 안, 즉 함수의 인자로 또다른 함수를 부르는 것을 콜백이라고 한다.


✅ 클로저 (closure)

💡 내부함수와 외부함수

function outter(){
    var title = 'coding everybody';  
    function inner(){        
        alert(title);
    }
    inner();
}
outter();

여기서 outter라는 외부함수 안에 있는 inner 내부함수에서는 외부함수에서 정의한 지역변수(이 예제에서 title)에 접근할 수 있다.

💡 private variable

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이다.
규모가 큰 프로그램을 짤 때 변수 사용을 용이하게 하기 위해 사용되는 방법이기도 하다.


✅ arguments

자바스크립트에서는 인자의 개수를 많이, 혹은 적게 작성해도 에러를 내지 않는다.

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

0개의 댓글