Можно ли вложить функции в объект в прототипе и получить доступ к базовому объекту?

Update: I can't answer the question, since it's locked, but I have my own solution to this problem at the bottom, working with Jonas' answer

Предположим, у меня есть это дополнение к прототипу. Я буду использовать HTMLElement в качестве примера.

HTMLElement.prototype.MyNamespaceGetThis = function() {
  return this;
}

document.body.MyNamespaceGetThis() вернется document.body

Но если я хочу вложить его в объект

HTMLElement.prototype.MyNamespace = {};
HTMLElement.prototype.MyNamespace.GetThis = function() {
  return this;
}

document.body.MyNameSpace.GetThis() вернет document.body MyNameSpace ({GetThis: ƒ})

Is there a way to make this or any variable return a reference to the base-object? document.body in this case?

Я пробовал несколько вариантов, например

HTMLElement.prototype.MyNameSpace = (function() {
  let that = this
  let obj = Object.defineProperties({}, {GetThis: {
    value: function() {
      console.log(that)
    },
    enumerable: false}})

  return obj;
})()

но это не удается по вполне понятным причинам. Функция запускается только один раз и возвращает ссылку на window

Я провел несколько экспериментов с .bind(), но ни один из них не дал желаемого результата по предсказуемым причинам.


My Solution

Что мне не понравилось в ответе Джонаса, так это то, что он в основном такой же, как MyNamespace().method, где MyNamespace возвращает набор методов.

Постоянные члены также невозможны. Если я хотел хранить данные членов, мне нужен был отдельный объект где-то для этого, и мне это не нравилось.

Мое решение состояло в том, чтобы использовать class, а затем вызывать его особым образом, не требующим памяти.

class MyNamespace {
  constructor(parent) {
    this.parent = parent;
  }

  GetThis() {
    return this.parent;
  }
}

А затем, для этого примера, вы добавляете его в прототип HTMLElement следующим образом.

Object.defineProperties(HTMLElement.prototype, {
    MyNamespace: {
      enumerable: false, writeable: true,
      get: function() {
        let ret = new MyNamespace(this);
        Object.defineProperty(this, 'MyNamespace', {
          enumerable: false,
          writeable: false, // note about this
          value: ret
        });
        return ret;
      },
      enumerable: false, writeable: false
    },
  })

Первый вызов document.body.MyNamespace.GetThis() вернет новый экземпляр класса MyNamespace, а затем вызовет из него GetThis(). Он также изменит document.body на MyNamespace, чтобы напрямую ссылаться на созданный экземпляр, а не создавать каждый раз новый. Это означает постоянные данные.

Что еще мне нравится в этом, так это то, что каждый элемент не несет в себе полный MyNamespace экземпляр, если только он не вызывается в жизни документа.

Как только ссылка обновляется, я замораживаю ее, чтобы ее нельзя было перезаписать, но легко представить, где человеку может понадобиться метод destroy. Вы бы изменили writable на true и что-то в этом роде.

class MyNamespace {
  constructor(parent) {
    this.parent = parent;
  }

  GetThis() {
    return this.parent;
  }

  destroy() {
    Object.defineProperties(HTMLElement.prototype, {
        MyNamespace: {
          enumerable: false, writeable: true,
          get: MyNamespace.factory(this, true),
          enumerable: false, writeable: false
        },
      })
  }

  renew() {
    this.parent.MyNamespace = MyNamespace.factory(this.parent, true)
    // HTMLElement.prototype.MyNamespace can also be set
    // to MyNamespace.factory(this)
  }

  static factory(parent, writeable) {
    return Object.defineProperty(parent, 'MyNamespace', {
      enumerable: false, writeable: writeable,
      value: new MyNamespace(parent)
    }).MyNamespace;
  }
}

person Regular Jo    schedule 13.07.2021    source источник


Ответы (1)


Превратите MyNamespace в геттер и сохраните ссылку на родителя:

function Namespace(parent) {
   return {
     parent,
     /* Your functions here */
   };
 }

Object.defineProperty(HTMLElement.prototype, "namespace", {
  get() { return Namespace(this); },
});

console.log( 
  document.body.namespace.parent === document.body // true
);
person Jonas Wilms    schedule 13.07.2021