• [Inside JS] 1. 자바스크립트 데이터 타입과 연산자

    2019. 9. 5.

    by. 나나 (nykim)

     

     

    글과 일부 이미지의 출처는 [ 인사이드 자바스크립트(송형주, 고현준 저) ]에 있음을 밝힙니다 :-)

     

     


     

    1. 자바스크립트 기본 타입

    JS의 기본 타입으로는 숫자, 문자, 불린값, undefiend, null이 있습니다.

     

     

     

    1) 숫자

    C언어의 경우 정수냐 실수냐에 따라 int, float 등과 같이 다양한 숫자 타입이 존재합니다다. 

    반면에 JS는 느슨한 타입 체크 언어이므로 정수든 실수든 그냥 숫자 타입이죠.

     

    var num = 5/2;

     

    위의 연산을 C언어에서 할 경우 소수 버린을 버린 2만 출력됩니다 (정수랑 정수끼리니까..)

    BUT!! JS에선 2.5가 나옵니다(정수건 실수건 넌 그냥 숫자야^^)

     

     

    2) 문자열

    길이가 1개이든 길든 JS는 그냥 문자!

     

    var str = ‘test’; 
    console.log(str[0]); //출력값: t
    str[0] = P;
    console.log(str); //출력값: test. <— ??? 안 바뀜! 한 번 생성된 문자열은 읽기만 가능하고 수정은 불가능하다

     

     

    3) 불린값

    true랑 false... ㅇㅇ다 아시죠?

     

     

    4) undefiend

    = 값이 비어있음. 정확히는 값이 “할당되지 않은” 변수 타입.

    undefiend 타입 변수의 값은 곧 undefiend이므로, 이건 그냥 타입이자 값입니다.

     

     

    5) null

    일부러 변수에 null 값을 넣어 값이 비어져있음을 나타냅니다.

    주의할 점은 null 타입의 변수를 typeof해보면 object가 나온다는 거!

     

    var IamNull = null; 
    console.log( typeof IamNull ); //출력값 : object 
    console.log( typeof IamNull === null); //출력값: false 
    console.log( IamNull === null); //출력값: true

     


     

    2. JS의 객체

     

    자바스크립트에서 기본타입을 제외한 모든 값은 "객체"입니다.

    여기서 객체란, ‘이름(key): 값(value)’형태의 프로퍼티를 저장하는 일종의 컨테이너라 보면 됩니다. 

     

    기본타입 객체는 하나의 값만을 갖지만, 참조타입 객체는 여러 개의 값을 가질 수 있습니다.

    객체의 프로퍼티로 함수가 포함할 수 있으며, 이러한 함수 프로퍼티를 "메서드"라고 합니다.

     

    JS에서는 객체를 다음과 같이 생성합니다.

    (자바에서는 클래스를 정의하고, 클래스 인스턴스를 생성해야 하는데 JS는 좀 더 간단하져!)

     

     

    1) 객체를 소환하는 법 1편

     

    Object() 생성자 함수

     

    var me = new Object(); 
    me.name = ‘NY KIM’; me.gender = ‘female’; 
    me.age = 25; 
    console.log(me); //결과: { name: ‘NY KIM’, gender: ‘female’, age: 25 }

     

     

    2) 객체를 소환하는 법 2편

     

    객체 리터럴 방식 

    *literal: 문자 그대로의. 그냥 있는 그대로만 써도 객체가 뿅 나오는 JS의 강려크한 문법

     

    프로퍼티이름: 프로퍼티값으로 표현.

    프로퍼티값으로 함수가 오면 그걸 메서드라고 부릅니다.

     

    var me = { name : ‘NY KIM’, gender: ‘female’, age: 25 };

     

     

    3) 객체에 접근하는 법

     

    객체에 접근하려면 다음의 두 가지 방법을 씁니다:

    []로 접근하거나, .로 접근하거나

     

    me.name
    me[‘name’]

     

     

    여기서 주의할 점!

    대괄호 접근법은, 접근하려는 프로퍼티를 문자열 형태로 만들고 대괄호로 감싸야 합니다.

    만약 me[name]과 같이 접근하면 undefiend를 퉷 뱉어내죠.

     

    또한, 프로퍼티가 표현식이거나 예약어인 경우 대괄호 접근법을 써야 합니다!

     

    me.full-name //불가. 출력값: NaN 
    me['full-name'] //가능

     

    me.full-name을 시도하면 NaN이란 값을 리턴하는데,

    이건 full(undefined)에서 name(undefiend)을 빼는 연산을 했기 때문이죠.

    undefined는 존재하지 않는 프로퍼티값에 접근할 때 출력되며, 

    NaN은 수치 연산을 해서 정상적인 값을 얻지 못할 때 출력됩니다.

     

    객체에 접근하여 값을 할당했을 때,

    해당 프로퍼티가 있으면 → 값을 갱신하고,

    해당 프로퍼티가 없으면 → 값을 할당한다

    는 걸 기억해 둡시다 :>

     

     

    4) 객체 프로퍼티 출력

     

    for ( .. in .. ) 문을 사용하면 객체의 모든 프로퍼티에 대해 루프를 수행할 수 있습니다.

     

    var me = { name : ‘NY KIM’, gender: ‘female’, age: 25 }; 
    var prop; 
    
    for (prop in me) { 
      console.log(prop, me[prop]);
    }
    
    /* 출력값: name 'NY KIM' gender 'female' age 25 */

     

     

    5) 객체의 프로퍼티 삭제하기

     

    delete 연산자를 써서 프로퍼티 삭제가 가능합니다. 단, 객체 자체를 삭제할 수는 없습니다.

     

    delete me.age; 
    console.log(me.age); //출력값: undefiend 
    
    delete me; //불가 
    console.log(me); //출력값: me

     


     

     

    3. 참조 타입의 특성

     

    1) 참조 타입의 특징

     

    객체 내의 배열이나 함수, 정규표현식 등.

    이런 참조 타입의 객체는 모든 연산이 실제 값이 아닌 참조값으로 처리됩니다.

     

    var objA = { val: 1 }; 
    var objB = objA; 
    objB.val = 99; 
    
    console.log(objA.val, objB.val) //출력: 99, 99 
    
    /* objA 변수는 객체 자체를 저장하고 있는 것이 아니라 생성된 객체를 가리키는 참조값을 저장하고 있습니다. 
    objB 변수가 가리키는 객체의 val값을 갱신하면, 변수 objA와 변수 objB가 동일한 객체를 참조하고 있으므로
    objA.val도 변하게 됩니다. */

     

     

    2) 참조 타입의 객체 비교

     

    기본타입과 다르게 참조타입은 참조값이 같아야 true가 됩니다.

     

    var objA = {value:100}; 
    var objB = {value:100}; 
    var objC = objA; 
    
    console.log(objA == objB); //출력: false 
    console.log(objC == objA); //출력: true

     

     

    3) 참조 타입의 함수 호출 방식

     

    기본 타입 객체 → "값"에 의한 함수 호출

    참조 타입 객체 → "참조"에 의한 함수 호출

     

    따라서...

     

    <1> 함수 호출 시 인자로 기본 타입을 넘겼다

    → 호출된 함수의 매개변수로 복사된 값이 전달됩니다. 호출된 변수의 값이 변경되지 않습니다.

     

    <2> 함수 호출 시 인자로 참조 타입을 넘겼다

    → 인자로 넘긴 객체의 참조값이 그대로 함수 내부로 전달됩니다.

    따라서 함수 내부에서 인자로 넘어온 실제 객체의 값을 변경하는 것도 가능합니다.

     

    var a = 100; //기본 타입의 숫자를 가진 변수
    var objA = { value: 100 }; //참조 타입인 객체
    
    function changeArg(num, obj){
       num = 200;
       obj.value = 200;
       console.log('num=',num,', obj=',obj);//출력값: num=200, obj={value:200}
    }
    
    changeArg(a, objA);
    
    console.log('a=',a); //출력값: a=100
    console.log('objA=',objA); //출력값: objA={value:200} //객체의 값이 100에서 200으로 변경됨!

     

     

     

     


     

    4. 프로토타입

     

    JS의 모든 객체는 자신의 부모 역할을 하는 객체와 연결되어 있습니다.

    즉, 부모 객체의 프로퍼티를 자기 것처럼 쓸 수 있다는 거죠. 이러한 부모 객체를 프로토타입 객체라고 부릅니다.

     

    var me = {
        id : 'nykim',
        isFemlae : true,
        age : 25
    };
    
    console.log(me.toString());
    console.dir(me);

     

     

    위에서 생성한 me 객체는 toString() 메서드가 없음에도 불구하고 에러없이 정상적으로 출력된 모습입니다. 이유는 바로 me 객체의 프로토타입에 toString() 메서드가 이미 정의되어 있고, me 객체가 상속처럼 메서드를 호출했기 때문이죠.

    me 객체를 잘 들여다보면 __proto__ 프로퍼티가 있는 걸 알 수 있는데, 이것이 바로 부모인 프로토타입 객체를 뜻합니다.

     

    ECMAScript 명세서에는 JS의 모든 객체는 자신의 프로토타입을 가리키는 [[Prototype]] 이라는 숨겨진 프로퍼티를 가진다고 설명하고 있습니다. (크롬은 이걸 __proto__와 같이 표현하는 것 뿐이고요!)

     


     

    5. 배열

     

    관대한 자스님의 배려 덕분에 자바스크립트에서는 배열을 만들기가 수월합니다.

    배열의 크기를 지정하지 않아도 되며, 어떤 위치에 어느 타입의 데이터를 저장하더라도 상관하지 않거든요 :-9

     

     

    1) 배열 소환하는 방법: 배열 리터럴

     

    배열 리터럴 표기법으로 새로운 배열을 생성할 수 있습니다.

    객체 리터럴이 중괄호{}를 이용한다면, 배열 리터럴은 대괄호[]를 사용합니다.

     

     

    2) 배열의 프로퍼티

     

    배열이 기본적으로 갖는 프로퍼티 중 하나인 length는 배열의 크기를 나타냅니다.

    단, 배열에 "실제로" 존재하는 원소 개수와 일치하지 않을 수 있습니다.

    JS에서는 배열의 크기를, 현재 배열의 인덱스 중 가장 큰 값을 기준으로 정하기 때문입니다.

    값이 할당되지 않은 인덱스의 요소는 undefiend 값을 기본으로 가집니다.

     

    배열의 요소에 접근할 때는 Array[0]과 같이 사용합니다.

    엇! 근데 대괄호 접근법은 [ ] 안에 프로퍼티 속성을 문자열을 적어야 한다고 하지 않았나요..???

    관대하신 JS는 [ ] 연산자 내에 숫자가 사용될 경우, 해당 숫자를 자동으로 문자열 형태로 바꿔주십니다(와우)

     

    var myArr = [];
    myArr[0] = 100;
    myArr[4] = 'hello';
    
    console.log(myArr); //출력값: [100, undefiend, undefiend, undeifend, 'hello'];
    console.log(myArr.length); //출력값: 5
    
    myArr[100] = true;
    console.log(myArr.length); //출력값: 101
    var myArr = ['zero', 'one', 'two'];
    
    myArr.push('three');
    console.log(myArr); //['zero', 'one', 'two', 'three'], legnth:4
           
    myArr.length = 5;
    console.log(myArr); //['zero', 'one', 'two', 'three', 'undefiend'], legnth:5
            
    myArr.push('four');
    console.log(myArr); //['zero', 'one', 'two', 'three', 'undefiend', 'four'], legnth:6

     

     

    3) 배열과 객체의 비교

     

    배열을 typeof 해보면 object를 출력합니다.

     

    var myArray = ['hi', 'hello'];
    var myObj = {
        '0': 'bye',
        '1': 'see you later'
    }
    
    console.log( typeof myArray ); // 출력값: object (!!)
    console.log( typeof myObj ); // 출력값: object
    
    myArray.push('Hey'); //가능
    myObj.push('Have a good day'); //오류 퉷

     

    만약 객체에 push() 메서드를 써보면 어떨까요?! 아쉽게도(?) 오류를 뱉네요....

    왜냐면 myobJ는 배열이 아니므로 push()등의 표준 배열 메서드를 사용할 수 없습니다.

    myArray와 myObj는 자신의 부모인 프로토타입 객체가 서로 다르니까요.

    (자기 부모인 프로토타입 객체로부터 프로퍼티를 찾아 쓰는 건데, 여기에도 없으면 쓸 수가 없겠죠?)

     

    myArray의 프로토타입은 Array.prototype 객체이고,

    myObj의 프로토타입은 Object.prototype 객체입니다.

     

    어라... 근데 배열도 object라면서요??

    맞습니다. 그래서 배열은 Array.prototype에 포함된 배열 표준 메서드뿐만 아니라,

    Object.prototype의 표준 메서드를 모두 사용할 수 있습니다!

     

     

    그나저나 배열도 객체라면 동적으로 프로퍼티를 추가할 수 있지 않을까요?!

    제가 한 번 해보겠습니다.

     

    var myArr = ['zero', 'one', 'two'];
    
    myArr.name = '나는 배열이다!!';
    myArr.isArray = true;
            
    console.dir(myArr);

     

     

    오, 성공했어요!!

     

     

    4) 배열의 프로퍼티 열거

     

    배열에 for..in..문을 돌리면 모든 프로퍼티를 열거할 수 있어요.

    반면 for문은 정확히 배열의 요소만 출력한다는 점이 다릅니다.

     

    for (var prop in myArr) {
      console.log( prop, '=', myArr[prop] );
    }
    
    console.log('-----------');
    
    for (var i=0; i<myArr.length; i++){
      console.log( i, '=', myArr[i] );
    }

     

     

     

    5) 배열 요소 삭제

     

    다시 말하지만 배열도 객체입니다.

    그래서 delete 연산자로 요소 삭제가 가능해요!

    단, 이 경우는 해당 값을 undefiend로 설정할 뿐 원소 자체를 삭제하지는 않습니당.

     

    var arr = ['zero', 'one', 'two'];
    delete arr[1];
    console.log(arr); //['zero', undefiend, 'two'], length = 3

     

    따라서 일반적으로는 splice() 배열 메서드를 사용해 요소를 완전히 삭제합니다.

     

    splice(start, deleteCount, item...)

    • start - 배열 시작 위치
    • deleteCount - 해당 위치부터 삭제할 요소의 수
    • item - 삭제할 위치에 추가할 요소
    var arr = ['zero', 'one', 'two'];
    arr.splice(2,1);
    console.log(arr); //['zero', 'one'], length = 2

     

     

    6) Array() 생성자 함수

     

    배열은 일반적으로 배열 리터럴 방식으로 생성하는데 (var me = ['nykim', '25];)

    사실 이것도 JS가 기본 제공하는 Array() 생성자 함수로 배열을 생성하는 과정을 단순화시킨 것입니다.

     

    Array()함수를 호출할 때

    • 인자가 1개이고 숫자라면 => 호출된 인자를 length로 갖는 빈 배열 생성
    • 그 외 => 호출된 인자를 요소로 갖는 배열 생성

     

    인 거죠 :)

     

     

     

    7) 유사 배열 객체

     

    배열의 length 프로퍼티는 배열의 동작에 있어 중요한 프로퍼티입니다.

    그런데 이 프로퍼티를 일반 객체가 갖고 있으면 어떨까요?!

    JS에서는 이렇게 length 프로퍼티를 가진 객체를 '유사 배열 객체'라고 부릅니다.

    이러한 유사 배열 객체는 놀라벡도 표준 배열 메서드를 사용할 수도 있어요(!)

     

    var array = ['nykim'];
    var object = {name: 'nykim', length: 1};
    
    array.push('hello');
    console.log(array); //출력값: ['nykim, 'hello']
    
    obejct.push('hi'); // (1*) 출력값: ERROR
    Array.prototype.push.apply(object, ['hi']); // (2*)
    console.log(object); //출력값: {'1': 'hi', name: 'nykim', length: 2}

     

    위에서 object 객체에다 push()라는 표준 배열 메서드를 썼더니 에러가 났습니다. (1*)

    그런데! apply() 메서드를 쓰면 요 표준 배열 메서드를 쓸 수가 있어요. (2*)

    자세한 건 후술할 예정이고, 여기서는 '유사 배열 객체도 배열 메서드를 쓸 수 있다'고만 알아둡시다!

     

     

     


     

     

    6. 기본 타입과 표준 메서드

     

    JS에서는 숫자, 문자열, 불린값에 대해 각 타입별로 호출 가능한 표준 메서드를 정의하고 있습니다.

    그런데 기본(원시) 타입은 객체가 아닌데 어떻게 메서드를 호출할까요?

     

    이 경우, 기본값은 메서드 처리 순간에 객체로 변환된 다음 각 타입별 표준 메서드를 호출하게 됩니다.

    리고 호출이 끝나면 다시 기본값으로 복귀하죠.

     

    var num = 0.5;
    console.log(num.toExponential(1)); //출력값: '5.0e-1'
    
    var string = 'nykim';
    console.log(string.charAt(2)); //출력값: 'k'

     

    위의 예시에서 toExponential()과 charAt()은 표준 메서드입니다.

    toExponential()은 표준 숫자형 메서드로서 숫자를 지수 형태의 문자열로 변환합니다. 여기에 쓰인 인자는 소수점 아래 몇 번째 자리까지 표시할 건지를 지정하는 거구요.

    charAt()은 표준 문자열 메서드이고, 인자로 받은 위치에 있는 문자를 리턴합니다. 문자열 인덱스는 0부터 시작하니까 k를 반환한 거구요.

     

    이처럼 타입은 기본 타입이지만, 이들을 위해 정의된 표준 메서드들을 객체처럼 호출할 수 있다는 점을 알아둡시다 :>

     

     


     

     

    7. 연산자

     

    1) + 연산자

     

    + 연산자는 '더하기 연산'과 '문자열 연결 연산'을 수행합니다.

    두 연산자가 모두 숫자라면 그냥 더하고, 문자열이 하나라도 포함되어 있으면 연결합니다.

     

    var add_01 = 1+3;
    var add_02 = 1+'string';
    
    console.log(add_01); //출력값: 4
    console.log(add_02); //출력값: 1string

     

     

    2) typeof 연산자

     

    typeof 연산자는 피연산자의 타입을 문자열 형태로 리턴합니다.

    여기서 null과 배열이 'object'라는 것과, 함수는 'function'이라는 것에 주의하고 넘어갑시다.

     

    기본 타입 숫자 'number'
    기본 타입 문자열 'string'
    기본 타입 불린값  'boolean'
    기본 타입 null 'object'
    기본 타입 undefined 'undefined'
    참조 타입 객체 'object'
    참조 타입 배열 'object'
    참조 타입 함수 'function'

     

     

    3) == (동등) 연산자와 === (일치) 연산자

     

    == 연산자는 타입 변환을 거쳐 비교하고, === 연산자는 타입 변경 없이 비교합니다.

    간단히 말하자면, === 연산자가 더 엄격합니다. 타입이 다르면 걍 false거든요.

    그래서 === 연산자로 비교하기를 권장하는 편입니다 :-0

     

    console.log( 1 == '1' ); // true
    console.log( 1 === '1' ); // false

     

     

    4) !! 연산자

     

    !!은 피연산자를 불린값으로 변환합니다.

     

     

    * 다음의 7가지 값은 false라는 것!

    ① false

    ② 0 또는 -0

    ③ " " / ' ' (empty strings)

    ④ null

    ⑤ undefined

    ⑥ NaN (Not a Number)

    ⑦ document.all

     

     

    댓글 0