2014년 4월 14일 월요일

[javascript] forWD - 4장 변수, 스코프, 메모리


0. 환경

macbook-pro 13” 2012 mid / 10GB


1. 앞장 정리

변수

  1. 자바 스트립트의 변수는 느슨한 타입

    느슨한 타입

    • 한 변수에 어떤 타입이라도 저장할 수 있음
  2. 초기화 하지 않을 경우 undefined

데이터타입

  1. 원시 데이터 타입 (다섯가지의 기본 데이터 타입)
    1. undefined
    2. null
    3. boolean
    4. 숫자
    5. 문자열
  2. 객체 (복잡한 데이터 타입)
    • key - value 쌍의 순서없는 형태

자바 스크립트 데이터 타입은 동적이라서 한 가지 데이터 타입이 여러 특성을 가질 수 있음음

typeof 연산자

자바스크립트의 변수는 느슨한 타입이므로 변수의 타입을 알아야 할 때
typeof는 원시 값에 대해서는 잘 작동하지만 참조 값에서는 쓸모 없음

타입 내용
undefined 정의되지 않은 변수
boolean 불리언
string 문자열
number 숫자
object 함수를 제외한 객체 또는 null
function 함수

instanceof 연산자

// 문법
'result' = 'variable' instanceof 'constructor'

변수가 주어진 참조타입의 인스턴스일 때 true반환

  1. 인스턴스는 프로토타입 체인으로 판단함
  2. 모든 참조 값은 Object의 인스턴스

Note

  1. typeof연산자를 함수에 사용시 function 반환
  2. typeof연산자를 정규표현식에 사용시 function 반환
    • ECMA-262에서 내부에 [call]메소드를 가진 객체는 typeof에서 function를 반환해야한다고 명시했기 때문
      - 사파리5까지, 크롬7까지만 적용, firefox, IE는 object 반환

2. 변수

  1. 원시 데이터 타입
    • 변수에 저장된 실제 값을 조작
  2. 객체 타입
    • 참조 값은 메모리에 저장된 객체
    • 객체의 메모리 공간을 직접 조작할 수 없으므로 참조로 접근

동적 프로퍼티

참조 값의 경우 언제든 프로퍼티와 메소드를 추가/삭제 가능
원시 값의 경우 프로퍼티가 없지만 추가하려도 해도 오류가 발생하지는 않음

// 참조 값
var person = new Object();
person.name = "Nicholas";
console.log("person.name: " + person.name);
console.log("person.age: " + person.age);
person.age = 30;
console.log("person.age: " + person.age);

console.log("------------\n");

// 원시 값
var name = "Dec7";
console.log("name: " + name);
console.log("name.age: " + name.age);
name.age = 30;
console.log("name.age: " + name.age);

/*
* 출력 결과
**************
person.name: Nicholas
person.age: undefined
person.age: 30
------------

name: Dec7
name.age: undefined
name.age: undefined 
**************
*/

값 복사

// 원시 값
var num1 = 5
var num2 = num1

num2의 값은 복사되었고, num1의 값과 완전히 분리되어 있음
원시값 복사

// 참조 값
var obj1 = new Object();
var obj2 = obj1;

obj1.name = "Dec7";
console.log("obj2.name: " + obj2.name);

/*
* 출력결과
**************
dog.name: Dec7
**************
*/

참조 값의 경우 다른 변수에 복사할 객체 자체가 아닌 heap에 저장된 객체를 가리키는 포인터를 복사함.
복사 후 두 변수는 동일한 객체를 가리킴.
참조값복사

매개변수

원시값이든 참조값이든 모두 오직 값으로 전달.
매개변수를 값으로 전달하면 지역 변수에 저장됨.
- arguments 객체로 저장
매개변수를 참조형으로 전달하면 메모리상 주소 위치가 지역변수에 저장. 지역변수의 내용을 변경하면 함수 외부에도 반영됨.

// 매개변수가 원시 값일 때
function add(num){
    num += 10;
    return num;
}

var count = 20;
var result = add(count);
console.log("count: " + count);
console.log("result: " + result);

/*
* 출력 결과
**************
count: 20
result: 30 
**************
*/
// 매개변수가 참조 값일 때
function setName (obj) {
    obj.name = "Dec7";
    /*
    * new object
    * obj가 값이 아닌 참조 형태로 전달된다면
    * 출력결과는 Galaxy가 되어야 함
    */
    obj = new Object();
    obj.name = "Galaxy";
    /*
    * 함수 내부에서 위 obj를 덮어쓰면
    * obj는 지역 객체를 가리키는 포인터가 되고
    * 이 지역객체는 함수가 종료되는 즉시 파괴됨.
    */
}

var person = new Object();
setName(person);
console.log("person.name: " + person.name);

