컴퓨터 공학/프로그래밍 과외 기록

[자바스크립트 과외] 8. Day3 요점정리

ITISIK 2021. 7. 11. 00:17
반응형


[프로그램의 실행과 평가과정]

실행 가능한 코드는 크게 세 가지로 나뉘며, 이들 코드는 평가 후, 적절한 실행문맥(E.C.)을 형성하게 된다.
실행문맥의 구조를 그림으로 그리면 아래와 같다.

위와 같은 실행문맥은, Stack이라는 가상의 자료구조로 관리가 되며, Stack에 새로운 문맥이 들어오는 것을 push, 기존에 존재하던 문맥이 삭제되는 것을 pop이라고 한다.

스택의 가장 아랫부분에는 전역 코드를 실행하기 위한 전역 실행 문맥이 존재한다. 어떤 함수를 호출(Call)하게 되면, 그 즉시 스택에 새로운 실행 문맥이 push되며, 해당 함수의 작업을 모두 마치고 return을 하게 되면(명시되어있지 않은 경우 undefined를 반환하며 함수를 마친다.), 해당 함수에 대한 실행 문맥은 pop되어 사라지게 된다.

즉, 아래와 같이 Call Stack에 in() 함수에 대한 실행 문맥까지 존재한다는 의미는, 아직 in() 함수의 호출에 대한 return이 되지 않았다는 의미이므로, in() 함수 내부의 console.log(x, y, tmp);이 실행되기 직전의 순간에 머물러 있는 상태의 Call Stack이라고 할 수 있다. 만약 in() 함수 내부의 모든 코드가 실행되었다면, Call Stack에서 in() 함수에 대한 실행 문맥(E.C.)는 pop되어 사라져 있을 것이다.

위 사진의 Call Stack과 같이 논리적인 연결고리를 일컫어, 스코프 체인 또는 유효 범위 체인이라고 부른다. 이러한 체인은 기본적으로 가장 내부에 있는 변수부터 참조하려 하고, 해당하는 식별자가 없는 경우에는 외부 렉시컬 환경 참조에 의해 참조 되어 있는 상위 실행 문맥(E.C.)에서 찾으려 한다. 이렇게 타고 타고 올라가다가, 전역 실행 문맥(E.C.)에서조차 찾지 못하게 되면 참조에러를 반환하며 프로그램을 끝마치게 된다.


[가비지 컬렉터]

작성된 프로그램을 실행하다보면, 더 이상 사용(참조)하지 않는 메모리 공간이 생기게 마련인데, 이렇게 낭비되고 있는 메모리 영역은 가비지 컬렉터가 자동으로 해제(free)시킨다. 최근의 주요 웹 브라우저에서는 마크 앤 스윕(Mark-and-Sweep) 알고리즘을 적용하여 전역 객체가 참조할 수 없는 객체를 모두 메모리에서 해제하는 방식을 취해 고립된 순환 참조 객체도 효율적으로 갈비지 컬렉션이 가능해졌다.


[클로저]

자바스크립트 함수 파트의 꽃이라고 부를 수 있으며, 클로저를 통해 변수를 은닉하고 객체를 캡슐화 시키는 것이 가능해진다. 클로저란, 어떤 함수 객체와 그 함수 객체를 감싸고 있는 렉시컬 환경 컴포넌트의 조합이라고 할 수 있다. 이러한 클로저의 실습을 위해 아래의 두 코드를 사용했다.
e.g.
function makeCounter(){
    var count = 0;
    return f;
    function f(){
        return count ++;
    }
}

var counter = makeCounter();
console.log(counter());
console.log(counter());
console.log(counter());


e.g.
function Person(name, age){
    var _name = name;
    var _age = age;
    return {
        getName : function(){ return _name; },
        getAge : function(){ return _age; },
        setAge : function( x ){ _age = x; }
    };
}
var person = Person("itisik", 28);
console.log(person.getName());
console.log(person.getAge());
person.setAge(29);
console.log(person.getAge());

이들 코드를 실습하면서 정해진 메서드를 통하지 않으면 객체의 내부에 생성된 변수에 그 어떤 방법으로도 접근할 수 없다는 사실을 알았다.

이렇게 유용한 클로저는 사실 사용자가 예상하지 못한 곳에서 일어나기도 해서 개발자를 당황하게 하기도 하는데, 아래의 두 예제가 바로 클로저를 잘못 사용한 예이다.
e.g.
var elm = document.getElementsByTagName("input");
for( var i = 0; i < elm.length; i++ ){
    elm[i].onclick = function(){
        console.log(i);
    }
}
// 내부에서 익명함수로서 정의한 함수와 그 함수를 감싸고 있는 외부인 전역 렉시컬 환경 컴포넌트를 조합으로 하는 클로저를 갖게 되어, i라는 변수가 이미 2가 된 후에 그 i값을 참조하게 되는 이상현상이 일어난다.

e.g.
for( var i = 0; i < 100; i++ ){
    setTimeout(function(){
       console.log(i);
    }, 1000 * i);
}
// setTimeout의 인수로 전달한 함수와 그 함수를 감싸고 있는 외부인 전역 렉시컬 환경 컴포넌트를 조합으로 하는 클로저를 갖게 되어, i라는 변수가 이미 100이 된 후에 그 i값을 참조하게 되는 이상현상이 일어난다.

[객체로서의 함수 / 콜백함수]

자바스크립트의 함수는, 함수가 함수의 인수로 사용될 수 있고, 함수가 함수의 반환값으로 사용될 수 있으며, 함수 객체 자체가 프로퍼티와 메서드를 가질 수 있는데 이와 같은 객체를 일급 객체라고 한다.

때문에 아래와 같이 다른 함수에 인수로 넘겨지는 콜백 함수를 구성할 수도 있다.
e.g.
function 먼저_할_일(callback_함수){
    console.log("급한 일 먼저 하겠습니다!");
    callback_함수();
}

function 먼저할일이_끝나면_할_일(){
    console.log("모든 일을 마쳤습니다!");
}

먼저_할_일(먼저할일이_끝나면_할_일);


사실 이와 같은 콜백함수는 이미 앞에서 우리도 모르게 사용한 적 있다. 바로 아래의 코드의 인수 중 첫 번째 인수가 콜백함수이다.
e.g.
setTimeout(function(){ ... }, 1000);
setInterval(function(){ ... }, 5000);

반응형