dh_0e

[JavaScript] 주요 문법 정리(1) (실행 컨텍스트, this binding, 유사 배열 객체) 본문

내일배움캠프/HTML,CSS,JavaScript

[JavaScript] 주요 문법 정리(1) (실행 컨텍스트, this binding, 유사 배열 객체)

dh_0e 2024. 4. 25. 01:36

 

실행 컨텍스트(Execution Context)

실행 컨텍스트란 실행 코드에 제공할 환경 정보들을 모아놓은 객체

콜 스택환경 정보를 저장하며 스택이므로 FILO(First In Last Out)의 구조임

콜 스택에 저장되는 실행 컨텍스트

 

실행 컨텍스트는 환경 정보 3가지가 모여 객체를 이루며 이를 통해 환경을 보장함

 

1. VariableEnvironment(VE) - 현재 컨텍스트 내의 식별자 정보(=record)와 외부 환경 정보(=outer)
2. LexicalEvironment(LE) - VE와 동일하지만 변경사항을 실시간으로 반영하며 스냅샷을 유지하지 않는다.
3. this Binding - 함수나 메소드에서 this를 특정 객체로 bind하여 사용하는 것

결국, 실행 컨텍스트를 생성할 때, VE에 정보를 먼저 담으며, 이를 그대로 복사해서 LE를 만들고 이를 활용한다.

 

environmentRecord(=record)

1. 식별자 정보를 저장 ex)var a=3 에서 var a를 의미
2. 함수에 지정된 매개변수 식별자, 함수 자체, var로 선언된 변수 식별자 등을 수집함
3. 컨텍스트 내부를 처음부터 끝까지 순서대로 훑어가며 수집 (수집만 하고 코드를 실행하지는 않음)

호이스팅이 이 record의 수집 과정이며 변수 정보 수집 과정을 이해하기 쉽게 설명한 '가상 개념'임

 

 

 

 

 

this란?

현재 실행되는 코드의 실행 컨텍스트

전역 환경에서 this는 전역 객체이며 노드 환경에선 global 객체이며 웹 브라우저에선 window 객체

 

함수 vs 메소드

독립적 vs 종속적
함수명() vs 객체. 메소드 명()
this가 전역 객체 vs this가 해당 객체
이때 메소드의 내부함수에서의 this는 전역 객체를 의미

function func() { // 함수
    console.log(this); // (1)
}

const obj1 = {
    method: function () { // 메소드
        console.log(this); // (2)
        const innerFunc = function () { // 메소드의 내부함수
            console.log(this); // (3) (4)
        };
        innerFunc();

        const obj2 = {
            innerMethod: innerFunc
        };
        obj2.innerMethod();
    }
};

func();
obj1.method();

/*
(1) Object[global] ..       global
(2) { method: [Function: method] }      = obj1
(3) Object[global] ..       global
(4) { innerMethod: [Function: innerFunc] }      = obj2
*/

 

 

 

 

this binding

함수나 메소드에서 this를 특정 객체로 bind하여 사용하는 것

 

 

1. this를 일정한 변수에 할당하는 방법
객체의 값을 가진 this를 어떠한 변수에 저장시켜 하위 함수에서 값을 가져와 활용
이제는 거의 사용하지 않는 하드코딩 방법

const obj = {
    method: function () {
        console.log(this); // { method: [Function: method] } = obj
        const self = this;
        const innerFunc = function () {
            console.log(self); // { method: [Function: method] } = obj
        };
        innerFunc();
    }
};

obj.method();

 

 

2. 화살표 함수 (Arrow function)
화살표 함수는 this를 바인딩하지 않는 함수이다!!
일반 함수와 화살표 함수의 가장 큰 차이점은? -> this binding 여부

(애초에 화살표 함수는 ES6에서 this binding 문제를 해결하기 위해 도입된 함수임)

const obj = {
    method: function () {
        console.log(this); // { method: [Function: method] } = obj
        const innerFunc = () => {
            console.log(this); // { method: [Function: method] } = obj
        };
        innerFunc();
    }
};

obj.method();


 

3. 콜백 함수 호출 시 그 함수 내부에서의 this (완벽히 이해 못 함)

콜백 함수 호출 시 그 함수 내부의 this는 전역 객체가 되지만, 예외로 콜백 함수에 별도로 this를 지정하는 경우가 있음
생성자 함수 내부에서의 this도 인스턴스를 지칭함 (호출 받을 때마다 달라진다)

인스턴스 : 일반적으로 실행 중인 임의의 프로세스, 클래스의 현재 생성된 오브젝트

 


4. 명시적 this binding (call, apply, bind)
1) func.call( {this로서 bind하고싶은 객체}, 매개변수 )
2) func.apply( {this로서 bind하고싶은 객체}, [매개변수] ) - call에서 매개변수들을 대괄호로 묶어주면 됨

3) func.bind( {this로서 bind하고싶은 객체} ) 즉시 호출하지 않고 this binding된 새로운 함수 리턴
func.bind( {this로서 bind하고싶은 객체}, 매개변수1, 매개변수2 )

위처럼 binding할 객체명 뒤에 매개변수를 미리 입력할 수도 있다.
이때 name 프로퍼티에 로그로 찍어보면 bound 즉, bind 됐다는 접두어가 같이 출력됨

var func = function (a, b, c, d) {
    console.log(this, a, b, c, d);
};
var bindFunc = func.bind({ x: 1 }, 4, 5);


console.log(func(1, 2, 3, 4)); // Object [global] {...} 1 2 3 4
console.log(bindFunc(6, 7)); // { x: 1 } 4 5 6 7

console.log(func.name); // func
console.log(bindFunc.name); // bound func


call보다 bind를 더 많이 사용하며 사실상 call, apply, bind, this우회보다 화살표 함수가 더 편함

this 우회     <     call, apply     <     bind     <     Arrow function

 

5. 생성자 함수 내부에서의 this

var Dog = function (name, age) {
	this.bark = '멍멍';
	this.name = name;
	this.age = age;
};

var mallaeng = new Dog('말랭', 3); //this : mallaeng
var jjoya = new Dog('쪼야', 15);  //this : jjoya

 

 

 

유사 배열 객체(array-like-object)

Key값이 일정한 규칙으로 반복이 가능한 배열과 유사한 객체

유사 배열 객체의 조건으론
1. 반드시 length가 필요해야함
2. index 번호가 0부터 시작해서 1씩 증가해야 함 (필수는 아니지만 예상치 못한 결과가 생길 수도 있음)

var obj = {
    0: 'a',
    1: 'b',
    2: 'c',
    3: 'd',
    length: 4
};

 

 

유사 배열 객체에 call을 사용하여 배열 메서드를 적용할 수 있음

Array.prototype.push.call(유사배열객체, data);
Array.prototype.slice.call(유사배열객체);

var obj = {
    0: 'a',
    1: 'b',
    2: 'c',
    3: 'd',
    length: 4
};

Array.prototype.push.call(obj, 'e');
console.log(obj); // { '0': 'a', '1': 'b', '2': 'c', '3': 'd', '4': 'e', length: 5 }

const slicedObj = Array.prototype.slice.call(obj);
console.log(slicedObj); // [ 'a', 'b', 'c', 'd', 'e' ]

 


복잡한 메커니즘 때문에 ES6에선 Array.from을 제시함
Array.from(유사배열객체) - 유사배열객체를 배열로 바꿔서 반환함

var obj = {
    0: 'a',
    1: 'b',
    2: 'c',
    3: 'd',
    length: 4
};

const nowArr = Array.from(obj);
console.log(nowArr); // [ 'a', 'b', 'c', 'd' ]