/*
* 출력 결과
**************
person.name: Dec7
**************
*/

함수 외부의 person이든 함수 내부의 obj모두 동일한 메모리 주소를 가리킴.
obj가 가리키는 것은 heap에 존재하는 전역객체이기 때문


3. 실행 컨택스트와 스코프

실행 컨텍스트

  • 이름
    • (변수/함수) 실행 컨텍스트(EC)
    • 짧게 컨텍스트라고 부름
  • 하는 일
    • 다른 데이터에 접근할 수 있는지 규정
    • 어떻게 행동하는지를 규정
  • 특징

    • 각 실행 컨텍스트에는 변수객체(VO)가 연결됨
    • 해당 컨텍스트에 정의된 모든 변수와 함수는 이 객체에 존재
    • 이 객체를 코드에서 직접 접근 불가
    • 이면에서 데이터를 다룰 때 이 객체를 사용
    • 실행 컨텍스트는 그것이 포함된 코드가 모두 실행되면 파괴됨
  • 종류

    1. 전역 컨텍스트

      • 가장 바깥쪽에 존재하는 실행 컨텍스트
      • 웹 브라우저에서 window라고 부름
      • 전역변수와 함수는 window객체의 property, method로 생성
      • 웹 브러우저가 닫칙 때까지 유지됨
    2. 함수 컨텍스트

      • 독자적인 실행 컨텍스트
      • 함수 호출시 생성됨
      • 실행 순서
        1. 실행시
          • 함수의 컨텍스트가 컨텍스트 스택쌓임.
        2. 종료시
          • 해당 컨텍스트를 컨텍스트 스택에서 꺼냄.
          • 컨트롤을 이전 컨텍스트로 인전
    3. eval()을 호출할 때 생성되는 세 번재 타입이 있긴함 (p117)

스코프체인

  • 컨텍스트에서 코드를 실행하면 변수객체에 스코프 체인이 형성
  • 목적
    • 실행 컨텍스트가 접근할 수 있는 모든 변수, 함수에 순서 정의

스코프체인 실행순서

  • 스코프 체인의 앞쪽
    • 항상 코드가 실행되는 컨텍스트의 변수 객체
    • 컨텍스트가 함수시 활성화 객체를 변수 객체로 사용

      활성화 객체

      • 항상 arguments 변수 하나로 시작
      • arguments객체는 전역 컨텍스트에는 없음
  • 변수객체 다음
    • 해당 컨텍스트를 포함하는 부모 컨텍스트
    • 그 다음은 부모의 부모 컨텍스트
    • 전역 컨텍스트까지 도달
  • 스코프 체인의 마지막
    • 전역 컨텍스트의 변수 객체

식별자를 찾기 위해 스코프 체인 순서를 따라가며 검색
(없는 경우, 에러 발생)

스코프체인 예제

var color = "blue";

function changeColor(){
    var anotherColor = "red";

    function swapColors(){
        var tempColor =anotherColor;
        anotherColor = color;
        color = tempColor;
        // color,anotherColor,tempColor모두 접근가능
    }
    // color,anotherColor접근가능.tempColor는 불가능
    swapColors();
    }
// color만접근가능
changeColor ( ) ;
  • 존재하는 실행 컨텍스트

    1. 전역 컨텍스트

      1. color변수 + changeColor()함수
    2. changeColor()의 지역 컨텍스트

      1. anotherColor변수 + swapColors()함수
      2. 전역 컨텍스트
    3. swapColors()의 지역 컨텍스트

      1. tempColor변수
      2. changeColor()함수의 컨텍스트
      3. 전역 컨텍스트
    4. 그림

      실행컨텍스트

  • 특징

    • 내부 컨텍스트는 스코프 체인을 통해 외부 컨텍스트로 접근 가능
    • 외부 컨텍스트는 내부 컨텍스트를 전혀 알 수 없음
  • swapColors()의 로컬 컨텍스트

    • 변수 객체 3개를 가짐

      1. swapColors()의 변수객체
      2. changeColor()의 변수객체
      3. 전역 변수객체
    • 자신의 변수 객체에서 변수나 함수를 찾음

    • 찾지 못할 경우 스코프 체인을 따라 한 단계씩 올라감
    • 아래로는 내려갈 수 없음
    • 함수 매개변수도 변수로 간주되어 실행 컨텍스트의 변수와 같은 규칙

스코프체인 확장

try-catch문의 catch블록with문
- 스코프체인 앞부분에 임시로 변수객체 생성
- 생성된 객체는 코드 실행이 끝나면 사라짐

  • with문

    해당 객체가 스코프체인에 추가

  • catch블록

    에러 객체를 선언하는 변수 객체가 생성

