March 16, 2021
var로 정의된 변수는 함수 스코프를 가진다는 것이 문제다. 함수를 벗어난 영역에서 사용하면 에러가 발생하고 함수 내에서는 어디서든 그 변수를 사용할 수 있다.
function foo() {
var age = 20;
}
console.log(age); // ReferenceError: age is not defined
var로 함수 내부가 아닌 프로그램의 가장 바깥에 정의하면 전역 변수가 된다. 프로그램 전체를 감싸는 하나의 함수가 있다고 생각하면 된다. 그런데, 함수 안에서 var 키워드를 사용하지 않고 변수를 정의하면 그 변수는 전역 변수가 된다. 따라서 아래의 코드에서는 에러가 발생하지 않는다.
function foo() {
age = 20; // 정상
}
function bar() {
console.log(age); // 20
}
foo();
bar();
use strict : 위와 같이 var 키워드를 사용하지 않을 경우 전역 변수가 되는 것을 방지하기 위해서 파일의 최상단에 use strict를 선언할 수 있다.
'use strict';
function foo() {
age = 20; // ReferenceError: age is not defined
}
function bar() {
console.log(age);
}
foo();
bar();
var는 함수 스코프이기 때문에 for문에서 정의된 변수가 반복문이 끝난 이후에도 계속 남아 있는 문제가 있다.
for (var i = 0; i < 10; i++) {
console.log(i);
}
console.log('last:', i); // last: 10
var의 스코프를 제한하기 위해 즉시실행함수를 사용하기도 한다. var는 함수 스코프를 가지기 때문에 즉시실행함수 로 스코프를 제한하는 방법이다. 아래의 코드에서 i는 함수로 감싸져있기 때문에 함수 밖에서 이 변수를 사용할 수 없게 되는 것이다.
(function() {
for (var i = 0; i < 10; i++) {
console.log(i);
}
})();
console.log('last:', i); // ReferenceError: i is not defined
var 키워드로 정의된 변수는 “선언 부분이” 그 변수가 속한 스코프의 최상단으로 Hoisting된다. 그래서 변수를 미리 사용해도 에러가 발생하지 않는다. 이러한 호이스팅 기능은 직관적이지 않고 보통의 프로그래밍 언어에서 찾아보기 힘들다.
console.log(myVar); // undefined
var myVar = 1;
위의 코드는 아래의 코드와 동일하다고 보면 된다.
var myVar = undefined;
console.log(myVar); // undefined
myVar = 1;
var 키워드로 정의된 변수는 다시 재선언, 재할당 할 수 있다.
var num = 1;
var num = 2;
console.log(num); // 2
예를 들어, if문 안에서 변수를 정의하면 if문 밖에서는 그 변수를 사용할 수 없다.
if (true) {
const i = 0;
}
console.log(i); // ReferenceError: i is not defined
심지어 그냥 블록으로 감싸주기만 해도 해당 블록 밖에서는 변수를 사용할 수 없다.
{
const i = 0;
}
console.log(i); // ReferenceError: i is not defined
같은 이름의 변수를 정의하는 경우 → 감싸고 있는 블록 안에서 먼저 변수를 찾고 없으면 그 바깥의 블록 안에서 변수를 찾는다.
let nickname = 'Jessie';
let age = 20;
console.log(nickname, age); // Jessie 20
if (true) {
let nickname = 'Lia';
console.log(nickname, age); // Lia 20
}
console.log(nickname, age); // Jessie 20
const, let으로 정의된 변수도 호이스팅이 된다. var와 차이점은, var는 호이스팅 된 후에 undefined가 할당되는 반면, const와 let은 호이스팅 된 후에 아무런 값도 할당되지 않는다는 것이다. 따라서 const, let의 경우에는 에러가 발생한다.
console.log(foo); // ReferenceError: foo is not defined
const foo = 1;
호이스팅이 된다는 또 다른 예시를 한 번 보자. 아래의 코드에서 만약 블록 안의 foo가 호이스팅 되지 않았다면 참조 에러는 발생하지 않고 1이 출력될 것이다. 하지만 호이스팅이 되기 때문에 블록 안의 foo에 접근하고 이 foo에는 아무런 값도 할당되지 않았기 때문에 참조 에러가 발생한다.
const foo = 1;
{
console.log(foo); // ReferenceError: foo is not defined
const foo = 2;
}
const name = 'Jessie';
const obj = {
age: 21,
name,
getName() {
return this.name;
}
};
위의 코드는 아래의 코드와 동일하다고 보면 된다.
const name = 'Jessie';
const obj = {
age: 21,
name: name,
getName: function getName() {
return this.name;
}
};
단축 속성명은 디버깅할 때도 유용하게 사용된다.
const name = 'Jessie';
const age = 20;
console.log(name, age); // Jessie 20
console.log({ name, age }); // { name: 'Jessie', age: 20 }
function makeObj1(key, value) {
const obj = {};
obj[key] = value;
return obj;
}
function makeObj2(key, value) {
return { [key]: value };
}
{ [key]: value }
: 객체를 만들면서 동시에 동적으로 속성 이름을 결정할 수 있다.const arr1 = [1,2,3];
const obj1 = { age: 23, name: 'Jessie' };
const arr2 = [...arr1];
const obj2 = { ...obj1 };
arr2.push(4);
obj2.age = 80;
console.log(arr1); // [1,2,3]
console.log(obj1); // [1,2,3,4]
console.log(arr2); // { age: 23, name: 'Jessie' }
console.log(obj2); // { age: 80, name: 'Jessie' };
const obj1 = { x: 1, y: 2 };
const obj2 = { ...obj1, y: 10 };
console.log(obj1); // { x: 1, y: 2 }
console.log(obj2); // { x: 1, y: 10 }
const arr = [1, 2];
const [a, b] = arr; // 비구조화 문법
console.log(a); // 1
console.log(b); // 2
let a, b;
[a, b] = [1, 2];
const arr = [1];
const [a = 10, b = 20] = arr;
console.log(a); // 1
console.log(b); // 20
let a = 1;
let b = 2;
[a, b] = [b, a];
console.log(a); // 2
console.log(b); // 1
const obj = { age: 21, name: 'Jessie' };
const { age, name } = obj;
const { name, age } = obj;
const { a, b } = obj;
const person = null;
const name = person.name; // TypeError: Cannot read property 'name' of null
const person = null;
const name = person && person.name;
const name2 = person?.name; // Optional Chaining
person?.name
: 자동으로 person을 검사해준다.(person === null || person === undefined) ? undefined : person.name
와 동일한 역할을 한다.const person = {
getName: () => 'abc',
};
const name = person.getName?.();
console.log(name); // abc
person
의 속성으로 getName
이 존재하지 않을 경우, console.log(name)
값으로 undefined
가 출력된다.function loadData(onComplete) {
console.log('loading...');
onComplete?.();
}
loadData();
const person = { friends: null, myInfo: null };
const firstFriend = person.friends?.[0];
const prop = 'name';
const name = person.myInfo?.[prop];
const person = {};
const name = person?.friends?.[0]?.mother?.name ?? 'default name';