1
Object.prototype.getB = function() {

  // how to get the current value a
  return a.b;

};
const a = {b: 'c'};
a.getB();

As you can see, I want to make a function to all Object value. And I need to get the object value in this function then do something.

Sebastian Simon
  • 14,320
  • 6
  • 42
  • 61
Harry Yu
  • 181
  • 1
  • 2
  • 11

1 Answers1

2

Monkey Patching

What you want to do is called monkey patching — you mutate a built-in prototype. There are many wrong ways to do it, but I’ll demonstrate a way that is currently the most correct way.

Methods

In your case, the function body should return this.b. You can get the object itself with the this keyword.

If you really want to monkey-patch, check for the function’s existence beforehand to ensure forward-compatibility and make the property writable, configurable and non-enumerable. Extracting a method makes getB a non-constructible method. All this ensures that getB behaves very much like existing built-in methods (or methods provided by the host environment).

if(!Object.prototype.hasOwnProperty("getB")){
  Object.defineProperty(Object.prototype, "getB", {
    enumerable: false,
    writable: true,
    configurable: true,
    value: {
      getB(){
        return this.b;
      }
    }.getB
  });
}

If you can’t support methods, use this instead:

if(!Object.prototype.hasOwnProperty("getB")){
  Object.defineProperty(Object.prototype, "getB", {
    enumerable: false,
    writable: true,
    configurable: true,
    value: function getB(){
      return this.b;
    }
  });
}

Keep in mind that arrow functions cannot be used for this purpose since they don’t have their own this context.

Getters / Setters

An alternative is to use a getter. Consider this:

const arr = [
    "a",
    "b",
    "c",
  ];

console.log(arr.indexOfB); // 1

How would an indexOfB getter on the Array prototype look like? We can’t use the above approach and replace value by get, or else we’ll get:

TypeError: property descriptors must not specify a value or be writable when a getter or setter has been specified

The property writable needs to be removed entirely from the descriptor. Now value can be replaced by get:

if(!Array.prototype.hasOwnProperty("indexOfB")){
  Object.defineProperty(Array.prototype, "indexOfB", {
    enumerable: false,
    configurable: true,
    get: {
      indexOfB(){
        return this.indexOf("b");
      }
    }.indexOfB
  });
}

A setter can also be specified by adding a set property to the descriptor:

if(!Array.prototype.hasOwnProperty("indexOfB")){
  Object.defineProperty(Array.prototype, "indexOfB", {
    enumerable: false,
    configurable: true,
    get: {
      indexOfB(){
        return this.indexOf("b");
      }
    }.indexOfB,
    set: {
      indexOfB(newValue){
        // `newValue` is the assigned value.
        // Use `this` for the current Array instance.
        // No `return` necessary.
      }
    }.indexOfB
  });
}
Sebastian Simon
  • 14,320
  • 6
  • 42
  • 61