실행한 코드의 환경 정보를 모아놓은 ~객체~
활성화되는 시점에서
1. 선언된 변수를 위로 끌어올린다 ( 호이스팅 )
2. 외부 환경 정보를 구성한다
3. this 값을 실행한
Stack
=> lasi in, first our // LIFO
Queue
=> first in first out // FIFO
콜스택 이라는 방법으로 코드의 환경과 순서를 보장한다
함수를 통해서 실행 컨텍스트를 구성한다
~% 실행 컨텍스트를 생성할 때 VE 에 정보를 담은 다음 LE 에 복사해서 변경사항을 반영한다~
record = 식별자 정보
수집 대상 정보
순서대로 수집한다 // 실행하는 것은 별개다
변수 정보 수집 과정을 이해하기 쉽게 설명한 ' 가상 개념 '
~식별자 정보를 맨 위로 끌어올리는 행위~
( record 를 수집하는 과정을 의미 )
호이스팅 규칙
1. 매개변수나 변수는 선언부를 호이스팅한다
function a(x) {
console.log(x);
var x;
console.log(x);
var x = 2;
console.log(x);
}
a(1); // 1 1 2
var x 다음 console.log(x) 가 undefined 가 아닌 1 이 찍히는 이유
호이스팅을 통해서
function a(x) {
var x
var x
var x
x = 1
console.log( x )
console.log( x )
x = 2
console.log( x )
}
이렇게 선언부를 호이스팅 하기 때문에 그렇다
function a () {
console.log( b ) // error
var b = ' bbb '
console.log( b ) // 'bbb'
functino b () {}
console.log( b ) // function b
}
이렇게 결과를 예측할 수 있지만
호이스팅 적용 후
function a () {
var a
function b () {}
console.log( b ) // function b
b = ' bbb '
console.log( b ) // 'bbb'
console.log( b ) // 'bbb'
}
실제 결과는 이렇게 나온다
~함수 선언문~은 정의부만 존재하고 할당 명령이 없다
function a () { ... ... ... }
~함수 표현식~은 별도 변수에 함수를 할당한다
var b = function () { ... ... ... }
이 두 방법은 호이스팅 면에서 많이 다르다
함수 선언문의 경우 function 이 가장 위로 호이스팅 된 이후 전체 영역에서 영향을 끼치기 때문에 아래 줄에 적어도 안전하지 않을 수 있다
따라서 함수 표현식을 활용하는 것을 추천
식별자에 대한 유효 범위를 의미한다
outer 는 현재 호출된 함수가 선언될 당시의 lexical Environment 를 참조한다
A 는 전역 컨텍스트의 LE( 환경 정보 ) 를 OUTER 로 갖게 된다
B 는 A의 LE( 환경 정보 ) 를 OUTER 로 갖게 된다
이 당시의 환경을 참조하기 위함
var a = 1;
var outer = function() {
var inner = function() {
console.log(a); // 3
var a = 3;
};
inner();
console.log(a); // 1
};
outer();
console.log(a); // 1
여기서 두번째 console.log( a ) 가 1이 찍히는 것은 inner 컨텍스트가 이미 종료되었고 outer 컨텍스트에서 스코프 체인에 의해서 상위 컨텍스트인 전역 컨텍스트의 환경을 가져와서 a = 1 이 찍히는 것이
다양한 상황에서 다른 의미로 사용된다
this 는 실행 컨텍스트가 생성될 때 결정된다 ( binding 된다 )
JS 를 돌리는 환경
1. 노드
2. 브라우저
~브라우저의 전역컨텍스트 에서의 this 는 WINDOW 라는 객체~ 이다
~노드의 전역컨텍스트 에서의 this 는 GLOBAL 이라는 객체~ 이다
함수와 메서드의 차이는 ~독립성~ 이다
함수는 독립적으로 실행되는 것에 반해
메서드는 종속적으로 실행된다
따라서
% 메서드 내부에서 함수를 호출한다 하여도 예외 없이 무조건 this 는 전역 객체를 가리킨다
var obj1 = {
outer: function() {
console.log(this); // (1)
var innerFunc = function() {
console.log(this); // (2), (3)
}
innerFunc(); // (2)
var obj2 = {
innerMethod: innerFunc
};
obj2.innerMethod(); // (3)
}
};
obj1.outer();
여기서 (1) 에서 this 는 obj1.outer() 를 통해서 호출된 this 이기 때문에 메서드 로서의 호출, 즉 호출의 주체인 obj1 을 가리킨다
두 번째로 console.log 에 찍히는 this 는 innerFuni() 즉 (2) 에 있는 함수로서의 호출로 this 를 불러왔기 때문에 예외없이 전역 객체를 가리킨다
세 번째로 console.log 에 찍히는 (3) 에 있는 obj2.innerMethod() 에서 호출된 이후 찍히는 console.log(this) 는 메서드로 호출된 this 이기 때문에 호출의 주체인 obj2 를 가리킨다
메서드로 활용하지 않았다고 전역객체를 바라보는 this 가 합리적이지 않다고 여겨 우회하는 방법이 생겨났다
화살표 함수는 this binding 과정을 생략한다
( 전에 있던 this 의 환경을 그대로 유지하여 가져온다 )
var obj = {
outer: function() {
console.log(this); // (1) obj
var innerFunc = () => {
console.log(this); // (2) obj
};
innerFunc(); (2)
}
}
obj.outer();
=> ~(2) 에서 this 는 함수 (2) 의 함수인 함수에서 호출된 this 이지만,~
~innerFunc 가 화살표 함수 이기 때문에 this binding 이 생략되어서~
~전에 가지고 있던 this 인 obj 를 가리키게 된다~
%화살표 함수와 보통 함수의 가장 큰 차이점은 this binding 여부이
%콜백함수도 함수다
=> 따라서 콜백함수는 기본적으로 전역객체를 바라보게 되어있는데
콜백함수에 별도로 this 를 지정해준 경우를 예외로 가지고 있다
생성자 함수 -> 인스턴스를 만들기 위한 일종의 틀
여기서 instance 를 새로 만들 때 마다 this 는 그 instance 의 주체를 가리키게 된다
var Cat = function (name, age) {
this.bark = '야옹';
this.name = name;
this.age = age;
};
var choco = new Cat('초코', 7); //this : choco
var nabi = new Cat('나비', 5); //this : nabi
// call, apply, bind ( 이 메서드 들을 살펴보게 된다 )
call & apply 는 메서드를 입력하는 즉시 함수를 호출한다
bind 는 함수를 this binding 해서 새로운 함수를 return 한다
let func = function (a, b, c) {
console.log(this, a, b, c);
};
// func(1, 2, 3);
func.call({ x: 1 }, 4, 5, 6); // this 에 {x:1} 객체를 명시적으로 할당해준다
let obj = {
a: 1,
method: function (x, y) {
console.log(this.a, x, y);
},
};
// method 안에 있는 this 는 항상 obj 를 가리킬 수 밖에 없다
obj.method(2, 3); // 1 2 3 ( 1은 onj.a 에서 온 값 )
obj.method.call({ a: 4 }, 5, 6); // 4 5 6 ( this 에 a:4 라는 객체를 할당했기 때문에 this.a => 4 )
// apply 는 call 가 완전히 똑같은 기능을 한다
// 하지만 뒤에 있는 매개변수를 [] 로 넣어줘야 한다
obj.method.apply({ a: 4 }, [5, 6]); // 4 5 6
let func = function (a, b, c) {
console.log(this, a, b, c);
};
// ex) 1
let bindFunc1 = func.bind({ x:1 })
bindFunc( 5, 6, 7); // {x:1} 5 6 7
// ex) 2
let bindFunc2 = func.bind({x:1} , 4, 5)
bindFunc2(10) // {x:1} 4 5 10
=> 위와 같이 미리 들어갈 요소를 지정해줄 수도 있다
func.name // func
bindFunc.name //~bound~ func
유사 배열 객체의 조건
배열은 아니지만 call, apply 를 통해서 배열의 메서드를 차용하게 할 수 있다
=> 이는 call&apply 가 즉시 실행함수 이기 때문에 this binding 을 하는 자리에 유사배열객체를 넣어 줌으로서 가능하게 해준다
Array.from() 에 유사배열객체를 넣으면 [] 로 만들어서 반환해준다
ES6 의 새로운 기능