let globalVar = "나는 전역 변수";
const globalConst = "나도 전역 변수";
function someFunction() {
console.log(globalVar); // "나는 전역 변수" 출력
console.log(globalConst); // "나도 전역 변수" 출력
}
someFunction();
console.log(globalVar); // "나는 전역 변수" 출력
var 키워드로 선언된 변수는 함수 스코프를 가짐function myFunction() {
var functionVar = "함수 안에서만 살아요";
console.log(functionVar); // "함수 안에서만 살아요" 출력
}
myFunction();
// console.log(functionVar); // 에러! functionVar는 함수 밖에서 접근 불가
{} 내부에서 let이나 const로 선언된 변수는 해당 블록 내에서만 접근이 가능if (true) {
let blockVar = "블록 안에서만 살아요";
const blockConst = "나도 블록 안에서만";
console.log(blockVar); // "블록 안에서만 살아요" 출력
console.log(blockConst); // "나도 블록 안에서만" 출력
}
// console.log(blockVar); // 에러! 블록 밖이라 접근 불가
// console.log(blockConst); // 에러! 블록 밖이라 접근 불가
function scopeTest() {
var functionScoped = "var는 함수 스코프";
let blockScoped = "let은 블록 스코프";
if (true) {
var functionScoped2 = "여전히 함수 스코프";
let blockScoped2 = "블록 스코프";
console.log(functionScoped); // 접근 가능
console.log(blockScoped); // 접근 가능
}
console.log(functionScoped2); // 접근 가능
// console.log(blockScoped2); // 에러! 블록을 벗어남
}
function dangerousScope() {
noKeyword = "위험해요!"; // 자동으로 전역 변수가 됨
}
dangerousScope();
console.log(noKeyword); // "위험해요!" 출력 - 의도치 않은 전역 변수 생성
// 블록 외부에서 선언
const outer1 = 100;
let outer2 = 200;
var outer3 = 300;
{
// 블록 내부에서 외부 변수 접근
console.log(outer1); // 100
console.log(outer2); // 200
console.log(outer3); // 300
// 블록 내부에서 새로운 변수 선언
const inner1 = "블록 안";
let inner2 = "블록 안";
var inner3 = "함수가 아닌 블록에서 var는 전역이 됨";
}
// console.log(inner1); // 에러! block scope
// console.log(inner2); // 에러! block scope
console.log(inner3); // "함수가 아닌 블록에서 var는 전역이 됨" - var의 특이한 동작
// 함수를 호출하고
hello(); // "안녕하세요!" 출력
// 나중에 함수를 선언해도 정상 작동합니다
function hello() {
console.log("안녕하세요!");
}
console.log(name); // undefined
var name = "John";
// 위 코드는 실제로 다음과 같이 동작
var name; // 선언부가 위로 호이스팅됨
console.log(name); // undefined
name = "John"; // 할당은 원래 위치에서 실행
// var의 경우
console.log(varVariable); // undefined
var varVariable = 10;
// let의 경우
console.log(letVariable); // ReferenceError!
let letVariable = 10;
// const의 경우
console.log(constVariable); // ReferenceError!
const constVariable = 10;
// 함수 호출이 선언보다 먼저 와도 동작
hello2(); // "hello2() 호출 실행되나요?" 출력
function hello2() {
console.log("hello2() 호출 실행되나요?");
}
console.log(val_2); // undefined
var val_2; // 선언만 호이스팅됨
console.log(val_3); // undefined
var val_3 = 10; // 선언은 호이스팅되지만 할당은 그대로
val_4++; // NaN - undefined에 증가 연산을 시도
console.log(val_4); // NaN
var val_4 = 10;
function getName() {
console.log(name); // undefined
var name = "John"; // 의도와 다르게 undefined 출력
return name;
}
var x = 1;
{
console.log(x); // undefined
var x = 2; // 호이스팅으로 인해 위의 x가 undefined
}
let과 const를 사용하면 호이스팅으로 인한 혼란을 크게 줄일 수 있음++ 나중에 ESLint 라는 도구를 사용 시, hoisting 이 발생하는 곳에 경고 발생함
const dog = {
sound: "멍멍!",
// 1. 이름 있는 함수
say1: function aaa() {
console.log(`say1: ${this.sound}`);
},
// 2. 익명 함수
say2: function() {
console.log(`say2: ${this.sound}`);
},
// 3. ES6 메서드 단축 구문
say3() {
console.log(`say3: ${this.sound}`);
},
// 4. 화살표 함수 (this 바인딩 주의!)
say4: () => {
console.log(`say4: ${this.sound}`); // undefined
}
}
const cat = {
sound: "야옹~"
};
// 1. 메서드로 호출 - 정상 동작
cat.say1 = dog.say1;
cat.say1(); // "야옹~" 출력
// 2. 일반 변수에 할당 - this 바인딩 끊김
const 개냥이 = cat.say1;
개냥이(); // undefined
// 1. bind() 사용
const 개냥이1 = cat.say1.bind(cat);
// 2. 화살표 함수로 감싸서 메서드 호출 형태 유지
const 개냥이2 = () => cat.say1();
// 3. call() 사용
const 개냥이3 = cat.say1;
개냥이3.call(cat);