type right - Lee-hyuna/33-js-concepts-kr GitHub Wiki

typeof ์™€ instanceof ์‚ดํŽด๋ณด๊ธฐ

์›๋ฌธ: Beyond typeof and instanceof: simplifying dynamic type checks

์ด ํฌ์ŠคํŒ…์€ instanceof๋ฅผ ๋” ๋งŽ์€ ๊ฐ’(ํ”ผ์—ฐ์‚ฐ์ž)์— ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋ฒ•์„ ์„ค๋ช…ํ•œ๋‹ค. ํŠนํžˆ ์›์‹œ ๊ฐ’์— ๊ด€ํ•ด ์ง‘์ค‘ํ•  ๊ฒƒ์ด๋‹ค.

1. ๋ฐฐ๊ฒฝ์ง€์‹: typeof vs. instanceof

Javascript์—์„œ ๊ฐ’์˜ ํƒ€์ž… ํ™•์ธ์„ ์–ธ์ œ ํ•ด์•ผํ• ๊นŒ? ๋Œ€๋žต ์ ์ธ ๊ทœ์น™์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • typeof๋Š” ๊ฐ’์ด ์›์‹œ ํƒ€์ž…์˜ ์š”์†Œ์ธ์ง€ ํ™•์ธํ•œ๋‹ค.

     if (typeof value === 'string')
    
  • instanceof๋Š” ๊ฐ’์ด ํด๋ž˜์Šค ๋˜๋Š” ์ƒ์„ฑ์ž ํ•จ์ˆ˜์˜ ์ธ์Šคํ„ด์Šค์ธ์ง€ ํ™•์ธํ•œ๋‹ค.

    if (value instanceof Map)
    

    (๋˜ํ•œ value.constructor ๋ฐ value.constructor.name๋„ ์œ ์šฉํ•˜๋‹ค)

ํ•˜์ง€๋งŒ ์ด๊ฒƒ์€ ์ด์ƒ์ ์ด์ง€ ๋ชปํ•˜๋‹ค. ์™œ๋ƒํ•˜๋ฉด ์›์‹œ ๊ฐ’๊ณผ ๊ฐ์ฒด์˜ ์ฐจ์ด์ ์ด ์ข…์ข… ๋ชจํ˜ธํ•ด์ง€๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ถ”๊ฐ€๋กœ ๋ช‡๊ฐ€์ง€ ์ด์ƒํ•œ ์ ์ด ์ƒํ™ฉ์„ ๋”์šฑ ๋ณต์žกํ•˜๊ฒŒ ๋งŒ๋“ ๋‹ค.

  • typeof null์€ 'object'์ด๋‹ค. 'null'์ด ์•„๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋ฒ„๊ทธ๋กœ ๊ฐ„์ฃผ๋œ๋‹ค.

  • typoeof๋Š” ๊ฐ์ฒด์™€ ํ•จ์ˆ˜๋ฅผ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋‹ค.

    > typeof {}
    'object'
    > typeof function () {}
    'function'
    

    ๋”ฐ๋ผ์„œ typeof๋ฅผ ํ†ตํ•ด ๊ฐœ์ฒด์„ฑ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ„๋‹จํ•œ ๋ฐฉ๋ฒ•์ด ์—†๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

  • ๋ชจ๋“  ๊ฐ์ฒด๊ฐ€ Object์˜ ์ธ์Šคํ„ด์Šค๋Š” ์•„๋‹ˆ๋‹ค.

     > Object.create(null) instanceof Object
     false
    

2. ์›์‹œ ๊ฐ’์— instaceof ์ ์šฉํ•ด๋ณด๊ธฐ

PrimitiveNumber ํด๋ž˜์Šค๊ฐ€ ์ฃผ์–ด์ง€๋ฉด, ์•„๋ž˜์˜ ์ฝ”๋“œ๋Š” x instanceof PrimitiveNumber ํ‘œํ˜„์‹์ด true๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ’ x๋ฅผ ๊ตฌ์„ฑํ•œ๋‹ค. PrimitiveNumber์— ๋Œ€ํ•œ ์ •์  ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด ํ‚ค๊ฐ€ ๊ณต์šฉ ์‹ฌ๋ณผ ์ธ Symbol.hasInstance๊ฐ€ ๋œ๋‹ค.

class PrimitiveNumber {
    static [Symbol.hasInstance](x) {
        return typeof x === 'number';
    }
}
console.log(123 instanceof PrimitiveNumber); // true

3. TypeRight library๋ฅผ ํ†ตํ•œ ๋™์  ํƒ€์ž… ํ™•์ธ

