336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

Type Checking (타입 체크)

자바스크립트는 동적 타입(dynamic typed) 언어로 변수에 어떤 값이 할당 될지 예측하기 어려움.


  1. dynamic typing(동적 타입)

다음 예제는 인수 a, b의 합하여 값을 리턴하는 것으로 초기 의도는 수의 합 계산을 위한 의도로 보이지만 인수의 타입에 따라 다른 결과가 나타날 수 있다.

function sum(a, b) {
  return a + b;
}

// 아마도 예상되는 초기 의도
sum(1, 3); // 4

// 숫자 대신 문자열을 인자로 넘길 경우 1+2 의 결과가 3이 아닌 '12'의 문자열의 형태로 넘어간다.
sum('1', '2'); // '12'

// 다른 정적인 언어같은 경우는 해당 코드를 컴파일 할시 에러가 나타나지만 자바스크립트에서는 문자열로 연산되어 의도치 않은 결과가 나온다.
sum('x', 1); // 'x1'

sum(1, 'x') // '1x'

이러한 결과는 변수나 반환값의 타입을 사전에 지정하지 않는 자바스크립트의 특징인 동적 타이핑(dynamic typing)에 의한 것이다. 이와 같은 이유로 자바스크립트는 타입체크가 필요하며 최근 리액트 진영에서는 타입스크립트를 사용하는 경향이 강하다.


  1. typeof(타입 연산자)

타입 연산자는 피연산자의 데이터 타입을 문자열로 반환.

typeof '';              // string
typeof 1;               // number
typeof NaN;             // number
typeof true;            // boolean
typeof [];              // object
typeof {};              // object
typeof new String();    // object
typeof new Date();      // object
typeof /test/gi;        // object
typeof function () {};  // function
typeof undefined;       // undefined
typeof null;            // object (설계적 결함)
typeof undeclared;      // undefined (설계적 결함)

typeof 연산자는 null을 제외한 원시타입을 체크하는 데는 문제가 없지만 객체의 종류까지 구분하여 체크하려 할때는 사용에 문제가 있다. (null과 배열의 경우는 object, 함수의 경우는 function, Date, RegExp, 사용자 정의 객체 등 대부분의 객체를 object로 리턴하기 때문)


  1. typeof 가 아닌 다른방법으로 타입체크하기

Object.prototype.toString

Object.prototype.toString 메소드는 객체를 나타내는 문자열을 반환한다.

var obj = new Object();
obj.toString(); // [object Object]

Object.prototype.call 메소드를 사용하면 모든 타입의 값을 알아낼 수 있다.

Object.prototype.toString.call('');             // [object String]
Object.prototype.toString.call(new String());   // [object String]
Object.prototype.toString.call(1);              // [object Number]
Object.prototype.toString.call(new Number());   // [object Number]
Object.prototype.toString.call(NaN);            // [object Number]
Object.prototype.toString.call(Infinity);       // [object Number]
Object.prototype.toString.call(true);           // [object Boolean]
Object.prototype.toString.call(undefined);      // [object Undefined]
Object.prototype.toString.call();               // [object Undefined]
Object.prototype.toString.call(null);           // [object Null]
Object.prototype.toString.call([]);             // [object Array]
Object.prototype.toString.call({});             // [object Object]
Object.prototype.toString.call(new Date());     // [object Date]
Object.prototype.toString.call(Math);           // [object Math]
Object.prototype.toString.call(/test/i);        // [object RegExp]
Object.prototype.toString.call(function () {}); // [object Function]
Object.prototype.toString.call(document);       // [object HTMLDocument]
Object.prototype.toString.call(argument);       // [object Arguments]
Object.prototype.toString.call(undeclared);     // ReferenceError

Object.prototype.call

이것을 이용한 타입을 반환하는 함수 작성

function getType(target) {
  return Object.prototype.toString.call(target).slice(8, -1);
}

String.prototype.slice 메소드를 사용하여 Object.prototype.toString.call 메소드가 반환한 문자열에서 “[object”와 “]”를 제외하고 타입을 나타내는 문자열만을 추출

getType('');         // String
getType(1);          // Number
getType(true);       // Boolean
getType(undefined);  // Undefined
getType(null);       // Null
getType({});         // Object
getType([]);         // Array
getType(/test/i);    // RegExp
getType(Math);       // Math
getType(new Date()); // Date
getType(function () {}); // Function

방금 생성한 함수를 이용하여 sum 함수에 타입체크기능을 추가하기

function sum(a, b) {
  // a와 b가 number 타입인지 체크
  if (getType(a) !== 'Number' || getType(b) !== 'Number') {
    throw new TypeError('파라미터에 number 타입이 아닌 값이 할당되었습니다.');
  }
  return a + b;
}

console.log(sum(10, 20));   // 30
console.log(sum('10', 20)); // TypeError

위의 getType메서드를 사용하여 각 타입별로 체크하는 기능을 작성

function getType(target) {
  return Object.prototype.toString.call(target).slice(8, -1);
}

function isString(target) {
  return getType(target) === 'String';
}

