Search code examples
javascriptprototype

Prototype extension


In my library, how do I extend prototype of Object thus the users of the library would be able to use that extension?

For example, inside my library I do Object.prototype.greet = () => console.log("Hello"). How do I make it possible for the end user of the library to use that method, just like ({}).greet()?


Solution

  • You are extending Object.prototype incorrectly. Actually, in your question you do it correctly, but in your actual code that you linked in a comment you do it wrong.

    Your current code is this:

    Object.prototype = {
        ...Object.prototype,
        forEach: function(block) {
            return forEachEntryOf(this, block)
        },
        map: function(block) {
            return mapEachEntryOf(this, block)
        },
        filter: function(block) {
            return filterEachEntryOf(this, block)
        }
    }
    

    This cannot work, because you attempt to replace Object.prototype but that property is not writable! (Even if it were, it would mean that any objects created in the past would not have the new functionality, only new objects would, and additionally you'd destroy all kinds of default functionality because all the default methods in the prototype are non-enumerable and wouldn't even be copied over...)

    The reason for why you don't recognize this problem is because you didn't enable strict mode. I recommend to always use strict mode, to catch errors like these.

    With strict mode enabled (adding 'use strict' at the top of the file), you get this error:

    TypeError: Cannot assign to read only property 'prototype' of function 'function Object() { [native code] }'

    The solution is therefore to assign the individual properties or use Object.assign:

    Object.prototype.forEach = function (block) {
      return forEachEntryOf(this, block)
    }
    
    Object.prototype.map = function (block) {
      return mapEachEntryOf(this, block)
    }
    
    Object.prototype.filter = function (block) {
      return filterEachEntryOf(this, block)
    }
    

    ...or...

    Object.assign(Object.prototype, {
      forEach: function(block) {
        return forEachEntryOf(this, block)
      },
      map: function(block) {
        return mapEachEntryOf(this, block)
      },
      filter: function(block) {
        return filterEachEntryOf(this, block)
      }
    })