1. 글에 대해
- 모든 결과는 Chrome 브라우저를 통해 테스트된 결과입니다.
2. const 키워드
- const 키워드는 let 키워드와 유사한 언어 매커니즘을 가지고있다.
3. ES5 & const
-
Object.defineProperty or create 메서드를 통해, 읽기전용 속성을 생성할 수 있다(단 일반적인 방법으로 (속성)값을 재 할당시 const 키워드와 같은 예외가 발생하지는 않는다)
// global ec // globalEC.VO 객체에 읽기 전용 속성을 생성한다.(이떄 생성된 a 속성은 변수가 아니다) Object.defineProperty(this, 'a', { writable: false, value: 1 }); // VO 객체의 a 속성 값을 변경한다. a = 2; // 읽기 전용 속성으로 값이 변경되지않는다. console.log(a); // 1 // writable 속성의 기본값은 false 이며, 반드시 속성을 정의할 필요는 없다. Object.defineProperty(this, 'b', { // writable: false, value: 1 }); // VO 객체의 b 속성 값을 변경한다. b = 2; // 읽기 전용 속성으로 값이 변경되지않는다. console.log(b); // 1 // global ec (function A(){ // A function ec // AO 객체는 직접 접근할 수 없다. 즉 AO 객체의 읽기 전용 속성을 생성할 수 없다는 단점이 존재한다. // 하지만 ES6 의 const 키워드를 통해서는 생성 가능하다. const a = 1; console.log(a); // 1 })(); // obj 객체에 읽기 전용 속성 생성하기 var obj = {}; // Object.defineProperty 메서드를 통해 생성하는 방법은 아래와 같다. Object.defineProperty(obj, 'x', { writable: false, value: 1 }); // 속성값을 변경한다 obj.x = 2; // 읽기 전용 속성으로 값이 변경되지않는다. console.log(obj.x); // 1 // Object.create 메서드를 통해 생성하는 방법은 아래와 같다. var obj2 = Object.create(Object.prototype, { x: { writable: false, value: 1 } }); // 속성값을 변경한다 obj2.x = 2; // 읽기 전용 속성으로 값이 변경되지않는다. console.log(obj2.x); // 1 // 인스턴스의 속성을 읽기 전용으로 초기화하는 방법은 아래와 같다. function A(){ if (!(this instanceof A)) return; // 읽기 전용 Object.defineProperty(this, 'x', { writable: false, value: 1 }); // 읽기/쓰기 Object.defineProperty(this, 'y', { writable: true, value: 1 }); } // 새로운 인스턴스를 생성한다. var newAObject = new A; // 생성된 인스턴스의 속성값을 변경한다 newAObject.x = 2; // 생성된 인스턴스의 속성값을 변경한다 newAObject.y = 2; // 읽기 전용 속성으로 값이 변경되지않는다. console.log(newAObject.x); // 1 // 읽기/쓰기 속성이며, 변경된 값인 2를 반환한다. console.log(newAObject.y); // 2
-
Object.defineProperty 메서드를 통해, 읽기 전용 속성을 재 정의 시, 재 정의대한 예외가 발생하게된다.
Object.defineProperty(this, 'a', { writable: false, value: 1 }); // 단 Object.defineProperty 메서드를 통해 읽기 전용 속성을 재 정의 시, 재 정의에 대한 예외가 발생하게된다. try{ Object.defineProperty(this, 'a', { writable: false, value: 2 }); } catch(e){ // Cannot redefine property: a console.log(e.message); }
4. ES6 & const
- const 키워드를 통해 선언된 상수는, 블럭 범위의 Isolated Scope(격리된 유효범위) 를 갖게된다.
{
// block scope
// const 키워드를 통한 변수 선언
const a = 1;
}
if (true){
const b = 2;
}
switch (1){
case 1:
const c = 3;
break;
}
for (var d = 0; d < 3; d++){
const _d = d;
console.log(_d); // 0, 1, 2
}
const e = 4;
try {
// 실행 코드 처리 시, 블록 범위에 선언된 a 상수는 선언되지 않았다는 예외가 발생하게 된다.
console.log(a);
}
catch(e){
// a is not defined
console.log(e.message);
}
try {
// 실행 코드 처리 시, 블록 범위에 선언된 b 상수는 선언되지 않았다는 예외가 발생하게 된다.
console.log(b);
}
catch(e){
// b is not defined
console.log(e.message);
}
try {
// 실행 코드 처리 시, 블록 범위에 선언된 c 상수는 선언되지 않았다는 예외가 발생하게 된다.
console.log(c);
}
catch(e){
// c is not defined
console.log(e.message);
}
try {
// 실행 코드 처리 시, 블록 범위에 선언된 d 상수는 선언되지 않았다는 예외가 발생하게 된다.
console.log(_d);
}
catch(e){
// _d is not defined
console.log(e.message);
}
console.log(e); // 4
- const 키워드를 통해 선언된 상수의 유효 범위는 자신을 포함한 블럭 및 그 내부 블럭까지 유효하다.
{
const a = 1;
{
const b = 2;
{
const c = 3;
{
const d = 4;
// 선언된 상수의 유효 범위는 자신을 포함한 블럭 및 그 내부 블럭까지 유효하다
console.log(a, b, c, d); // 1, 2, 3, 4
}
}
}
console.log(a); // 1;
// 해당 블럭 Scope 에서는 b 상수에 접근할 수 없다.
try{
console.log(b);
}
catch(e){
// b is not defined
console.log(e.message);
}
}
- 동일 블럭 범위에서, 동일한 식별자 이름으로 상수를 재 선언시 예외가 발생하게된다.
// 동일 블럭 범위에서, 동일한 식별자 이름으로 변수를 재 선언시, 아래와 같은 예외가 발생하게된다.
const a = 1;
// Uncaught SyntaxError: Identifier 'a' has already been declared
const a = 2;
const obj = {};
const obj = {}; // Uncaught SyntaxError: Identifier 'obj' has already been declared
{
const b = 1;
// Uncaught SyntaxError: Identifier 'b' has already been declared
const b = 2;
}
if (true){
const i = 1;
const i = 2; // Uncaught SyntaxError: Identifier 'i' has already been declared
}
(function A(){
const c = 1;
const c = 2; // Uncaught SyntaxError: Identifier 'c' has already been declared
})();
// 다른 식별자 이름으로 선언 시 예외가 발생하지 않는다.
{
const c = 1;
const d = 2;
console.log(d); // 2
}
- const 키워드를 통해 선언된 상수 값을 재 할당 시 예외가 발생하게 된다.
const a = 1;
// Uncaught TypeError: Assignment to constant variable.
a = 2;
// 당연한 말이겠지만, 선언된 obj 객체의 속성까지 상수 범위가 적용되지는않는다.
const obj = {x: 1};
// x 속성은 읽기/쓰기 속성으로 선언되어있다.
// Object {value: 1, writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(obj, 'x'));
obj.x = 2;
console.log(obj.x); // 2
- const 키워드를 통해 선언된 상수는 EC 진입 및 실행 코드 처리 후에도 VO 의 새로운 속성으로 추가되지않는다..
// global ec 진입 시 VO 의 새로운 속성으로 추가되지않는다.
try {
console.log(a); // a is not defined
}
catch(e){
console.log(e.message);
}
const a = 1;
// 할당된 값을 반환한다.
console.log(a); // 1
// 실행 코드 처리후에도 VO 의 새로운 속성으로 추가되지않는다.
console.log(window.a); // undefined
- 동일 VO(AO) 범위에서, 동일한 식별자 이름으로 변수(or 함수) 선언 시 예외가 발생하게 된다.(단 const 키워드를 통해 선언된 변수는 VO 의 속성으로 추가되지않는다)
// 테스트 1
// global ec
const a = 1;
// globalEC.VO.a
var a; // Uncaught SyntaxError: Identifier 'a' has already been declared
// 테스트 2
// global ec
const a = 1;
{
// globalEC.VO.a
var a; // Uncaught SyntaxError: Identifier 'a' has already been declared
}
// 테스트 3
// global ec
const a = 1;
if (true){
// globalEC.VO.a
var a; // Uncaught SyntaxError: Identifier 'a' has already been declared
}
// 테스트 4
// global ec
const a = 1;
// globalEC.VO.a
// Uncaught SyntaxError: Identifier 'a' has already been declared
function a(){
// a function ec
}
// 테스트 5
// global ec
const a = 1;
(function A(){
// A function ec
// 이 경우 a 변수는 globalEC.VO 의 속성으로 추가되며, 마찬가지로 예외가 발생하게된다.
a; // Uncaught SyntaxError: Identifier 'a' has already been declared
})();
// 테스트 6
// global ec
(function A(){
// function ec
const a = 1;
// 이 경우 a 변수는 AFunctionEC.AO 의 속성으로 추가되며, 마찬가지로 예외가 발생하게된다.
var a;
})();
// 테스트 7
// global ec
const a;
(function A(){
// A function ec
// 이 경우 a 변수는 AFunctionEC.AO 의 속성으로 추가되며, 예외가 발생하지않는다.
var a;
console.log(a); // undefined
})();
- 루프(for, while 등)문 내부에서 (const 키워드를 통해)선언된 변수는, 비동기 함수안에서 각기 다른 상수를 참조하게된다.(즉 각 루프는 서로 다른 상수(값)를 가지게 된다)
// global scope
for (var i = 0; i < 10; i++) {
// block scope
// 루프문 내부에 const 키워드를 통해 선언된 상수
const _i = i;
window.setTimeout(function() {
// 이 경우 _i 상수는 각기 다른 상수 값을 참조하게된다.
console.log(_i); // 0 ~ 9
// var 키워드를 통해 선언된 i 변수는, 함수 Scope Chain 매커니즘에 의해 최종 증감값인 10을 참조하게된다.
console.log(i); // 10
});
}
console.log(i); // 10;
var i = 4;
while (i) {
// block scope
const _i = i;
// const 키워드를 통해 상수를 선언한다.
window.setTimeout(function() {
// 이 경우 _i 상수는 각기 다른 변수 값을 참조하게된다.
console.log(_i); // 4 ~ 1
});
i--;
}
// ES5 를 통한 구현은 아래와 같다.
for (var i = 0; i < 10; i++){
// 루프 순회 시 (읽기 전용 속성)재 정의에 대한 예외가 발생하게 된다.
// Uncaught TypeError: Cannot redefine property: _i
Object.defineProperty(this, '_i', {
writable: false,
value: i
});
window.setTimeout(function(){
console.log(_i); // 0 ... error
});
}
- eval 함수를 통해, 선언된 상수는 local sandbox 안에서 평가된다.
eval('const i = 1');
try{
i;
}
catch(e){
console.log(e.message); // i is not defined
}