如何在自定义 Object.prototype.xxx 函数中获取对象本身?

IT技术 javascript object monkeypatching
2021-03-09 10:05:58
Object.prototype.getB = function() {

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

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

如您所见,我想为所有 Object 值创建一个函数。我需要在这个函数中获取对象值然后做一些事情。

1个回答

猴子补丁

你想要做的叫做猴子补丁 ——你改变一个内置的原型。有很多错误的方法可以做到这一点,但我将演示一种目前最正确的方法。

方法

在您的情况下,函数体应该返回this.b. 您可以使用this关键字获取对象本身

如果你真的想打猴子补丁,事先检查函数是否存在以确保向前兼容,并使属性可写、可配置和不可枚举(最后一个是使用时的默认值defineProperty)。提取一个方法使getB一个不可构造的函数。所有这些确保其getB行为与现有的内置方法(或宿主环境提供的方法)非常相似。

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

Object.hasOwn是一种相当新的方法,但在较旧的环境中,它可以简单地替换为Object.prototype.hasOwnProperty.call或其变体。如果您不能支持方法,请改用它:

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

请记住,箭头函数不能用于此目的,因为它们没有自己的this绑定。

吸气剂 / 吸气剂

另一种方法是使用吸气剂。考虑一下:

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

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

如何将一个indexOfB吸气剂Array的原型是什么样子?我们不能使用上述方法并替换valueget,否则我们将得到:

TypeError: 当指定了 getter 或 setter 时,属性描述符不得指定值或可写

该属性writable需要从描述符中完全删除现在value可以替换为get

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

也可以通过向set描述符添加属性来指定 setter

if(!Array.prototype.hasOwnProperty("indexOfB")){
  Object.defineProperty(Array.prototype, "indexOfB", {
    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
  });
}