JavaScript Add a Custom Function or Property to All Objects/Variables

Everything in JavaScript is an object. When you try to access a property on the object, it is looked up on the object but if not found, then looked up on the object’s prototype. The prototype is another object accessible via ob.__proto__ or even better Object.getPrototypeOf(ob). This prototype is also an object which further has its own prototype (hence a chain of prototypes).

So now basically, if you want to add a custom property of any type (integer, string, functions, objects, arrays, etc.) on an object, you could either add it to that object or its prototype. What if for some reason we wanted to add a custom attribute or function to all JS objects though (both existing and new ones)?

Well, all JS objects inherit their prototypes eventually from Object.prototype, i.e., the entire prototype chain we spoke about above ends in Object.prototype and eventually, Object.getPrototypeOf(Object.prototype) or Object.prototype.__proto__ is just null. So to add and make some property accessible on all existing and new objects, we just have to add that on Object.prototype.

Say if we wanted to add a function called dd to all objects that’d log/dump the object values, i.e., instead of console.log(ob) we want to do ob.dd, here’s how that would happen with Object.defineProperty:

Object.defineProperty(Object.prototype, 'dd', {
  get() {
    const v = this.valueOf();
    console.log('Logging: ', v);
    return v;
  },
  set(value) {
    // If some object wants to define its own version of `dd`
    Object.defineProperty(this, 'dd', {
      value,
      configurable: true,
      writable: true,
      enumerable: true,
    });
  },
  configurable: true,
});

Now every object (primitives as well as user-defined) will have a .dd property available on it that’ll dump/log its value as well as return it.

> 'str'.dd
Logging:  str
'str'
> (10).dd
Logging:  10
10
> let foo = { bar: 'baz' }
undefined
> foo.dd
Logging:  { bar: 'baz' }
{ bar: 'baz' }
> function Animal(type) { this.type = type; }; let dog = new Animal('dog');
undefined
> dog.dd
Logging:  Animal { type: 'dog' }
Animal { type: 'dog' }
> dog.dd = 'overwritten'
'overwritten'
> dog.dd
'overwritten'

Bonus: In this example, since the value is also returned, you could safely add .dd to all kinds of expressions (to log them) without breaking the code:

if (foo.bar.dd === 'baz') {}

const dogRef = dog.dd;

Leave a Reply

Your email address will not be published. Required fields are marked *