0. Javascript 자료형

Javscript의 데이터 타입 종류

위와 같은 자바스크립트 데이터 타입이 다양하게 있다.

Javascript 배열을 보고, 생김새는 유사 C언어 같기도 하여 혹시나하는 의문이 생겼다.

이를 하나의 배열에 넣을 수 있는가? 그리고 그것을 출력할 수 있는가? 에 대한 의문이다.

 

1. Javscript 배열 소스

<html>
    <head>
        <title>Javascript Array Test</title>
    </head>
    <body>
        <!-- No Body Data -->
    </body>

    <script>
        var a = [];
        var i = 0;

        a.push("Data1");
        a.push(1);
        a.push(true);
        a.push(null);

        for(i; i<a.length; i++)
        {
            document.write(a[i] + "    " + typeof(a[i]) + "<br>");
        }
    </script>
</html>

 

위와 같이 String, Number, Boolean, Null 데이터 타입의 값을 하나의 배열에 넣어주도록 하고, 이를 출력해보았다.

 

2. 결과

결과 출력 모습

보아하니 하나의 배열에도 잘 들어가는 것 같다.

 

자바스크립트의 반복문은 while, do while, for, for in문으로 총 네 가지가 있습니다.

특성은 C 언어와 python과 비슷합니다.


while문

var value = 0;
while(value < 5) {
    alert('No.' + value);
    value++;
}


while문은 C언어와 거의 같다고 보시면 될 것 같습니다.


do while문

var value = 0;
do {
    alert('No.' + value);
    value++;
} while(value < 5);


do while문도 마찬가지로 C언어와 거의 같은 형태를 보이고 있습니다.


for문

var array = ['1', '2', '3', '4'];

for(var i=0; i<array.length; i++) {
    alert(array[i]);
}


여기서 특이한 점이 array의 길이를 .length를 통해 표현하고 있습니다.

리스트(배열)의 길이는 .length를 통해 설정할 수 있습니다.


for in문

var array = ['1', '2', '3', '4'];
 
for(var i in array) {
    alert(array[i]);
}


자바스크립트는 배열이나 객체를 좀 더 쉽게 다룰 수 있도록 for in문을 제공합니다. 이는 마치 python의 형태와 유사한데, 완전히 같다고는 할 수 없습니다. 하하... 위의 예제에서 in 앞의 var i는 index를 나타내는 것이며 배열 내의 값을 나타내진 않습니다.






자바스크립트의 조건문은 if문과 switch문이 있습니다.

특성은 C언어나 다른 일반적인 언어와 비슷합니다.


if문

var date = new Date();
var hour = date.getHours();
 
if(hour < 11) {
    alert("It is Breakfast");
}
else if(hour >= 11 && hour < 15) {
    alert("It is Lunch");
}
else {
    alert("It is Dinner");
}


switch문

var input = Number(prompt('Input Your Number.', 'Number'));
 
switch(input % 2) {
    case 0:
        alert("Even!!!");
        break;
    case 1:
        alert("Odd!!");
        break;
    default:
        alert("It is not number..!");
        break;
}


삼항 연산자

var input = prompt('Input Your Number.', 'Number');
var number = Number(input);
 
(number > 0) ? alert('Natural Number') : alert('Not Natural Number');


이외에도 javascript에서는 보다 짧게 조건문을 작성해볼 수 있습니다.

다음과 같은 예제와 같습니다.


짧은 조건문

true || alert('Answer A');
false || alert('Answer B');
// || 연산 첫 번째 줄에서 Answer A는 실행되지 않고 Answer B는 실행됩니다.
 
true && alert('Answer C');
false && alert('Answer D');
// && 연산 첫 번째 줄에서 Answer C는 실행되고 Answer D는 실행되지 않습니다.


설명을 더하면, 다음과 같습니다.

1. true || alert(); 에서는 왼쪽이 이미 참이기 때문에 오른쪽 값을 확인하지 않고 넘어가버립니다.

