How do you check the difference between an ECMAScript 6 class and function?

前端 未结 8 1913
借酒劲吻你
借酒劲吻你 2020-12-07 19:19

In ECMAScript 6 the typeof of classes is, according to the specification, \'function\'.

However also according to the specification you are

8条回答
  •  野趣味
    野趣味 (楼主)
    2020-12-07 19:23

    Ran some performance benchmarks on the different approaches mentioned in this thread, here is an overview:


    Native Class - Props Method (fastest by 56x on large examples, and 15x on trivial examples):

    function isNativeClass (thing) {
        return typeof thing === 'function' && thing.hasOwnProperty('prototype') && !thing.hasOwnProperty('arguments')
    }
    

    Which works because the following is true:

    > Object.getOwnPropertyNames(class A {})
    [ 'length', 'name', 'prototype' ]
    > Object.getOwnPropertyNames(class A { constructor (a,b) {} })
    [ 'length', 'name', 'prototype' ]
    > Object.getOwnPropertyNames(class A { constructor (a,b) {} a (b,c) {} })
    [ 'length', 'name', 'prototype' ]
    > Object.getOwnPropertyNames(function () {})
    [ 'length', 'name', 'arguments', 'caller', 'prototype' ]
    > Object.getOwnPropertyNames(() => {})
    > [ 'length', 'name' ]
    

    Native Class - String Method (faster than regex method by about 10%):

    /**
     * Is ES6+ class
     * @param {any} value
     * @returns {boolean}
     */
    function isNativeClass (value /* :mixed */ ) /* :boolean */ {
        return typeof value === 'function' && value.toString().indexOf('class') === 0
    }
    

    This may also be of use for determining a Conventional Class:

    // Character positions
    const INDEX_OF_FUNCTION_NAME = 9  // "function X", X is at index 9
    const FIRST_UPPERCASE_INDEX_IN_ASCII = 65  // A is at index 65 in ASCII
    const LAST_UPPERCASE_INDEX_IN_ASCII = 90   // Z is at index 90 in ASCII
    
    /**
     * Is Conventional Class
     * Looks for function with capital first letter MyClass
     * First letter is the 9th character
     * If changed, isClass must also be updated
     * @param {any} value
     * @returns {boolean}
     */
    function isConventionalClass (value /* :any */ ) /* :boolean */ {
        if ( typeof value !== 'function' )  return false
        const c = value.toString().charCodeAt(INDEX_OF_FUNCTION_NAME)
        return c >= FIRST_UPPERCASE_INDEX_IN_ASCII && c <= LAST_UPPERCASE_INDEX_IN_ASCII
    }
    

    I'd also recommend checking out my typechecker package which includes the use cases for the above - via the isNativeClass method, isConventionalClass method, and a isClass method that checks for both types.

提交回复
热议问题