this, function 등의 동작 원리가 포함되어 있으며, 이런 원리들은 자바스크립트의 핵심 원리로 간주된다.undefined로 초기화된다. (var기준)console.log(a); // undefined
var a = 10;
function foo() { return "Hello"; }
function outer() {
let a = 1;
function inner() {
console.log(a); // outer의 스코프에 접근 가능
}
inner();
}
outer();
this 바인딩this 키워드의 값을 결정한다.window 또는 global)undefined(strict 모드) 또는 전역 객체this를 결정const obj = {
a: 10,
method() {
console.log(this.a); // obj의 a
}
};
obj.method();
function first() {
console.log("First");
}
function second() {
console.log("Second");
}
first();
second(); // 호출 순서대로 실행: first() => second() 실행 순서가 보장된다.
function makeCounter() {
let count = 0;
return function() {
return ++count; // 클로저를 통해 count 유지
};
}
const counter = makeCounter();
console.log(counter()); // 1
console.log(counter()); // 2
function a() {
b();
}
function b() {
console.log("b");
}
a(); // 호출 스택: global → a → b
this 값이미지 출처 : heycoding tistory
let, const 변수와 함수 선언 뿐 아니라 코드의 스코프와 관련된 정보를 관리한다. 현재 컨텍스트 내의 var로 선언된 변수와 함수 선언의 정보를 관리한다.
실행 컨텍스트 생성 시, Variable Environment는 var 변수와 함수 선언만 초기화하고, let과 const는 Lexical Environment에서 관리된다.
Lexical Environment의 스냅샷이 아니며, 각자 독립적으로 생성되고 관리된다.this가 참조하는 객체를 나타낸다.window 또는 global 객체를 참조한다.{ a: 10, b:function(){} }window 객체(브라우저)나 global 객체(Node.js)가 환경 레코드 역할을 한다.let, const를 사용하는 블록 스코프({})도 독립적인 렉시컬 환경을 생성한다.{
let a = 10;
const b = 20;
}
function outer() {
let a = 10; // outer 렉시컬 환경의 변수
function inner() {
console.log(a); // 상위 렉시컬 환경(outer)을 참조
}
inner();
}
outer();
outer() 실행 시:
outer 함수의 렉시컬 환경 생성{ a: 10 }inner() 실행 시:
inner 함수의 렉시컬 환경 생성{} (함수 내부에서 선언된 변수 없음)outer 함수의 렉시컬 환경ReferenceError)가 발생한다.let x = 10;
function foo() {
let y = 20;
function bar() {
let z = 30;
console.log(x + y + z); // 10 + 20 + 30
}
bar();
}
foo();
bar 함수의 렉시컬 환경:{ z: 30 }foo 함수의 렉시컬 환경foo 함수의 렉시컬 환경:{ y: 20 }{ x: 10 }function makeCounter() {
let count = 0; // 클로저로 참조됨
return function () {
count++;
return count;
};
}
const counter = makeCounter();
console.log(counter()); // 1
console.log(counter()); // 2
let, const로 선언된 변수를 블록 스코프로 관리한다.var 키워드와 관련된 변수의 호이스팅과 스코프를 처리한다.var 키워드로 선언된 변수는 환경 레코드의 변수 환경(Variable Environment)에 저장된다.※ 외부 렉시컬 환경 참조 X
- 변수 환경은 외부 렉시컬 환경 참조를 가지지 않으며, 단지 현재 스코프 내의 변수를 관리한다.
변수 환경 (Variable Environment)
변수 환경은 변수의 선언과 값을 관리한다. 하지만, 실행 중에 값이 변경되더라도, 변수 환경 자체는 변경된 값을 추적하지 않는다.
초기화 단계에서 설정되며, 실행 중에 변경된 값은 변수 환경이 아닌, 실행 스택이나 스코프 체인을 통해 처리된다.
변수 환경은 렉시컬 환경과 다르게 외부 렉시컬 환경을 참조하지 않는다. 변수 환경은 현재 함수의 변수들만 관리하며, 외부 함수의 변수나 스코프에는 접근하지 않는다.
렉시컬 환경 (Lexical Environment)
function outer() {
var x = 10; // 'x' 변수 선언
function inner() {
console.log(x); // 'x'를 참조
}
x = 20; // x 값을 변경
inner(); // x 값을 출력
}
outer();
변수 환경 (Variable Environment)
변수 환경은 변수 선언과 초기 값을 관리한다. outer 함수 내에서 x는 변수 환경에 선언되고, 초기 값은 10으로 설정된다.
실행 중에 값이 변경되면, 변수 환경은 변경된 값을 추적하지 않는다.
x의 값이 20으로 변경되었지만, 변수 환경 자체는 초기값인 10만을 관리하고 변경된 값을 추적하지 않는다.x는 변수 환경에 10으로 설정된 후, 실행 중에 20으로 변경된다. 변수 환경은 여전히 10을 관리하지만, x의 값은 실행 스택에서 20으로 변경된다.x 값의 변경 사항을 추적하지 않기 때문에, inner 함수가 호출될 때 초기 값 10을 참조할 수 있다.outer() 함수 실행:var x = 10;이 실행되며, x는 outer 함수의 변수 환경에 10으로 저장된다.x = 20;로 값 변경:x의 값을 20으로 변경하지만, 변수 환경은 여전히 10을 저장하고 있다.var로 선언된 변수는 함수의 변수 환경에서 초기값을 관리하고, 변수의 값 변경은 변수 환경에서 추적되지 않기 때문이다.inner() 함수 호출:inner() 함수가 호출된다. 이때 inner() 함수의 렉시컬 환경은 outer() 함수의 변수 환경을 참조한다.inner()함수는 자신의 변수환경에 x가 없기 때문에 outer()함수의 변수 환경을 참조하게 된다.inner() 함수는 x를 참조할 때, 변수 환경에서 초기값인 10을 참조한다.inner()가 실행될 때 변수 환경에는 x = 10만 저장되어 있기 때문이다.inner() 함수에서 x는 여전히 10을 출력한다.inner() 함수에서 x를 참조할 수 있는 이유는 렉시컬 환경 덕분인데, 렉시컬 환경이 상위 스코프의 변수를 참조할 수 있기 때문에, inner() 함수는 outer() 함수의 변수 환경을 참조하여 x = 10을 출력하는 것이다.렉시컬 환경 (Lexical Environment)
inner 함수는 렉시컬 환경을 생성할 때, 상위 렉시컬 환경으로 outer 함수의 스코프를 참조한다.inner 함수는 렉시컬 환경을 통해 outer 함수의 x를 참조할 수 있다.inner 함수는 렉시컬 환경을 통해 상위 함수인 outer의 스코프 체인을 참조하여 x를 찾을 수 있다.inner 함수는 렉시컬 환경을 통해 outer 함수의 변수 환경에 접근하고, x의 변경된 값 20을 참조합니다. 즉, x는 outer에서 실행 중에 변경된 값인 20을 출력한다.inner 함수는 렉시컬 환경을 통해 outer의 변수 환경에 접근하여 x를 참조한다.inner 함수가 실행될 때 x는 변경된 값인 20으로 출력된다. inner는 outer의 스코프 체인을 참조하여 변경된 값인 20을 출력한다.outer() 함수 실행:outer() 함수가 실행될 때, 실행 컨텍스트가 생성된다. 이 컨텍스트에는 변수 환경과 렉시컬 환경이 포함되어 있다.x = 10이 저장되어 있다.inner() 함수는 outer() 함수의 렉시컬 환경 내에 존재한다.inner() 함수는 렉시컬 환경에서 outer() 함수의 변수 환경을 참조할 수 있다.x 값 변경:x의 값이 10에서 20으로 변경된다. 변수 환경은 x의 초기값만 저장하고, 값이 변경되면 해당 변경을 추적하지 않는다.x의 값은 실행 스택에서 변경된 20이 저장됩니다.inner() 함수 실행:inner() 함수가 실행될 때, inner()의 실행 컨텍스트가 생성된다.inner() 함수가 outer() 함수의 렉시컬 환경을 참조하게 된다.inner()는 outer() 함수의 변수 환경을 참조할 수 있다.outer() 함수)의 변수 환경을 참조하고, 이때 변경된 x 값인 20을 출력하게 된다.20을 콜 스택에서 보고 찾는데, 변수 환경은 콜 스택을 확인하지 않고, 변수 환경에서 최초 초기화된 값만 기억한다는 것이다.console.log(x)에서 x는 변경된 값인 20을 출력한.x의 변경된 값 20을 추적하지 않지만, 렉시컬 환경에서는 실행 시 값이 변경된 x를 참조하여 20을 출력할 수 있다.this 바인딩은 this 식별자 키워드와 this가 가리켜야 하는 객체를 연결하는 것을 의미한다.this는 자바스크립트에서 함수가 호출될 때 그 함수가 속한 객체를 참조하는 키워드이다.. this의 값은 함수가 호출되는 방식에 따라 달라질 수 있다.this값이 어떻게 바인딩되는지 살펴보자.window, Node.js에서는 globalconsole.log(this); // 브라우저에서는 window 객체를 가리킴
function highOrderFunction(callback) {
callback(); // 일반 함수 호출로 실행됨
}
function callbackFunction() {
console.log(this); // 전역 스코프에서 호출된 일반 함수
}
highOrderFunction(callbackFunction);
// 출력: window (브라우저 환경)
function highOrderFunction(callback) {
callback();
}
const obj = {
name: "example",
method: function () {
highOrderFunction(function () {
console.log(this); // 일반 함수 호출
});
}
};
obj.method();
// 출력: window (브라우저 환경)
use strict 사용 여부에 따라 this가 다르게 출력될 수 있다.use strict 사용 : undefineduse strict 미사용 : window(브라우저)function hello(){
console.log(this); // window/global
}
hello();
this는 객체 자체를 참조한다.this를 호출하면 해당 메서드를 포함하는 객체가 this이다.window/global)가 this이다. const obj = {
name: 'John',
greet: function() {
console.log(this.name);
}
};
obj.greet(); // 'John' 출력, this는 obj를 참조
this는 새로 생성되는 객체의 인스턴스이다.function Person(name) {
this.name = name;
}
const person1 = new Person('Alice');
console.log(person1.name); // 'Alice'
this가 자신의 문맥을 따르지 않는다. 대신, 외부 스코프의 this를 상속받는다.const obj = {
name: 'John',
greet: () => {
console.log(this.name);
}
};
obj.greet(); // undefined, 화살표 함수는 외부 문맥의 this(전역 객체)를 참조
call, apply, bind 메소드를 사용하여, this를 명시적으로 설정할 수 있다.const obj = { name: 'Alice' };
function greet() {
console.log(this.name);
}
greet.call(obj); // 'Alice', call을 사용하여 this를 obj로 설정
※ call(thisArg, arg1, arg2, ...)
this객체를 1번째 인수로, 함수 내에서 필요로 하는 파라미터는 2번째 인수로 전달하면 된다.const obj = {name: 'tom'};
const say = function(city){
console.log(`hello ${this.name}, this is ${city}`);
};
say.call(obj, 'seoul'); // hello tom, this is seoul
// ------------------
function foo(a, b, c) {
console.log(a + b + c);
console.log(this);
};
foo.call(obj, 1, 2, 3); // 6, { name: 'tom' }
※ apply(thisArg, [arg1, arg2, ...]
this객체를 1번째 인수로, 함수 내에서 필요로 하는 파라미터는 배열 형태로 인수를 전달할 수 있도록 하면 된다.const obj = {name: 'tom', age: 21};
const say = function(city, dongNm){
console.log(`hello ${this.name}, ${this.age}, this is ${city} ${dongNm}`);
};
say.apply(obj, ['seoul', '법정동']) // hello tom, 21, this is seoul 법정동
// -----------------------------
function foo(a, b, c) {
console.log(a + b + c);
console.log(this);
};
foo.apply(obj, [1, 2, 3]); // 6, { name: 'tom' }
※ const boundFunc = bind(thisArg, arg1, arg2, ...);
bind함수는 새로운 함수를 생성하고, 해당 함수가 호출될 때 항상 특정한 this값을 가질 수 있도록 한다.bind함수로 별도 함수를 생성할 때 전달한 인수를 this로 가지며, 이 함수를 가지고 있다가 나중에 실행할 수 있다는 것이 큰 특징이다. const obj = {name: 'tom'};
const say = function(city){
console.log(`hello ${this.name}, this is ${city}`);
};
const boundSay = say.bind(obj);
boundSay("busan"); // hello tom, this is busan
var x = 'xxx';
function foo () {
var y = 'yyy';
function bar () {
var z = 'zzz';
console.log(x + y + z);
}
bar();
}
foo();

전역 실행 컨텍스트
전역 영역에 존재하는 코드를 관리하는 실행 컨텍스트로, 모든 스크립트 코드는 전역 실행 컨텍스트 안에서 실행된다.
자바스크립트 코드가 실행될 때 가장 처음 생성되고, 프로그램 전체를 감싸는 기본 환경을 관리하는 컨텍스트이다. (코드 실행을 위한 무대라고 생각)
아래는 전역 실행 컨텍스트의 역할이다.
코드의 시작점 : 자바스크립트 엔진이 코드를 실행하기 위해 가장 먼저 생성하는 컨텍스트
전역 변수와 함수 관리
window 객체, Node.js에서는 global 객체가 자바스크립트 실행 환경에서 가장 최상위 객체가 된다.window, global 객체를 이용해 전역 코드의 변수와 함수를 저장하고 실행한다.프로그램 전체를 실행 : 함수 호출 전까지 실행되는 모든 전역 코드가 이 컨텍스트에서 처리된다.
항상 하나만 존재 : 프로그램이 실행되는 동안 단 하나의 전역 실행 컨텍스트만 존재하며, 실행되는 동안 절대 사라지지 않는다.
함수 실행 컨텍스트
콜 스택에서 전역 컨텍스트와 관련된 코드들을 자바스크립트 엔진이 순차적으로 실행시키다가 foo()함수가 호출되면 자바스크립트 엔진은 foo()함수에 대한 환경 정보를 수집해서 foo()의 함수 실행 컨텍스트를 생성한 후 콜 스택에 담는다.
foo()의 함수 실행 컨텍스트가 놓였으므로 전역 컨텍스트와 관련된 코드보다 foo()의 함수 실행 컨텍스트와 관련된 코드가 우선순위가 더 높아지면서, foo() 함수 내부의 코드들이 순차로 실행되기 시작한다.foo() 함수 실행 도중, bar()함수가 실행되면, bar() 함수에 대한 함수 실행 컨텍스트가 콜 스택 가장 위에 담기게 된다.
bar()함수에 대한 함수 실행 컨텍스트가 콜 스택 가장 위에 쌓이게 되면, 콜 스택에서 bar() 함수 실행 컨텍스트가 제거되고, 제어권이 다시 이전 컨텍스트인 foo() 함수 실행 컨텍스트로 전환된다.
코드가 모두 진행되고 bar() 함수의 실행이 종료되면 bar() 함수 실행 컨텍스트가 콜 스택에서 제거되고, 다시 foo() 함수 실행 컨텍스트가 콜 스택의 맨 위에 존재하게 되므로, 코드 실행이 중단되었던 부분부터 이어서 실행하게 된다.
window 객체를 이용해 전역 코드의 변수와 함수를 저장하고 실행하는 방법 예시// 브라우저 환경
var a = 5;
function hello() {
console.log("Hello!");
}
console.log(window.a); // 5
window.hello(); // Hello!
a와 hello는 전역 실행 컨텍스트에 의해 window 객체의 속성으로 관리된다.window.a와 window.hello()로 접근이 가능하다.