function isNumber(target) {
  return getType(target) === 'Number';
}

function isBoolean(target) {
  return getType(target) === 'Boolean';
}

function isNull(target) {
  return getType(target) === 'Null';
}

function isUndefined(target) {
  return getType(target) === 'Undefined';
}

function isObject(target) {
  return getType(target) === 'Object';
}

function isArray(target) {
  return getType(target) === 'Array';
}

function isDate(target) {
  return getType(target) === 'Date';
}

function isRegExp(target) {
  return getType(target) === 'RegExp';
}

function isFunction(target) {
  return getType(target) === 'Function';
}

4. instanceof 메서드

위와 같이 Object.prototype.toString 메서드를 통해 각 객체의 타입을 식별 할 수는 있으나 객체의 상속관계까지 체크 할수는 없음. 이를 instanceof 메서드를 통해 해당 객체가 어떤 객체를 상속받고 있는지 확인 할 수 있다.

// 프로토타입을 상속받는 자바스크립트 코드.

function Human() {}
function Man() {}
Man.prototype = new Human()

const man = new Man();

man instanceof Man
man instanceof Human

예제 1) HTMLElement가 아닌 빈 객체에 Dom 속성을 추가하려 한다면 다음과 같은 에러가 나타난다.

// HTMLElement를 상속받은 모든 DOM 요소에 css 프로퍼티를 추가하고 값을 할당한다.
function css(elem, prop, val) {
  // type checking...
  elem.style[prop] = val;
}

css({}, 'color', 'red');
// TypeError: Cannot set property 'color' of undefined

이와 같은 에러를 방지하기 위해서 우리는 대상이 HTMLElement를 상속 받는지 확인하여야한다.

Instanceof 연산자는 피연산자인 객체가 우항에 명시된 타입의 인스턴스인지 여부를 알려준다. 이때 타입이란 constructor를 말하며 프로토타입 체인에 존재하는 모든 constructor를 검색하여 일치하는 constructor가 있다면 true를 반환한다.

function Person() {}
const person = new Person();

console.log(person instanceof Person); // true
console.log(person instanceof Object); // true

예제 2) 예제 1)에서 발생한 오류를 방지하기 위한 코드 추가

// HTMLElement를 상속받은 모든 DOM 요소에 css 프로퍼티를 추가하고 값을 할당한다.
function css(elem, prop, val) {
  // type checking
  if (!!!(elem && elem instanceof HTMLElement)) {
    throw new TypeError('매개변수의 타입이 맞지 않습니다.');
  }
  elem.style[prop] = val;
}


css({}, 'color', 'red'); // TypeError: 매개변수의 타입이 맞지 않습니다.

5. 유사 배열 객체

배열인지 체크하기 위해서는 Array.isArray 메서드를 사용한다.

console.log(Array.isArray([]));    // true
console.log(Array.isArray({}));    // false
console.log(Array.isArray('123')); // false

유사 배열 객체(array-like object)은 length 프로퍼티를 갖는 객체로 문자열, arguments, HTMLCollection, NodeList 등은 유사 배열이다. 유사 배열 객체는 length 프로퍼티가 있으므로 순회할 수 있으며 call, apply 함수를 사용하여 배열의 메소드를 사용할 수도 있다.

어떤 객체가 유사 배열인지 체크하려면 우선 length 프로퍼티를 갖는지 length 프로퍼티의 값이 정상적인 값인지 체크한다.

const isArrayLike = function (collection) {
  // 배열 인덱스: 32bit 정수(2의 32제곱 - 1)
  // 유사 배열 인덱스: 자바스크립트로 표현할 수 있는 양의 정수(2의 53제곱 - 1)
  const MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; // == 2**53

  // 빈문자열은 유사배열이다. undefined == null => true
  const length = collection == null ? undefined : collection.length;
  return typeof length === 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
};

// true
console.log(isArrayLike([]));
console.log(isArrayLike('abc'));
console.log(isArrayLike(''));
console.log(isArrayLike(document.querySelectorAll('li')));
console.log(isArrayLike(document.getElementsByName('li')));
console.log(isArrayLike({ length: 0 }));
(function () {
  console.log(isArrayLike(arguments));
}());


// false
console.log(isArrayLike(123));
console.log(isArrayLike(document.querySelector('li')));
console.log(isArrayLike({ foo: 1 }));
console.log(isArrayLike());
console.log(isArrayLike(null));

참조링크 ....

true + false
12 / "6"
"number" + 15 + 3
15 + 3 + "number"
[1] > null
"foo" + + "bar"
'true' == true
false == 'false'
null == ''
!!"false" == !!"true"
[‘x’] == ‘x’
[] + null + 1
[1,2,3] == [1,2,3]
{}+[]+{}+[1]
!+[]+[]+![]
new Date(0) - 0
new Date(0) + 0

유사배열 예제

var yoosa = {
  0: 'a',
  1: 'b',
  2: 'c',
  length: 3
};

Array.prototype.forEach.call(yoosa, function(i) { console.log(i); });

+ Recent posts