0. 환경
macbook-pro 13” 2012 mid / 10GB
1. 앞장 정리
변수
자바 스트립트의 변수는 느슨한 타입
느슨한 타입
초기화 하지 않을 경우 undefined
데이터타입
- 원시 데이터 타입 (다섯가지의 기본 데이터 타입)
- undefined
- null
- boolean
- 숫자
- 문자열
- 객체 (복잡한 데이터 타입)
자바 스크립트 데이터 타입은 동적이라서 한 가지 데이터 타입이 여러 특성을 가질 수 있음음
typeof 연산자
자바스크립트의 변수는 느슨한 타입이므로 변수의 타입을 알아야 할 때
typeof는 원시 값에 대해서는 잘 작동하지만 참조 값에서는 쓸모 없음
타입 |
내용 |
undefined |
정의되지 않은 변수 |
boolean |
불리언 |
string |
문자열 |
number |
숫자 |
object |
함수를 제외한 객체 또는 null |
function |
함수 |
instanceof 연산자
// 문법
'result' = 'variable' instanceof 'constructor'
변수가 주어진 참조타입의 인스턴스일 때 true반환
- 인스턴스는 프로토타입 체인으로 판단함
- 모든 참조 값은 Object의 인스턴스
Note
- typeof연산자를 함수에 사용시 function 반환
- typeof연산자를 정규표현식에 사용시 function 반환
- ECMA-262에서 내부에 [call]메소드를 가진 객체는 typeof에서 function를 반환해야한다고 명시했기 때문
- 사파리5까지, 크롬7까지만 적용, firefox, IE는 object 반환
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)가 연결됨
- 해당 컨텍스트에 정의된 모든 변수와 함수는 이 객체에 존재
- 이 객체를 코드에서 직접 접근 불가
- 이면에서 데이터를 다룰 때 이 객체를 사용
- 실행 컨텍스트는 그것이 포함된 코드가 모두 실행되면 파괴됨
종류
전역 컨텍스트
- 가장 바깥쪽에 존재하는 실행 컨텍스트
- 웹 브라우저에서 window라고 부름
- 전역변수와 함수는 window객체의 property, method로 생성
- 웹 브러우저가 닫칙 때까지 유지됨
함수 컨텍스트
- 독자적인 실행 컨텍스트
- 함수 호출시 생성됨
- 실행 순서
- 실행시
- 종료시
- 해당 컨텍스트를 컨텍스트 스택에서 꺼냄.
- 컨트롤을 이전 컨텍스트로 인전
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 ( ) ;
존재하는 실행 컨텍스트
전역 컨텍스트
- color변수 + changeColor()함수
changeColor()의 지역 컨텍스트
- anotherColor변수 + swapColors()함수
- 전역 컨텍스트
swapColors()의 지역 컨텍스트
- tempColor변수
- changeColor()함수의 컨텍스트
- 전역 컨텍스트
그림
특징
- 내부 컨텍스트는 스코프 체인을 통해 외부 컨텍스트로 접근 가능
- 외부 컨텍스트는 내부 컨텍스트를 전혀 알 수 없음
swapColors()의 로컬 컨텍스트
변수 객체 3개를 가짐
- swapColors()의 변수객체
- changeColor()의 변수객체
- 전역 변수객체
자신의 변수 객체에서 변수나 함수를 찾음
- 찾지 못할 경우 스코프 체인을 따라 한 단계씩 올라감
- 아래로는 내려갈 수 없음
- 함수 매개변수도 변수로 간주되어 실행 컨텍스트의 변수와 같은 규칙
스코프체인 확장
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.