How to get object itself in custom Object.prototype.xxx function?

前端 未结 1 1359
被撕碎了的回忆
被撕碎了的回忆 2020-12-21 23:51
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

1条回答
  •  礼貌的吻别
    2020-12-22 00:07

    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
      });
    }
    

    0 讨论(0)
提交回复
热议问题