2. false || alert(); 에서는 왼쪽이 거짓이기 때문에 오른쪽 값을 확인합니다. 따라서 alert() 함수가 실행됩니다.

3. true && alert(); 에서는 왼쪽이 참이기 때문에 오른쪽을 확인합니다.(and 연산은 둘 다 참이어야 실행됩니다.) 따라서 alert() 함수가 실행됩니다.

4. false && alert(); 에서는 왼쪽이 이미 거짓이기 때문에 오른쪽을 볼 것도 없이 이미 이 연산은 거짓이 되어 실행되지 않습니다.






자바스크립트에서 변수를 선언할 때 var, let, const 형태로 선언할 수 있습니다.


varfunction-scoped라고 함

let, constblock-scoped라고 함


여기서 function-scoped와 block-scoped가 무엇일까 알아보니 다음과 같은 내용을 볼 수 있었습니다.


01. var (function-scoped)

// var는 function-scope이기 때문에 for문이 끝난다음에 i를 호출하면 값이 출력이 잘 됨
// 이건 var가 hoisting이 되었기 때문이다.
for(var j=0; j<10; j++) {
  console.log('j', j)
}
console.log('after loop j is ', j) // after loop j is 10


// 아래의 경우에는 에러가 발생한다.
function counter () {
  for(var i=0; i<10; i++) {
    console.log('i', i)
  }
}
counter()
console.log('after loop i is', i) // ReferenceError: i is not defined


여기서 hoisting이라는 말이 나오는데.. (처음에 hosting이라고 착각함 ㅎㅎ....)

이건 또 무슨 말이고 하니.. 요약하자면 "후선언된 변수나, 함수들이 해당 Scope에서 최상위에 위치하는 걸 뜻함"이라고 합니다.

대충 선언 부분이 잘못되도 자바스크립트에서는 이를 올바르게 코딩된 것처럼 인식한다는 뜻인데, 이는 다음 포스트에서 다루도록 하겠습니다.


위에서 나타난 에러처럼 ReferenceError 즉, 선언이 안 되었다는 에러가 나타납니다.

간단히 이해하기 위해 다음과 같이 코드를 바꿀 수 있습니다.


// var는 function-scope이기 때문에 for문이 끝난다음에 i를 호출하면 값이 출력이 잘 됨
// 이건 var가 hoisting이 되었기 때문이다.
var j=0;
for(j=0; j<10; j++) {
  console.log('j', j)
}
console.log('after loop j is ', j) // after loop j is 10


// 아래의 경우에는 에러가 발생한다.
function counter () {
  var i=0;
  for(i=0; i<10; i++) {
    console.log('i', i)
  }
}
counter()
console.log('after loop i is', i) // ReferenceError: i is not defined
//--> i는 counter 함수의 지역변수이기 때문임


위와 같이 지역변수의 느낌으로 이해하면 쉽게 와닿을 수 있습니다.


자바스크립트에서는 immediately-invoked function expression( or IIFE, pronounced "iffy")라는 것이 있다고 합니다..

무슨 말인지 알아먹기 힘든 영어로 되어있지만 예시를 통해 알아보도록 합시다.


다음은 IIFE로 function-scope처럼 만들 수 있는 예시입니다.


IIFE function-scope 예시(1)

// IIFE를 사용하면
// i is not defined가 뜬다.
(function() {
  // var 변수는 여기까지 hoisting이 된다.
  for(var i=0; i<10; i++) {
    console.log('i', i)
  }
})()
console.log('after loop i is', i) // ReferenceError: i is not defined


위의 소스코드를 보면 소괄호로 묶어 마치 하나의 함수처럼 만들어준 것처럼 보입니다.

hoisting이 되는 위치도 웃긴 게, function 내부에 되어버리게 되어, 결국 function 밖에서 실행할 때 사용되는 i의 값은 undefined 변수가 되어버리게 됩니다.

에러가 나지 않도록 작성한 코드는 다음과 같습니다.


IIFE function-scope 예시(2) - hoisting

