scope
: 어떤 변수들에 접근할 수 있는지 정의한 범위var
: 함수 스코프let
const
: 블록 스코프원시 타입(Primitive Type)
과 객체(참조형)
으로 나뉜다.number
string
boolean
null
undefined
Symbol
Bigint
Number.isNaN()
메서드를 사용해 판별하자.a = 3 - 'a';
console.log(a === a); // false
console.log(Number.isNaN(a)); // true
숫자의 범위는 Number.MAX_SAFE_INTEGET
와Number.MIN_SAFE_INTEGET
사이로 정의하는 것이 좋다. 이 범위를 넘어선 숫자의 연산은 부정확할 수 있다. 이 문제를 해결하려면 ES2020에서 새로 등장한 BigInt
타입을 사용하자.
심볼은 ES2015에서 도입된 원시 타입
이다. 데이터의 유일함을 나타낼 때 사용하며, 생성된 심볼은 다른 어떤 심볼과도 일치하지 않는다. 심볼은 객체가 아닌 원시 타입이기 때문에 new 키워드를 사용해 생성할 수 없다.
const sym1 = Symbol('key');
const sym2 = Symbol('key');
console.log(sym1 === sym2) // false
전역 심볼
: 전역 심볼을 생성해 매번 새로운 심볼을 생성하지 않고 기존 심볼을 검색해 사용하기도 한다. Symbol.for()
메서드를 사용하여 전역 심볼을 생성한다. 다른 라이브러리들과 충돌을 피하도록 prefix를 사용해 구분하자.심볼은 객체나 클래스에서 유일한 프로퍼티를 만들 때 사용한다. 프로퍼티를 만들면 유일함이 보장되어 프로퍼티 추가 시 충돌을 방지한다. 또한 외부에서 직접 해당 프로퍼티에 접근할 수 없어 의도치 않은 프로퍼티 변경을 막을 수 있다.
사실 심볼로 정의한 프로퍼티를 수정할 방법이 있다. getOwnPropertySymbols()
메서드로 심볼 키 값을 얻어와서 갱신할 수 있지만 지양하길 바란다.
만약 객체에 프로퍼티가 존재하지 않는다면 새로운 프로퍼티가 추가되고, 있다면 기존 프로퍼티 값이 갱신된다.
어떤 프로퍼티에 접근할 때마다 동적인 계산이 필요하거나, 프로퍼티 값이 변경될 때마다 별도의 처리 코드가 필요하다면 어떨까?
이럴 때 getter
와 setter
접근자 프로퍼티를 사용해 일반 프로퍼티처럼 사용할 수 있다.
접근자 프로퍼티의 값에 접근하면 getter 메서드가 호출되며 이 메서드의 반환 값이 접근 표현식의 결괏값이다. 만약 접근자 프로퍼티의 값을 변경하려고 하면 setter 메서드가 호출된다.
접근자 프로퍼티는 프로퍼티의 값을 갱신할 때 유효성을 검증하거나, 조건에 따라 다른 값을 변환하는 작업들을 할 때 많이 사용한다.
const obj = {
myName: 'javascript',
set name(name) {
if (name != null) {
this.myName = name;
}
},
get name() {
return this.myName;
}
}
접근자 프로퍼티를 생성하는 또 다른 방법은 정적 메서드 Object.defineProperty()
를 사용하는 것이다.
이 메서드는 객체에 직접 새로운 프로퍼티를 정의하거나 이미 존재하는 프로퍼티를 수정한 후 그 객체를 반환한다.
const obj = { myName: 'javascript' };
Object.defineProperty(obj, 'name', {
set(name) {
if (name !== null) {
this.myName = name;
}
},
get() {
return this.myName;
},
writable: true, // name 프로퍼티의 수정을 허용한다
value: 'myName', // name 프로퍼티의 값을 설정한다.
});
첫 번째 인자로 대상이 되는 객체, 두 번째 인자로 추가 또는 갱신하려는 프로퍼티 명이나 심볼
마지막 인자로 프로퍼티 서술자
를 정의한 객체를 넘긴다.
프로퍼티 서술자에는 configurable
enumerable
writable
value
get
set
slice
: 배열에서 특정 범위의 원소를 복사해 새로운 배열을 생성해 반환한다.
단, 얇은 복사를 수행하기 때문에 배열의 원소가 객체이면 참조가 유지되니 주의해야 한다.
const obj = {};
const arr = [1, obj, 3];
const newArr = arr.slice(1, 2);
// slice() 메서드는 얕은 복사를 하기 때문에 배열 내의 중첩된 객체의 참조 유지
console.log(newArr[0] === obj); // true
배열을 복사하는 또 다른 방법은 펼침 연산자 (spread operator)
를 사용하는 것이다. 마찬가지로 얕은 복사를 수행한다
const arr = [1, 2, 3];
const newArr = [...arr];
console.log(newArr); // [1, 2, 3]
자바스크립트에서는 일반 객체를 배열처럼 사용할 수 있다.이러한 객체를 유사 배열 객체라고 한다. 유사 배열 객체는 length 프로퍼티로 양의 정수 값을 가진 객체여야만 한다. 대표적으로는 argements
객체이다.
argument 객체는 함수에 전달한 인자를 유사 배열 객체로 만든 데이터이다.
배열이 아닌 유사 배열 객체이기 때문에 배열의 내장 메서드를 사용할 수 없다.
function foo(a, b, c) {
console.log(arguments[0], arguments[1], arguments[2]); // 'a', 'b', 'c'
console.log(arguments.length); // 3
// 아래 코드는 TypeError가 발생한다.
arguments.forEach((arg) => {
console.log(arg)
});
}
foo('a', 'b', 'c')
TypeError가 발생할 때, 내장 메서드를 call()
또는 apply()
함수와 결합해 사용한다.
function foo(a, b, c) {
// 아래 코드는 TypeError가 발생한다.
Array.prototype.forEach.call(arguments, (arg) => {
console.log(arg)
});
}
foo('a', 'b', 'c')
자바스크립트의 모든 값은 truthy 값과 falsy 값 두 가지로 나뉜다.
false
null
undefined
NaN
''(빈 문자열)
0
0n