Contents

Javascript의 Typeof와 Instanceof

자바스크립트에서 정말 선택받은 몇몇을 제외하고 모든 것은 객체이다.

그럼 익명의 객체가 어떤 타입인지 알기 위해서는 어떤 방법을 사용할 수 있을까?

typeof

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/typeof

typeof object 형태로 사용한다. typeof의 반환 값은 사전에 정의된다.

type result
Undefined “undefined”
Null “object”
Boolean “boolean”
Number “number”
BigInt “bigint”
String “string”
Symbol “symbol”
Function “function”
다른 모든 객체 “object”

typeof는 언제 사용할까

객체의 undefined 검사에서 사용될 수 있다. if (typeof object === 'undefined') 처럼.. 자바스크립트의 변수가 어떤 값을 가지는지 모호할 때 사용한다 (var 키워드 등)

typeof를 사용해서 nullish 체크를 할 수 있지만 옵셔널 체이닝과는 완전히 다른 개념이다.

왜 null은 object type일까?

주의해야 할 점은, typeof null은 항상 “object"로 반환된다는 점이다. MDN 설명에 따르면..

자바스크립트가 처음 구현될 때 자바스크립트의 값은 타입 태그와 값으로 표시되었습니다.

object의 타입 태그는 0이었고, null은 Null Pointer (0x00)으로 표기되었습니다.

그 결과 null은 타입 태그로 0을 가지고, typeof null은 object를 반환합니다.

변경 요청이 거절되었는데, 거절된 사유도 그럴듯하다.

This proposal has been rejected. It was implemented in V8 but it turned out that it broke a lot of existing sites. In the spirit of One JavaScript this is not feasible.

V8엔진에서 구현되었지만 기존 사이트들이 정상적으로 작동하지 않는 원인이 되었고, 이는 하나의 자바스크립트 정신에 위배되기 때문에 기각한다.

typescript에서도 typeof null은 “object"라고 표시된다.

내가 본 자바스크립트의 기능 중 최악이다 ㅋㅋ

var myNullVar = null;
alert(typeof myNullVar); // alerts the string "object"
alert(myNullVar  instanceof Object); // alerts "false"

instanceof

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/instanceof

instanceof 연산자는 생성자의 prototype 속성이 객체의 프로토타입 체인 내에 존재하는지 판별한다.

// 생성자 정의
function C(){}
function D(){}

var o = new C();

// true, 왜냐하면 Object.getPrototypeOf(o) === C.prototype
o instanceof C;

// false, 왜냐하면 D.prototype이 o 객체의 프로토타입 체인에 없음
o instanceof D;

o instanceof Object; // true, 왜냐하면
C.prototype instanceof Object // true

C.prototype = {};
var o2 = new C();

o2 instanceof C; // true

// false, 왜냐하면 C.prototype이
// 더 이상 o의 프로토타입 체인에 없음
o instanceof C;

D.prototype = new C(); // C를 D의 [[Prototype]] 링크로 추가
var o3 = new D();
o3 instanceof D; // true
o3 instanceof C; // true, 왜냐하면 이제 C.prototype이 o3의 프로토타입 체인에 존재

StringDate 객체도 Object 타입이기 때문에 typeof를 사용해서는 제대로 된 객체 판별이 불가능하다.

var simpleStr = "This is a simple string";
var myString  = new String();
var newStr    = new String("String created with constructor");
var myDate    = new Date();
var myObj     = {};

simpleStr instanceof String; // returns false, prototype chain을 확인하고, undefined를 찾는다.
myString  instanceof String; // returns true
newStr    instanceof String; // returns true
myString  instanceof Object; // returns true

myObj instanceof Object;    // returns true, undefined prototype 임에도 불구하고 true.
({})  instanceof Object;    // returns true, 위의 경우와 동일.

myString instanceof Date;   // returns false

myDate instanceof Date;     // returns true
myDate instanceof Object;   // returns true
myDate instanceof String;   // returns false

언제, 무엇을 사용해야 할까?

typeofinstanceof 모두 객체가 ‘어떤 타입인지’ 알려주는 연산자이다.

