Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
236 views
in Technique[技术] by (71.8m points)

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

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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 (the last of which is the default when using defineProperty). Extracting a method makes getB a non-constructible function. All this ensures that getB behaves very much like existing built-in methods (or methods provided by the host environment).

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

Object.hasOwn is quite a new method, but in older environments it can simply be replaced by Object.prototype.hasOwnProperty.call or a variant thereof. If you can’t support methods, use this instead:

if(!Object.prototype.hasOwnProperty("getB")){
  Object.defineProperty(Object.prototype, "getB", {
    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 binding.

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", {
    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", {
    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
  });
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...