Strict Mode
function foo() {
x = 10;
}
foo();
console.log(x); // ?
전역 스코프에도 x 변수의 선언이 존재하지 않기 때문에 ReferenceError를 발생시킬 것 같지만 자바스크립트 엔진은 암묵적으로 전역 객체에 x 프로퍼티를 동적 생성
→ 전역 객체의 x 프로퍼티는 마치 전역 변수처럼 사용 가능
→ 암묵적 전역(implicit global)이라고 함
→ 오류를 발생시키는 원인이 될 가능성이 큼
ES5부터 strict mode(엄격 모드)가 추가
→ 자바스크립트 언어의 문법을 좀 더 엄격히 적용하여 오류를 발생시킬 가능성이 높거나 자바스크립트 엔진의 최적화 작업에 문제를 일으킬 수 있는 코드에 대해 명시적인 에러를 발생시킨다.
(ESLint 같은 린트 도구를 사용해도 strict mode와 유사한 효과를 얻을 수 있다)
strict mode의 적용
strict mode를 적용하려면 전역의 선두 또는 함수 몸체의 선두에 ‘use strict’;를 추가
'use strict';
function foo() {
x = 10; // ReferenceError: x is not defined
}
foo();
전역에 strict mode를 적용하는 것은 피하자
전역에 적용한 strict mode는 스크립트 단위로 적용
스크립트 단위로 적용된 strict mode는 다른 스크립트에 영향을 주지 않고 해당 스크립트에 한정되어 적용됨
strict mode 스크립트와 non-strict mode 스크립트를 혼용하는 것은 오류를 발생시킬 수도 있다.
즉시 실행 함수로 스크립트 전체를 감싸서 스코프를 구분하고 즉시 실행 함수의 선두에 strict mode를 적용한다.
// 즉시 실행 함수의 선두에 strict mode 적용
(function () {
'use strict';
// Do something...
}());
함수 단위로 strict mode를 적용하는 것도 피하자
함수 단위로 strict mode 적용 가능
어떤 함수는 strict mode를 적용하고, 어떤 함수는 strict mode를 적용하지 않는 것은 바람직하지 않다.
→ strict mode는 즉시 실행 함수로 감싼 스크립트 단위로 적용하는 것이 바람직
strict mode가 발생시키는 에러
1. 암묵적 전역
선언하지 않은 변수를 참조하면 ReferenceError가 발생
(function () {
'use strict';
x = 1;
console.log(x); // ReferenceError: x is not defined
}());
2. 변수, 함수, 매개변수의 삭제
delete 연산자로 변수, 함수, 매개변수를 삭제하면 SyntaxError가 발생
3. 매개변수 이름의 중복
중복된 매개변수 이름을 사용하면 SyntaxError가 발생
4. with 문의 사용
with 문은 전달한 객체를 스코프 체인에 추가함.
with 문은 동일한 객체의 프로퍼티를 반복해서 사용할 때 객체 이름을 생략할 수 있어서 코드가 간단해지는 효과 O
→ 그러나 성능, 가독성 나빠지는 문제
→ with 문은 사용하지 않는 것이 좋다.
strict mode 적용에 의한 변화
1. 일반 함수의 this
strict mode에서 함수를 일반 함수를 호출하면 this에 undefined가 바인딩
→ 생성자 함수가 아닌 일반 함수 내부에서는 this를 사용할 필요가 없기 때문
→ 에러 발생x
(function () {
'use strict';
function foo() {
console.log(this); // undefined
}
foo();
function Foo() {
console.log(this); // Foo
}
new Foo();
}());
2. arguments 객체
strict mode에서 매개변수에 전달된 인수를 재할당하여 변경해도
arguments 객체에 반영x
(function (a) {
'use strict';
// 매개변수에 전달된 인수를 재할당하여 변경
a = 2;
// 변경된 인수가 arguments 객체에 반영x
console.log(arguments); // { 0: 1, length: 1}
}(1));
빌트인 객체
자바스크립트 객체의 분류
표준 빌트인 객체
- 표준 빌트인 객체는 ECMAScript 사양에 정의된 객체를 말하며, 애플리케이션 전역의 공통 기능을 제공
- 표준 빌트인 객체는 자바스크립트 실행 환경과 관계없이 언제나 사용 가능
- 표준 빌트인 객체는 전역 객체의 프로퍼티로서 제공 → 별도의 선언 없이 전역 변수처럼 언제나 참조 가능
호스트 객체
- 호스트 객체는 ECMAScript 사양에 정의되어 있지 않지만 자바스크립트 실행 환경에서 추가로 제공하는 객체
- 브라우저 환경에서는 DOM, BOM, Canvas, XMLHttpRequest 등 클라이언트 사이드 Web API를 호스트 객체로 제공
- Node.js 환경에서는 Node.js 고유의 API를 호스트 객체로 제공
사용자 정의 객체
- 사용자가 직접 정의한 객체
표준 빌트인 객체
자바스크립트는 Object, String, Number…등 40여 개의 표준 빌트인 객체 제공
Math, Reflect, JSON을 제외한 표준 빌트인 객체는 모두 인스턴스를 생성할 수 있는 생성자 함수 객체
생성자 함수 객체인 표준 빌트인 객체: 프로토타입 메서드와 정적 메서드 제공
생성자 함수 객체가 아닌 표준 빌트인 객체: 정적 메서드만 제공
표준 빌트인 객체인 String, Number, Boolean, Function, Array, Date는 생성자 함수로 호출하여 인스턴스 생성 가능
// String 생성자 함수에 의한 String 객체 생성
const strObj = new String('Lee'); // String {"Lee"}
console.log(typeof strObj); // object
생성자 함수인 표준 빌트인 객체가 생성한 인스턴스의 프로토타입은 표준 빌트인 객체의 prototype 프로퍼티에 바인딩된 객체
// String 생성자 함수에 의한 String 객체 생성
const strObj = new String('Lee'); // String {"Lee"}
// String 생성자 함수를 통해 생성한 strObj 객체의 프로토타입은
// String.prototype이다.
console.log(Object.getPrototypeOf(strObj) === String.prototype) ;; // true
표준 빌트인 객체는 인스턴스 없이도 호출 가능한 빌트인 정적 메서드 제공
// Number 생성자 함수에 의한 Number 객체 생성
const numObj = new Number(1.5); // Number {1.5}
// toFixed는 Number.prototype의 프로토타입 메서드
// Number.prototype.toFixed는 소수점 자리를 반올림하여 문자열로 반환
console.log(numObj.toFixed()); // 2
// isInteger는 Number의 정적 메서드
// Number.isInteger는 인수가 정수인지 검사하여 그 결과를 Boolean으로 반환
console.log(Number.isInteger(0.5)); // false
원시값과 래퍼 객체
원시값이 있는데도 String, Nmber 등의 표준 빌트인 생성자 함수가 존재하는 이유는?
원시값은 객체가 아니므로 프로퍼티나 메서드를 가질 수 없는데도 원시값인 문자열이 마치 객체처럼 동작
const str = 'hello';
// 원시 타입인 문자열이 프로퍼티와 메서드를 갖고 있는 객체처럼 동작
console.log(str.length); // 5
console.log(str.toUpperCase()); // HELLO
원시값에 대해 마치 객체처럼 마침표 표기법으로 접근하면 자바스크립트 엔진이 일시적으로 원시값을 연관된 객체로 변환해줌
래퍼 객체 : 문자열, 숫자, 불리언 값에 대해 객체처럼 접근하면 생성되는 임시 객체
const str = 'hi';
// 원시 타입인 문자열이 래퍼 객체인 String 인스턴스로 변환
console.log(str.length); // 2
console.log(str.toUpperCase()); // HI
// 래퍼 객체로 프로퍼티에 접근하거나 메서드를 호출한 후
// 다시 원시값으로 되돌림
console.log(typeof str);
그 후 래퍼 객체의 처리가 종료되면 래퍼 객체의 [[StringData]] 내부 슬롯에 할당된 원시값으로 원래의 상태, 즉 식별자가 원시값을 갖도록 되돌리고 래퍼 객체는 가비지 컬렉션의 대상이 됨
null과 undefined는 래퍼 객체 생성 x
→ 객체처럼 사용하면 에러가 발생
전역 객체
코드가 실행되기 이전 단계에 자바스크립트 엔진에 의해 어떤 객체보다도 먼저 생성되는 특수한 객체이며, 어떤 객체에도 속하지 않은 최상위 객체
브라우저 환경에서는 window(or self, this, frames)가 전역 객체를 가리키지만 Node.js 환경에서는 global이 전역 객체를 가리킴
(globalThis는 표준 사양이므로 ECMAScript 표준 사양을 준수하는 모든 환경에서 사용 가능)
전역 객체는 계층적 구조상 어떤 객체에도 속하지 않은 모든 빌트인 객체(표준 빌트인 객체와 호스트 객체)의 최상위 객체
전역 객체는 개발자가 의도적으로 생성x
→ 전역 객체를 생성할 수 있는 생성자 함수 제공x
전역 객체의 프로퍼티를 참조할 때 window(or global)을 생략 가능
전역 객체는 Object,String,Number, …등 모든 표준 빌트인 객체를 프로퍼티로 가지고 있음
자바스크립트 실행 환경에 따라 추가적으로 프로퍼티와 메서드를 가짐.
브라우저 환경: DOM, BOM, Canvas, … 등 클라이언트 사이드 Web API를 호스트 객체로 제공
Node.js 환경: Node.js 고유의 API를 호스트 객체로 제공
var 키워드로 선언한 전역 변수와 선언하지 않은 변수에 값을 할당한 암묵적 전역, 그리고 전역 함수는 전역 개게의 프로퍼티가 됨
브라우저 환경의 모든 자바스크립트 코드는 하나의 전역 객체 window를 공유
빌트인 전역 프로퍼티
전역 객체의 프로퍼티
Infinity 프로퍼티: 무한대를 나타내는 숫자값 Infinity
NaN 프로퍼티: 숫자가 아님(Not-a-Number)을 나타내는 숫자값 NaN
undefined 프로퍼티: 원시 타입 undefined
빌트인 전역 함수
애플리케이션 전역에서 호출할 수 있는 빌트인 함수로서 전역 객체의 메서드
eval 함수
- eval 함수는 기존의 스코프를 런타임에 동적으로 수정
- eval 함수의 사용을 금지해야 한다.
isInfinite 함수
- 전달받은 인수가 정상적인 유한수인지 검사하여 유한수이면 true 반환
- 무한수이면 false반환
- 전달받은 인수의 타입이 숫자가 아닌 경우, 숫자로 타입을 변환 후 검사 수행
- 인수가 NaN으로 평가되는 값이라면 false 반환
isNaN 함수
- 전달받은 인수가 NaN인지 검사하여 그 결과를 불리언 타입으로 반환
- 전달받은 인수의 타입이 숫자가 아닌 경우 숫자로 타입을 변환 후 검사 수행
parseFloat 함수
전달받은 문자열 인수를 부동 소수점 숫자, 즉 실수로 해석하여 반환
- 공백으로 구분한 문자열은 첫 번째 문자열만 변환
- 앞뒤 공백은 무시
parseInt 함수
전달받은 문자열 인수를 정수로 해석하여 반환
- 두 번째 인수로 진법을 나타내는 기수 전달
// '10'을 2진수로 해석하고 그 결과를 10진수 정수로 반환
parseInt('10' , 2); // -> 2
기수를 지정하여 10진수 숫자를 해당 기수의 문자열로 변환하여 반환하고 싶을 때는 Number.prototype.toString 메서드를 사용
const x = 15;
// 10진수 15를 2진수로 변환하여 그 결과를 문자열로 변환
x.toString(2); // -> '1111'
// 문자열 '1111'을 2진수로 해석하고 그 결과를 10진수 정수로 반환
parseInt(x.toString(2), 2); // -> 15
encodeURI / decodeURI 함수
완전한 URI를 문자열로 전달받아 이스케이프 처리를 위해 인코딩
- URI: 인터넷에 있는 자원을 나타내는 유일한 주소
- 인코딩: URI의 문자들을 이스케이프 처리하는 것
- 이스케이프 처리: 네트워크를 통해 정보를 공유할 때 어떤 시스템에서도 읽을 수 있는 아스키 문자 셋으로 변환하는 것
decodeURI 함수는 인코딩된 URI를 인수로 전달받아 이스케이프 처리 이전으로 디코딩 함
encodeURIComponent / decodeURIComponent 함수
- encodeURIComponent 함수는 URI 구성 요소를 인수로 전달받아 인코딩
- decodeURIComponent 함수는 매개변수로 전달된 URI 구성 요소를 디코딩
암묵적 전역
선언하지 않은 식별자에 값을 할당하면 전역 객체의 프로퍼티가 된다.
전역 변수가 아니므로 호이스팅이 발생하지 않는다.
단지 프로퍼티이므로 delete 연산자로 삭제 가능
'Modern JS Deep Dive' 카테고리의 다른 글
[JS Deep Dive] 27장 정리 - 배열에 관하여 (2) | 2024.11.27 |
---|---|
[JS Deep Dive] 24, 25, 26장 정리 - 클로저, 클래스, ES6 함수의 추가 기능에 관하여 (0) | 2024.11.17 |
[JS Deep Dive] 19장 정리 - 프로토타입에 대하여 (28) | 2024.10.07 |
[JS Deep Dive] 17, 18장 정리 - 생성자 함수에 의한 객체 생성 | 함수와 일급 객체에 대하여 (31) | 2024.10.07 |
[JS Deep Dive] 15,16장 정리 - let, const 키워드와 블록 레벨 스코프 | 프로퍼티 어트리뷰트에 대하여 (32) | 2024.10.07 |