실행 가능한 코드의 모든 환경 정보를 모아놓은 객체
var a = 3
var a
)Environment Record
- 현재 context와 관련된 코드의 식별자 정보를 저장함
(함수에 지정된 매개변수 식별자, 함수 자체, 변수 식별자 등)
Outer Environment Refernce
- 함수가 선언되는 시점의 외부 환경 정보를 가짐
JS 엔진이 자체적으로 변수/함수의 Environment Record를 코드의 최상단으로 올려 해석하는 것
var a = 3
의 var a
)를 끌어올림 // TEST 코드
function a(x) {
console.log(x);
var x;
console.log(x);
var x = 2;
console.log(x);
}
a(1);
// 매개변수를 적용한 함수의 내부
var x = 1;
console.log(x);
var x;
console.log(x);
var x = 2;
console.log(x);
// 호이스팅을 적용한 함수의 내부
var x;
var x;
var x;
x = 1;
console.log(x); // 1
console.log(x); // 1
x = 2;
console.log(x); // 2
// TEST 코드
function a() {
console.log(b);
var b = 'bbb';
console.log(b);
function b() {}
console.log(b);
}
a();
// 호이스팅을 적용한 함수의 내부
var b;
function b() {}
console.log(b); // [Function: b]
b = 'bbb';
console.log(b); // bbb
console.log(b); // bbb
// TEST 코드
function sum (a, b) {
return a + b;
}
console.log(sum(1, 2));
function sum (a, b) {
return 'a: ' + a + ', b: ' + b;
}
console.log(sum(1, 2));
// 호이스팅 결과
function sum (a, b) {
return a + b;
}
function sum (a, b) {
return 'a: ' + a + ', b: ' + b;
}
console.log(sum(1, 2)); // a: 1, b: 2
console.log(sum(1, 2)); // a: 1, b: 2
// TEST 코드
var sum = function (a, b) {
return a + b;
}
console.log(sum(1, 2));
var sum = function (a, b) {
return 'a: ' + a + ', b: ' + b;
}
console.log(sum(1, 2));
// 호이스팅 결과
var sum;
var sum;
sum = function (a, b) {
return a + b;
}
console.log(sum(1, 2)); // 3
sum = function (a, b) {
return 'a: ' + a + ', b: ' + b;
}
console.log(sum(1, 2)); // a: 1, b: 2
종류 | 영향 범위 |
---|---|
전역 Scope | 프로그램 전체에 영향을 줌 |
지역 Scope | 함수의 내부에만 영향을 줌 |
블록 Scope | 블록의 내부에만 영향을 줌(ex. if문, for문) |
Outer Environment Reference는 함수가 선언되는 시점의 외부 환경 정보를 가진다.
각 중첩 함수는 선언될 때마다 콜 스택(Call Stack)에 적재되며, 실행 완료 시 콜 스택(Call Stack)에서 빠져나간다.
함수의 식별자 정보를 찾는 과정
예시
// TEST 코드
var a = 1;
var outer = function() {
var inner = function() {
console.log(a); // 1번 a
var a = 3;
};
inner();
console.log(a); // 2번 a
};
outer();
console.log(a); // 3번 a
var a;
console.log(a); // undefined
a = 3;
따라서, 1번 a
= undefined
2번 a
는 inner()를 사용한 이후의 a 이기 때문에, inner 함수의 a 값은 외부에 영향을 주지 않는다. // inner() 함수 실행 이후의 코드
var a = 1;
var outer = function() {
console.log(a); // 2번 a
};
outer();
console.log(a); // 3번 a
var a = 1
따라서, 2번 a
= 1
3번 a
는 outer()를 사용한 이후의 a이기 때문에, outer 함수의 a 값은 외부에 영향을 주지 않는다. // outer() 함수 실행 이후의 코드
var a = 1;
console.log(a); // 3번 a
따라서, 3번 a
= 1
중첩 함수가 해 함수의 외부 함수보다 더 오래 유지되는 경우, 외부 함수가 종료되었음에도 중첩 함수가 Outer Environment Reference를 통해 변수의 식별자 정보를 참조할 수 있음
이유 : 변수는 자신이 선언되는 시점의 Lexical Environment를 가지기 때문
예시
// TEST 코드
const x = 1;
function outer() {
const x = 10;
const inner = function() {
console.log(x);
};
return inner;
}
const innerFunc = outer();
innerFunc();
const innerFunc = outer();
x = 10
을 저장한다.x = 10
)을 return 하고 종료하며 콜 스택에서 빠져 나온다.x = 10
은 outer 함수 종료 이후에도 유효하다.따라서, innerFunc()의 결과값
= 10
클로저의 사용 용도
: 상태(state)가 외부에 의해 의도치 않게 변경되지 않도록 하기 위해 사용 (캡슐화: Encapsulation)
this 값 : 함수가 호출되는(=실행 컨텍스트가 생성되는) 시점에 해당 함수가 속한 객체의 참조 값
this 값은 호출되는 상황에 따라 값이 변경된다.
상황 | this 값 |
---|---|
최상위 레벨(전역 공간)의 this | global(node.js), window(브라우저) |
함수 내부의 this | global(node.js), window(브라우저) |
메서드 내부의 this | 메서드를 호출한 객체 |
메서드 내부의 함수의 this | global(node.js), window(브라우저) |
이벤트 핸들러의 this | 이벤트를 호출한 요소 |
화살표 함수의 this | 함수의 한 단계 상위 객체 |
메서드를 사용하여 this가 가리키는 객체를 지정할 수 있음
let obj = {
a: 1,
method: function(x, y) {
console.log(this.a, x, y);
}
};
obj.method(2, 3); // 1 2 3
obj.method.call({a: 4}, 5, 6); // 4 5 6
obj.method.apply({a: 7}, [8, 9]); // 7 8 9
유사 배열 객체
: 인덱스(index)와 길이(length)가 존재하는 객체
- 특징
- length를 반드시 객체에 명시해야 한다.
- 배열의 메서드를 직접 사용할 수 없다.
let obj = { 0: 'a', 1: 'b', 2: 'c', length: 3 };
Array.prototype.push.call(obj, 'd');
console.log(obj); // {0: 'a', 1: 'b', 2: 'c', 3: 'd', length: 4}
Array.prototype.psuh.apply(obj, ['e']);
console.log(obj); // {0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', length: 5}
Array.from() 메서드
: 객체를 배열로 변환하는 ES6 문법let obj = { 0: 'a', 1: 'b', 2: 'c', length: 3 }; let arr = Array.from(obj); console.log(arr); // ['a', 'b', 'c']
function Person(name, gender) {
this.name = name;
this.gender = gender;
}
function Student(name, gender, school) {
Person.call(this, name, gender);
this.school = school;
}
let obj = {
a: 1,
method: function(x, y) {
console.log(this.a, x, y);
}
};
let bindObj = obj.method.bind({a: 4});
bindObj(5, 6); // 4 5 6
let bindObj = obj.method.bind({a: 4}, 5, 6);
bindObj(7, 8); // 4 5 6 7 8
console.log(obj.method.name); // method
console.log(bindObj.name); // bound method
가장 가까운 scope의 객체를 this 값으로 설정하기 때문에 별도의 this binding이 필요하지 않음