typeof는 unary operator이고, instanceof는 binary operator인 것 이외에 차이점이 있을까?

  • 사실 unary vs binary 차이가 크긴 하다
  • unary는 코드 작성 시점에 어떤 내용이 들어올 지 모를 때 사용하고
  • binary는 코드 작성 시점에 어떤 내용이 대충 들어올지 아는 상태에서 정말 이 타입의 인스턴스가 맞나? 체크

https://stackoverflow.com/questions/899574/what-is-the-difference-between-typeof-and-instanceof-and-when-should-one-be-used

1. 커스텀 타입에 대해서는 instanceof를 사용

var ClassFirst = function () {};
var ClassSecond = function () {};
var instance = new ClassFirst();
typeof instance; // object
typeof instance == 'ClassFirst'; // false
instance instanceof Object; // true
instance instanceof ClassFirst; // true
instance instanceof ClassSecond; // false 

2. 간단한 빌트인 타입에 대해서는 typeof를 사용

'example string' instanceof String; // false
typeof 'example string' == 'string'; // true

'example string' instanceof Object; // false
typeof 'example string' == 'object'; // false

true instanceof Boolean; // false
typeof true == 'boolean'; // true

99.99 instanceof Number; // false
typeof 99.99 == 'number'; // true

function() {} instanceof Function; // true
typeof function() {} == 'function'; // true

3. 복잡한 빌트입 타입에 대해서는 instanceof를 사용

/regularexpression/ instanceof RegExp; // true
typeof /regularexpression/; // object

[] instanceof Array; // true
typeof []; //object

{} instanceof Object; // true
typeof {}; // object

상세 비교

instanceof 연산자는 객체의 prototype 속성의 constructor에 대한 테스트를 진행한다.

때문에 instanceof 는 객체 타입에만 적용할 수 있다.

대부분의 경우, instanceof someObject 가 true이면 객체가 해당 생성자를 통해 생성되었거나 그 서브클래스의 생성자를 통해 생성되었다는 것을 의미한다.

하지만 프로토타입은 Object.setPrototypeOf() 를 통해서 명시적으로 설정될 수 있기 때문에 항상 정확한 것은 아니다. (물론 성능때문에 권장되는 행동은 아니다)

대부분의 경우에는 생성자를 사용해서 string이나 number를 생성하지 않는다. 이 경우에는 좀 헷갈리지만 주의해서 사용해야 한다.

let num = new Number(5);
console.log(num instanceof Number); // print true
console.log(typeof num); // print object
num++; //num is object right now but still can be handled as number
//and after that:
console.log(num instanceof Number); // print false
console.log(typeof num); // print number

개인적으로는 나도 instanceof를 선호하는데.. string 간 비교는 깔끔하지 않다고 생각이 들기 때문이다.

하지만 typeof를 사용해야만 하는 케이스가 좀 있어 그 경우를 기억해보도록 해야 겠다.

별개로 instanceof는 또한 동일한 윈도우 안에 있는 객체들 간에서만 사용할 수 있다는 단점도 존재한다.

  • iframe 이나 iframe을 사용한 팝업 윈도우의 경우에는 별개의 윈도우로 인식된다.
  • 때문에 서로 다른 iframe 안에서 instanceof를 호출할 경우 정상적으로 작동하지 않는다.
  • 하지만 typeof는 모든 케이스에서 동일한 결과를 리턴할 것을 보장하기 때문에 좀 더 안전하다.

typescript를 쓰면 되지 않느냐?

typescript는 컴파일 시점에 타입에 대한 체킹을 강제하는 기능이 더해진 자바스크립트라고 생각한다.

  • 자바의 제네릭에 대한 정보가 컴파일 시점에 지워지는 것처럼, 타입스크립트 또한 컴파일 이후에는 자바스크립트가 되기 때문에 타입에 대한 오류는 검사하지 않는다.

safe coding을 하기 위해서는 여전히 런타임에 인스턴스의 타입 정보를 가져와야 할 일이 있기 때문에 사용할 필요가 없다는 말은 성립하지 않는다.