Default value of a type in javascript

default-value, javascript, types

Solution

Both previous answers correctly note that the default (unassigned) value of a variable in JavaScript is `undefined`, but neither addresses what you seem to be looking for—an equivalent of e.g. the `default` operator in C#.

Fortunately, JavaScript has a very simple type system: everything that isn't one of the seven primitive types is an object and can be called via its constructor.¹ The following function, given a string representing

- the name of a JS primitive type, e.g.`'string'` or `'null'`;

- any valid production of the `typeof` operator, e.g. `'function'`;

- a function name either in the `this` value it is called with or its local scope²

will produce a reasonable interpretation of a "default" value:

function defaultVal(type) {
    if (typeof type !== 'string') throw new TypeError('Type must be a string.');
    
    // Handle simple types (primitives and plain function/object)
    switch (type) {
        case 'bigint'    : return BigInt(0);
        case 'boolean'   : return false;
        case 'function'  : return function () {};
        case 'null'      : return null;
        case 'number'    : return 0;
        case 'object'    : return {};
        case 'string'    : return "";
        case 'symbol'    : return Symbol();
        case 'undefined' : return void 0;
    }
    
    try {
        // Look for constructor in this or current scope
        var ctor = typeof this[type] === 'function'
                   ? this[type]
                   : eval(type);
        
        return new ctor;
    
    // Constructor not found, return new object
    } catch (e) { return {}; }
}

You can call it like this:

defaultVal( typeof 1 ); // -> 0
defaultVal( 'bigint' ); // -> 0n
defaultVal( 'object' ); // -> {}
defaultVal( 'RegExp' ); // -> /(?:)/

Unfortunately, the JS `typeof` operator may be a bit… anameic for our purposes. For example, `typeof null === 'object'`¹, and `typeof [] === 'object'`, which probably isn't what you want.

To work around this, here's a function that returns the result of calling `typeof` on a value unless the result is 'object', in which case it will return `'null'` if the value is `null` and `obj.constructor.name` otherwise (with `'object'` as the fallback value if all else fails):

function getType(obj) {
    var type = typeof obj;
    
    if (type !== 'object') return type; // primitive or function
    if (obj === null) return 'null';    // null
    
    // Everything else, check for a constructor
    var ctor = obj.constructor;
    var name = typeof ctor === 'function' && ctor.name;

    return typeof name === 'string' && name.length > 0 ? name : 'object';
}

And now we can have:

defaultVal( getType( 1234 ) );  // -> 0
defaultVal( getType( [99] ) );  // -> []
defaultVal( getType( 'ab' ) );  // -> ""
defaultVal( getType( null ) );  // -> null   (Not possible with typeof!)
defaultVal( getType( /.*/ ) );  // -> /(?:)/ (Not possible with typeof!)

function T () {}
defaultVal( getType( new T ) ); // -> T {}   (Not possible with typeof!)

I suspect this is as close to what you're looking for as you're going to get. Also, to head off any criticism: the use of eval above might seem a bit dirty, but it's the only way to get a named value from the current scope.

¹ `null` is a bit of an oddity. The ECMAScript 2020 specification clearly refers to it as a primitive; however, `typeof null` is `'object'` due to a bug in the original JavaScript implementation. At one point MDN excluded null from its list of primitives, counting only six primitives and stating that `null` should be considered a "special case for every `Object`".

Based on the spec, I refer to `null` as a primitive in this answer, and MDN has since been updated to agree with this stance.

² This function can't call a constructor instantiated in another scope; instead, I've made it possible to call it with `this` bound to an object containing any such constructors it may reference:

function innerScopeCtor() {
    function T () {}
    
    return defaultVal.call( { T : T }, 'T' );
}

innerScopeCtor(); // T {}

If you don't do this, it will just fall back to returning a new object.

Problem

Is there a function in JavaScript that returns the default value for a type name that is passed to it? For example: ``` var defaultValue = built_in_getDefaultValue("number"); console.log(defaultValue); // Logs the number 0 to the console. ```

Original source