TypeRight์€ ๋™์  ํƒ€์ž… ํ™•์ธ์„ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค. ๋‹ค๋ฅธ ๊ธฐ๋Šฅ ์ค‘์—์„œ๋„ ๋‹ค์Œ ์˜ˆ์ œ๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์ด์ „ ์˜ˆ์ œ์—์„œ ์‚ฌ์šฉํ•œ ๋ฐฉ๋ฒ•์„ ์ด์šฉํ•œ๋‹ค. ์ด๊ฒƒ์˜ ์œ ์ผํ•œ ๋ชฉ์ ์€ instanceof ์—ฐ์‚ฐ์ž์˜ ์˜ค๋ฅธ์ชฝ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

  • PrimitiveUndefined
  • PrimitiveNull
  • PrimitiveBoolean
  • PrimitiveNumber
  • PrimitiveString
  • PrimitiveSymbol

TypeRight๋Š” ๊ฐ’์ด ๊ฐœ์ฒด์ธ์ง€ ํ™•์ธํ•˜๋Š” ํด๋ž˜์Šค๋ฅผ ์ œ๊ณตํ•˜์ง€ ์•Š์ง€๋งŒ ์‰ฝ๊ฒŒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด๋Ÿฌํ•œ ๊ธฐ์ดˆ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ TypeRight๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•จ์ˆ˜์˜ ๋งค๊ฐœ ๋ณ€์ˆ˜์— ์ ์ ˆํ•œ ํƒ€์ž…์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

import * as tr from 'type-right';

function dist(x, y) {
    tr.force(x, tr.PrimitiveNumber, y, tr.PrimitiveNumber);
    return Math.hypot(x, y);
}
dist(3, 4); // 5
dist(3, undefined); // TypeError

4. ๊ฐ„๋‹จํ•œ ํƒ€์ž… ํ™•์ธ์„ ์œ„ํ•œ ๋‹ค๋ฅธ ์ ‘๊ทผ ๋ฐฉ๋ฒ•

์œ ํ˜• ๊ฒ€์‚ฌ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ์œ„ํ•œ ๋‘ ๊ฐ€์ง€ ์ œ์•ˆ์€ ํ˜„์žฌ statge-0 ๋‹จ๊ณ„์— ์žˆ๋‹ค. ์ฆ‰, ํ–ฅํ›„์— ๋” ์ด์ƒ ํƒ๊ตฌ๋˜์ง€ ์•Š์„ ์ˆ˜๋„ ์žˆ๋Š” ๋œป์ด๋‹ค.

4.1. ํŒจํ„ด ๋งค์นญ

Brian Terlson๊ณผ Sebastian Markbรฅge์— ์˜ํ•ด ์ œ์•ˆ๋œ "ECMAScript Pattern Matching Syntax"์ด ์žˆ๋‹ค. Symbol.matches ๊ฐ€ ์กด์žฌํ•˜๋ฉฐ ๊ฐ’์„ "machable"ํ•˜๊ฒŒ ๋งŒ๋“ ๋‹ค.

match (val) {
    MyClass:
        console.log('val is an instance of MyClass');
}

์ด ์†์„ฑ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋˜๊ฑฐ๋‚˜ ์ˆ˜๋™์œผ๋กœ ์ถ”๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค. (A ํ–‰).

class PrimitiveNumber {
    static [Symbol.matches](x) { // (A)
        return x instanceof this;
    }
}

4.2. Builtin.is() and Builtin.typeOf()

James M. Snell์˜ "Builtin.is and Builtin.typeOf" ์ œ์•ˆ์€ ํƒ€์ž… ๊ฒ€์‚ฌ๋ฅผ ์œ„ํ•œ ๋ช‡ ๊ฐ€์ง€ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์†Œ๊ฐœํ•œ๋‹ค.

Builtin.is(value1, value2)๋Š” value1๊ณผ value2๊ฐ€ ๋™์ผํ•œ ์ƒ์„ฑ์ž๋ฅผ ์ฐธ์กฐํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค. value1๊ณผ value2๋Š” ํ˜„์žฌ ์˜์—ญ์ด๋‚˜ ๋‹ค๋ฅธ ์˜์—ญ์—์„œ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

> Builtin.is(Date, vm.runInNewContext('Date'))
true
> Builtin.is(Date, Date)
true

Builtin.typeOf()๋Š” ์›์‹œ ๊ฐ’๊ณผ ๋‚ด์žฅ ํด๋ž˜์Šค ๋ชจ๋‘์—์„œ ์ž‘๋™ํ•˜๋Š” typeof์˜ ํ™•์žฅ์œผ๋กœ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

Builtin.typeOf(undefined); // 'undefined'
Builtin.typeOf(null); // 'null'
Builtin.typeOf(123); // 'number'

Builtin.typeOf(new Number()); // 'Number'
Builtin.typeOf([]); // 'Array'
Builtin.typeOf(new Map()); // 'Map'

// The builtin counts, not the user-defined class
class MyArray extends Array {}
Builtin.typeOf(new MyArray()); // 'Array'

5.์ถ”๊ฐ€ ์ฝ์„ ๊ฑฐ๋ฆฌ