Search code examples
javascriptnode.jsecmascript-6stricthasownproperty

Which object does not have `hasOwnProperty` in JavaScript?


With some values, calling hasOwnProperty throws an error.

Let's check the following code:

null.hasOwnProperty('bar') // Error
undefined.hasOwnProperty('bar') // Error
(0).hasOwnProperty('bar') // Returns false

Are there any other variables rather than null and undefined that throws an error when calling with .hasOwnProperty?

The same question for setting an object's property:

null.bar // Error
undefined.bar // Error
(0).bar === undefined // Returns true

=========

Another case where it throws an error in my Node.js environment:

In a browser

'use strict';
(0).bar = 0; // Nothing happens

In Node.js v.10.3.0:

(0).bar = 0; // Nothing
'use' strict';
(0).bar === undefined; // Returns true
true.bar === undefined; // Returns true
''.bar = '';// STILL NOTHING HAPPENS
(0).bar = 0; //TypeError: Cannot create property 'bar' on number '0'
(true).bar = true; // TypeError: Cannot create property 'bar' on boolean 'true'

========

Eventually, I found Check if a value is an object in JavaScript:

if (obj instanceof Object) obj.hasOwnProperty(...) // Or set a property on it

This solution totally fulfills my needs.


Solution

  • TLDR;

    Object.prototype.hasOwnProperty can be called directly on

    • Object.prototype,

    • The subset of objects which have Object.prototype in their inheritance chain and don't redefine hasOwnProperty in either the inheritance chain or on the object, and

    • BigInt, Boolean, Number, String and Symbol primitive values. Calling it on primitive values is generally superfluous however as

        (primitiveValue).hasOwnProperty(propertyName)
      

      always rerturns false - primitive values do not have own properties.


    Data Types

    JavaScript currently supports eight different data types in the ECMAScript 2020 specification:

    BigInt (introduced in ECMAScript 2020), Boolean, Null, Undefined, Number, String, Symbol (new in ECMAScript 2015)
    and Object.

    The first seven of these are primitive values rather than object values - including null which is of data type Null. (Yes, typeof null returns "object" instead of "null", but this is an artifact of early JavaScript engine design that can't be fixed because it would break the web.)

    Number, Boolean and String

    Values of type Number, Boolean and String are automatically converted into "wrapper" object instances of global constructors Number, Boolean and String respectively when used with property value lookup syntax.

    Hence

    (1).hasOwnProperty("MAX_SAFE_INTEGER")
    

    returns false because the property is inherited from Number.prototype. Similarly hasOwnProperty calls on Boolean values return false because Boolean wrapper objects don't have any innate own properties themselves. But

    ("hello folks").hasOwnProperty("length");
    

    returnstrue because "length" is an own property of the String wrapper object.

    Undefined and Null

    Primitive values of data type Undefined (undefined) or Null (null) are not converted to wrapper objects and generate syntax errors when attempting to call hasOwnProperty on them as a method:

        (undefined).hasOwnProperty("example")  // TypeError
        (null).hasOwnProperty("example")       // TypeError
    

    Symbol and BigInt

    Symbol and BigInt data type values have separate treatment - they were both introduced following a decision that new data types in ECMAScript would not have object wrappers.

    Effectively this means that the JavaScript engine internally implements the syntax of applying Symbol.prototype and BigInt.prototype methods to symbol and bigint data types respectively, but only allows read access to prototyped methods and properties - any attempt to set a property on a symbol or bigint data type generates an error.

    • Neither the Symbol nor BigInt global functions allow the use of new before calls to them.

    • Symbol acts a factory function and returns a new symbol value.

    • BigInt is a type conversion function to convert strings and numbers to bigint data type.

    • Unlike older object wrappers for boolean, number and string data types, attempting to set properties on a symbol or bigint data type never quietly succeeds.

    Object

    Objects ( of data type Object) generally inherit hasOwnProperty from Object.prototype. This inheritance can fail if either hasOwnProperty is redefined somewhere later in the inheritance chain (not a good idea), or if the object was created with null in its inheritance chain before reaching Object.prototype.

    The easiest way to create an object with null at the start of its inheritance chain is by calling

    Object.create( null);
    

    Extending such an object will also create objects which don't inherit from Object.prototype and so can't use hasOwnProperty.

    Note that applying instanceof Object to an object whose prototype chain does not include Object.prototype returns false. Do not use instanceof to determine Object data type.

    Wrapper objects and strict mode.

    In early versions of JavaScript, setting properties on wrapper objects automatically created from primitive values was syntactically correct and did not generate errors. However, the wrapper object was discarded as soon as the wrapper object expression was evaluated. Trying to look up a custom property in later code fails because a new, different wrapper object, lacking the custom property, is used for the lookup.

    Strict mode generates an error if an attempt is made to assign a property value to any primitive value.

    Possible Check Function

    const checkOwnProperty = (obj, propertyName) =>
        (obj && (typeof obj == "object" || typeof obj == "function") &&
        Object.prototype.hasOwnProperty.call( obj, propertyName))
        ? true : false;
    
    // Test:
    var o = {name: "foo"};
    console.log (  "name " + checkOwnProperty( o, "name"))
    console.log (  "foo " +  checkOwnProperty( o, "foo"))
    console.log (  "0 " +  checkOwnProperty( 0, "foo"))

    CheckOwnProperty returns a boolean reflecting if the first argument is of Object data type and has an own property with the same name as the second argument. It returns false for all primitive values.