// 이 코드를 실행하면 에러없이 after loop i is 10이 호출된다.
(function() {
  for(i=0; i<10; i++) {
    console.log('i', i)
  }
})()
console.log('after loop i is', i) // after loop i is 10


위의 소스코드가 에러가 나지 않는 이뉴는 i를 function 내에서 다시 재정의하지 않아서 hoisting이 이루어졌다는 의미입니다.

즉, i 함수는 function 밖에서 선언된 전역(global) 변수라는 것입니다.


이러한 hoisting을 방지하기 위해서는 use strict라는 것을 사용할 수 있습니다.

밖에서 사용한 전역변수가 함수 내에서 hoisting 되지 않도록 방지하는 것입니다.


IIFE function-scope 예시(2) - use strict

// 아까랑 다르게 실행하면 i is not defined라는 에러가 발생한다.
var i;
(function() {
  'use strict'
  for(i=0; i<10; i++) {
    console.log('i', i)
  }
})()
console.log('after loop i is', i) // ReferenceError: i is not defined


위의 소스코드는 밖에서 선언된 var i의 값이 hoisting되지 않았기 때문에, i의 값에는 아무런 값이 들어가 있지 않습니다.

따라서 정상적으로 에러를 출력하는 걸 볼 수 있습니다.


변수 하나에 너무나 많은 고민이 들어가게 됩니다. 허허...

이러한 수고를 덜어주기 위해 등장한 것이 바로 let과 const라고 할 수 있습니다.


02. let, const (block-scoped)

자바스크립트에는 var만 존재했을 때 다음과 같은 문제가 있었다고 합니다.

// 이미 만들어진 변수이름으로 재선언했는데 아무런 문제가 발생하지 않는다.
var a = 'test'
var a = 'test2'

// hoisting으로 인해 ReferenceError에러가 안난다.
c = 'test'
var c


위와 같은 문제점으로 인해 자바스크립트를 욕하는 사람이 많았다고 합니다.. ㅎㅎ

하지만 let과 const를 사용하면 var를 사용할 때보다 훨씬 편리하게 코드를 작성할 수 있게 되었다고 합니다.


이 두 가지 형태는 변수의 재선언이 불가능하다는 공통점이 있습니다.(마치 C언어의 #define과 const의 느낌이 아닐까 싶습니다.)


let은 변수에 재할당이 가능하지만, const는 재선언, 재할당이 모두 불가능합니다.


// let
let a = 'test'
let a = 'test2' // Uncaught SyntaxError: Identifier 'a' has already been declared
a = 'test3'     // 가능

// const
const b = 'test'
const b = 'test2' // Uncaught SyntaxError: Identifier 'a' has already been declared
b = 'test3'    // 불가능 Uncaught TypeError:Assignment to constant variable.


이때 let과 const에 hoisting이 발생하지 않는 건 아닙니다.

만약 var가 function-scoped로 hoisting 되었다면 let과 const는 block-scoped로 hoisting이 일어나게 됩니다.


d = "test"
var d; // hoisting이 되어 에러가 나지 않음

/* javascript가 인식할 때 다음과 같이 인식됨
var d;
d = "test";
자기 알아서 순서가 바뀐 채로 인식됨 ㄷㄷ*/

c = 'test' // ReferenceError: c is not defined
let c;


c가 에러가 나는 이유는 let의 특징인 tdz(temporal dead zone) 때문입니다.

이는 let으로 선언된 변수는 값을 할당하기 전에 변수가 먼저 선언되어 있어야 합니다.(위의 4 ~ 6번째 라인과 같은 hoisting이 일어나지 않음)


이는 const도 예외가 아닙니다. 단지 let보다 좀 더 업격할 뿐...


// let은 선언하고 나중에 값을 할당이 가능하지만
let dd
dd = 'test'

// const 선언과 동시에 값을 할당 해야한다.
const aa // Missing initializer in const declaration


자바스크립트에 tdz와 같은 기능이 필요한 이유는 동적언어이다보니 runtime type check가 필요해서라고 합니다.




+ Recent posts