-
[Javascript] 스코프와 바인딩Javascript 2024. 4. 9. 16:23
렉시컬(정적) 스코프
- 변수나 상수가 코드상 어디에서 지정되었는가에 따라 그 사용 범위를 결정
- 함수가 코드상 어디에서 정의되었는가에 따라 그 상위 스코프를 결정
- 호출한 곳을 기준으로 하는 동적 스코프 dynamic scope 와 상반되는 개념
const x = 1; const y = 1; const z = 1; function func1 () { const y = 2; const z = 2; console.log('2', x, y, z); //2 1 2 2 func2(); } function func2 () { const z = 3; console.log('3', x, y, z); //3 1 1 3 } console.log('1', x, y, z) //1 1 1 func1();- 정의된 블록을 기준으로 상위 스코프의 값이 사용됨
const x = 1; const y = 1; const z = 1; function func1 () { const y = 2; const z = 2; function func2 () { const z = 3; console.log('3', x, y, z); //3 1 2 3 } console.log('2', x, y, z); //2 1 2 2 func2(); } console.log('1', x, y, z) //1 1 1 1 func1();렉시컬 환경
- 전체 문서, 함수, 블록을 실행하기 전 만들어지는 내부 객체
- 각 스코프의 고유 값들과 외부 스코프에 대한 참조를 포함
const x = 1; const y = 1; const z = 1; function func1 (a) { const y = 2; const z = 2; function func2 (b) { const z = 3; console.log('3', x, y, z, b); //3 1 2 3 2 } console.log('2', x, y, z, a); //2 1 2 2 1 func2(a + 1); } console.log('1', x, y, z) //1 1 1 1 func1(1);
클로저
- 내부 함수에서 외부 함수의 값에 접근할 수 있다는 개념 .. 함수 중첩시
=> 반환된 내부함수가 자신이 선언됐을 때의 환경인 스코프를 기억하여 자신이 선언됐을 때의 환경 밖에서 호출되어도 그환경에 접근할 수 있는 함수 : 자신이 생성될 때의 환경(렉시컬 스코프)를 기억하는 함수
function func1 () { const word = 'Hello'; function func2 () { console.log(word); } return func2; } const logHello = func1(); //func1안의 함수인 func2가 반환되어 저장 //func1의 실행이 끝났음에도 해당 스코프 내의 값이 살아있음 //func2와 func1가 선언된 환경(func1의 스코프)의 조합 logHello();예시
function createCounter (start) { let num = start; return function () { console.log(++start); return start; } } const count = createCounter(10);this
- 기본적으로 자신이 속한 곳을 가리킴 - 문맥 context
- 💡 함수의 호출 방식에 따라 가리키는 바가 달라짐 - 자바스크립트 특성

- 전역에서의 this : 전역 객체란 node 환경에서는 global 객체, 브라우저에서는 window 객체
- 함수안에서의 this : 여전히 전역 객체를 참조, 단 엄격모드에서는 함수안에서의 this = undefined

3. 메서드에서의 this : 객체의 메서드에서 this호출시 this는 그 객체를 참조
const obj = { name: "John", doSomething: function() { console.log(this.name) } } obj.doSomething() // John함수는 특정 기능을 수행하는 독립된 코드블록을 의미 : function이나 화살표 함수
메서드는 함수의 하위 개념. 객체의 프로퍼티(property)에 함수가 할당될 때 그 함수를 method라 정의
- 개별적으로 선언한 함수를 객체의 메서드로 설정한 경우
function sayName() { console.log(this.name) } const obj = { name: "John", doSomething: sayName } const obj2 = { name: "Chris", doSomething: sayName } obj.doSomething(); // John obj2.doSomething(); // ChrissayName 함수를 선언하고 두 객체의 메서드로 각각 전달하였습니다. 여기서 두 개의 메서드에서의 this는 각각 obj1과 obj2를 참조
외부 함수 sayName만 보면 위의 첫 번째로 살펴본 내용(1. 함수 안에서의 this)과 같이 this가 전역 객체를 참조할 것 같지만, 자바스크립트의 this는 런타임 시점에서 결정되기 때문에 메서드로 할당되는 순간 해당 객체를 참조
5. 객체안에서의 this
//객체 리터럴 - 해당 객체를 가리킴 const obj = { x: 123, getX: function () { return this.x; } } console.log(obj.getX()); //생성자 함수 - 생성될 인스턴스를 가리킴 function Person (name, age) { this.name = name; this.age = age; this.introduce = function () { return `저는 ${this.name}, ${this.age}세입니다.` } } console.log( new Person('홍길동', 20).introduce() ); //클래스 선언 - 생성될 인스턴스를 가리킴 class YalcoChicken { constructor (name, no) { this.name = name; this.no = no; } introduce () { return `안녕하세요, ${this.no}호 ${this.name}점입니다!`; } } console.log( new YalcoChicken('강남', 17).introduce() );this의 동적바인딩 :
- this가 가리키는 대상이 함수의 호출 주체 또는 그 방식에 따라 달라짐
const korean = { favorite: '김치', makeStew: function (isHot, pots) { return `${isHot ? '매운' : '순한'} ${this.favorite}찌개 ${pots}냄비`; } }; const italian = { favorite: '피자' }; console.log( korean.makeStew(true, 1) //매운 김치찌개 1냄비 ); // 이탈리아인에게 한국인이 찌개 끓이는 법을 알려줌 italian.makeStew = korean.makeStew; console.log( italian.makeStew(false, 2) // 순한 피자찌개 2냄비 ); //함수가 누가, 어떻게 호출되었는가에 따라 this가 가리키는 대상이 달라짐해결방법들 : call, apply, bind
1. call : this의 대상과 인자들을 나열
console.log( italian.makeStew.call(korean, false, 2) ); //순한 김치찌개 2냄비2. apply : this의 대상 뒤의 인자들을 배열로
console.log( italian.makeStew.apply(korean, [false, 2]) ); //순한 김치찌개 2냄비3. bind : this의 대상이 동적으로 변하지 않는 함수를 반환
// ⭐ this가 바인딩된 새 함수를 만듦 italian.makeRightStew = korean.makeStew.bind(korean); console.log( italian.makeRightStew(false, 2) //순한 김치찌개 2냄비 ); // 💡 추가 인자들까지 바인딩 가능 italian.makeClassicStew = korean.makeStew.bind(korean, true, 1); console.log( italian.makeClassicStew() //매운 김치찌개 1냄비 );4. 바인딩된 함수를 내보내는 함수
const korean = { favorite: '김치', makeStew: function (isHot, pots) { return `${isHot ? '매운' : '순한'} ${this.favorite}찌개 ${pots}냄비`; }, teachMakingStew: function () { return this.makeStew.bind(this); } }; const italian = { favorite: '피자' }; italian.makeStew = korean.teachMakingStew(); console.log( italian.makeStew(false, 2) //순한 김치찌개 2냄비 );5. 생성자 함수일 경우 - 함수 자체를 미리 인스턴스에 바인딩
function Korean () { this.favorite = '김치'; this.makeStew = function (isHot, pots) { return `${isHot ? '매운' : '순한'} ${this.favorite}찌개 ${pots}냄비`; }; // 💡 여기서 바인딩을 고정시켜버림 this.makeStew = this.makeStew.bind(this); } function Italian () { this.favorite = '피자'; } const korean = new Korean(); const italian = new Italian(); italian.makeStew = korean.makeStew; console.log( italian.makeStew(false, 2) //순한 김치찌개 2냄비 );- 배열 메서드의 thisArg
- 콜백으로 주어진 함수 내에서 this가 가리킬 대상
- 보통 콜백함수 다음 인자로 넣음

this의 정적바인딩
const obj = { // function 선언 함수 func1: function () { return true; }, // 메서드 func2 () { return true; }, // 화살표 함수 func3: () => true } console.log( obj.func1(), //true obj.func2(), //true obj.func3() //true );
function 선언 함수만 생성자로 활용 가능 - 더 많은 기능이 있고 무겁다는 의미 - 화살표 함수에서의 this : 객체의 메서드로 화살표 함수를 전달하면 this는 그 객체를 참조하지 않고 상위컨텍스트 참조
1. 객체 리터럴에서
const obj = { name: "John", doSomething: () => { console.log(this) } } obj.doSomething() //Window {window: Window, self: Window, document: document, name: "", location: Location, …}따라서 예시에서처럼 객체 외부의 컨텍스트를 그대로 이용하고 싶은 경우에는 화살표 함수를 사용
- function 함수나 메서드의 동적 바인딩과 다르게 동작
- 함수가 어디서 선언되었는가에 따름 - ⭐️ 가장 근접한 상위 스코프에 바인딩 고정
- 즉 this를 정적으로 바인딩함
2. 생성자 함수와 클래스에서
- 기본적으로는 가리키는 대상이 동일 (해당 인스턴스)
- ⭐ 동적으로 바인딩하는 타 방식과의 차이 확인
function Korean () { this.favorite = '김치'; this.makeStew = function (isHot) { // 선언함수 사용 return `${isHot ? '매운' : '순한'} ${this.favorite}찌개`; }; this.fryRice = (isHot) => { // 화살표함수 사용 return `${isHot ? '매운' : '순한'} ${this.favorite}볶음밥`; }; } function Italian () { this.favorite = '피자'; } const korean = new Korean(); const italian = new Italian(); console.log(korean.makeStew(true)); //매운 김치찌개 (동적바인딩) console.log(korean.fryRice(true)); //매운 김치볶음밥 (정적바인딩)- 정적 바인딩의 경우 call, apply, bind의 this인자 무시
console.log( korean.fryRice.call({favorite: '된장'}, true) ); console.log( korean.fryRice.apply({favorite: '된장'}, [true]) ); console.log( korean.fryRice.bind({favorite: '된장'}, true)() ); // 매운 김치볶음밥'Javascript' 카테고리의 다른 글
[Javascript] 프로토타입과 상속 (0) 2024.04.10 [Javascript] Prototype 프로토타입 (0) 2024.04.09 [Javascript] 이터러블, 제너레이터 (0) 2024.04.08 [Javascript] Set , Map (0) 2024.04.08 [Javascript] 클래스 Class (1) 2024.04.05