function buildUrl() {
    var qs = "?debug=true";

    /*
    * with문이 location객체에 적용되므로
    * location 객체개 scope chain에 추가됨
    */
    with(location) {
        /*
        * href는 location.href를 참조
        * qa는 buildUrl()함수 컨텍스트의 변수객체 참조
        * 
        * with문 내에서 선언한 url은 
        * buildUrl() 함수 컨텍스트로 편입됨
        */
        var url = href + qs;
    }
    /*
    *  with문을 통해 편입되었기 때문에 반환할 수 있음
    */
    return url;
}

var result = buildUrl();
console.log("url: " + result);

/* 
 * 실행결과
*************************
url: file:///Users/Dec7/Desktop/Javascript.html?debug=true
*************************
*/

Note

  • IE8까지는 JS구현에 문제가 있음
    • catch문에서 잡아낸 에러가 catch문의 변수객체가 아닌 실행 컨텍스트의 변수객체로 추가되어 catch블록 외부에서 접근 가능한 버그가 있음
  • IE9부터는 수정됨

블록레벨 스코프

for (var i=0; i < 10; i++){
    // do-something
}
alert(i); // 10
  • JS는 블록단위 스코프가 없음
  • JS는 변수를 선언할 때 현재 실행 컨텍스트에 추가

변수선언

  • var를 사용해 선언하면 자동으로 가장 가까운 컨텍스트에 추가
  • var를 사용하지 않으면 자동으로 전역 컨텍스트에 추가
// 전역 컨텍스트 예제
function one() {
    var one_num = 10;

    function two() {
        var two_num = 20;

        function three () {
            var three_num = 30;

            function four() {
                // var 키워드 미사용, 전역선언
                four_num = 40;
                console.log("in four(), four_num: " + four_num);
            }
            four();
            console.log("in three(), four_num: " + four_num);
        }
        three();
        console.log("in two(), four_num: " + four_num);

    }
    two();
    console.log("in one(), four_num: " + four_num);
}

one();
console.log("in global, four_num: " + four_num);

/*
* 출력결과
*********************
in four(), four_num: 40
in three(), four_num: 40
in two(), four_num: 40
in one(), four_num: 40
in global, four_num: 40 
*********************
*/
// var 키워드를 사용한 경우
function one() {
    var one_num = 10;

    function two() {
        var two_num = 20;

        function three () {
            var three_num = 30;

            function four() {
                // var 키워드 사용
                var four_num = 40;
                console.log("in four(), four_num: " + four_num);
            }
            four();
            console.log("in three(), four_num: " + four_num);
        }
        three();
        console.log("in two(), four_num: " + four_num);

    }
    two();
    console.log("in one(), four_num: " + four_num);
}

one();
console.log("in global, four_num: " + four_num);

/*
* 출력결과
*********************
in four(), four_num: 40
Uncaught ReferenceError: four_num is not defined
// console.log("in three(), four_num: " + four_num);에서 에러발생
*********************
*/

Note
- 변수를 선언하지 않고 사용하면 하면 에러 가능성 높아짐
- 스트릭모드에서 변수를 선언하지 않고 초기화시 에러

식별자검색

  • 컨텍스트 내부에서 식별자를 참조하기 전에 검색이 선행
  • 검색은 스코프체인 앞에서 시작
  • 식별자 이름으로 검색
  • 로컬 컨텍스트에서 검색 후 찾지 못하면
    • 스코프체인을 따라 검색을 계속함
    • 스코프체인 내부의 객체에도 프로토타입 체인이 있으므로 각 객체의 프로토타입 체인을 따라 검색할 수도 있음
  • 같은 식별자가 로컬 컨텍스트에 정의되어 있으며 부모 컨텍스트에 동일한 식별자가 있다고 하더라도 참조 불가
  • 검색에도 비용이 발생
    • 지역변수는 스코프체인 검색이 필요없으므로 전역변수보다 빨리 검색

4. 가비지 콜렉션

  • 더 이상 사용하지 않는 변수를 찾고 메모리를 회수함
  • 이 프로세스는 주기적으로 실행됨
  • [비추] 코드 실행 중 특정 시점에서 메모리 회수하도록 지정할 수도 있음
  • -

변수 사용여부


  • 더 이상 변수가
  • 하지만 명확하지 않은 경우가 많음
    • 사용여부를 확인 후 회수
    • 사용될 가능성이 있는지를 추측
    • 더 이상 사용하지 않는 변수의 기준을 브라우저마다 다름

      지역 변수
      함수를 실행하면 지역 변수가 생성됨
      함수가 종료된다면 그 지역 변수는 더 이상 필요 없음

* 참고자료


Written with Dec7.

댓글 없음:

댓글 쓰기