Как добавить метод в прототип объекта

1

Существует много способов создания объектов. Тем не менее, я хотел знать, почему я получаю сообщение об ошибке с этим подходом (просто пытаюсь узнать). Что означает "undefined" в сообщении об ошибке? Проблема не связана с тем, как объект был впервые создан, поскольку я пробовал var Obj = {}; и получил тот же результат. Спасибо.

'use strict';
 var Obj=Object.create(null);
 var descriptor={
    value: 37, writable: true, enumerable: true, configurable: true};
 Object.defineProperty(Obj, 'p0' , descriptor);   
 // Next line causes an error: Cannot set property 'f' of undefined
 Obj.prototype.f = function() { //define a method f() on Obj PROTOTYPE
        return ('hello ${this.p0}'); 
  };
 console.log(Obj.f());
  • 1
    Это означает, что Obj.prototype не определен.
  • 2
    Возможный дубликат создания объекта Js с Object.create (null)?
Показать ещё 6 комментариев
Теги:

2 ответа

3
Лучший ответ

Поэтому, в основном, я думаю, что это сводится к фундаментальному непониманию того, что такое prototype. Отдельные экземпляры объекта не имеют .prototype, скорее, они имеют внутреннюю ссылку на прототип конструктора, из которого был создан экземпляр объекта. Ранее это было известно как .__proto__ (AKA dunder-proto), но с тех пор оно официально устарело.

Совсем недавно, чтобы ссылаться на прототип конструктора для экземпляра объекта, вы можете получить доступ к свойству, называемому .constructor. (* Примечание *: .constructor может быть неопределенным в зависимости от того, как был создан объект). Из этого вы можете получить доступ к .prototype.

Аналогичным образом вы можете использовать Object.getPrototypeOf(obj) и Object.setPrototypeOf(obj) где obj - это экземпляр объекта.

Например:

var x = Object.create(null);
console.log("x.prototype", x.prototype);

var y = Object.create({a: "foo"});
console.log("y.prototype:", y.prototype);

.prototype не определен в обоих случаях, потому что экземпляры объектов не имеют свойства прототипа, только конструкторы объектов.

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

function myObj (){
  this.a = "foo";
}
// myObj is a constructor function, which has a prototype that we can set properties on
myObj.prototype.b = "bar";
// obj is an instance of an object, which does not have a prototype property
var obj = new myObj();

console.log("obj.prototype:", obj.prototype);
console.log("Object.getPrototypeOf(obj):", Object.getPrototypeOf(obj));
console.log("obj.constructor.prototype:", obj.constructor.prototype);
  • 0
    Спасибо за ваше объяснение проблемы. Однажды я могу понять, как работает этот язык.
  • 2
    Пожалуйста, __proto__ любые упоминания об устаревшем __proto__ getter / setter. Нет, объекты сами по себе не имеют __proto__ , у них есть внутренняя цепочка прототипов - обычно называемая [[prototype]]. К нему всегда нужно обращаться, используя Object.getPrototype .
Показать ещё 6 комментариев
2

Интересный пример OP заслуживает тщательной проверки, чтобы лучше понять полученную ошибку, а также как улучшить код.

Передача null в Object.create() создает неопределенный объект, который вызывает ошибку. Коррекция включает в себя передачу вместо объекта прототипа, такого как Object. Результат: Obj имеет действительный и определенный объект со всеми методами прототипа Object.

Переменный дескриптор содержит действительный объект, прототип которого кстати доступен как descriptor.constructor.prototype. Подробнее о конструкторах здесь.

Утверждение, добавляющее свойство Obj, является правильным, но имеет ограниченную полезность. Он добавляет свойство непосредственно к Obj, а не к его прототипу. По этой причине добавление метода f к прототипу неудобно, поскольку он может получить доступ только к свойству p0 конкретного объекта Obj из-за свойства, не принадлежащего прототипу Obj. Заключительный оператор указывает, что метод f() работает правильно относительно Obj, когда выполняется следующий код:

'use strict';

// creates undefined object
var Obj=Object.create(null);
console.log("Obj is " + Obj.constructor);

// instantiate Obj of type Object
Obj = Object.create( Object );
console.log("Obj is now instance of Object? " + (Obj instanceof Object));


var descriptor={
value: 37, writable: true, enumerable: true, configurable: true};

// directly add property to object Obj
Object.defineProperty(Obj, 'p0', descriptor);

// adding new method to Obj prototype
 Obj.prototype.f = function() { 
    return ("hello " + Obj.p0); 
  };
  
console.log(Obj.f());

ОП может пожелать пересмотреть код следующим образом:

'use strict';

var descriptor =
{
value: 37, 
writable: true,
enumerable: true,
configurable: true
};


/*  instantiate Obj of type Object
 *  like this:  
 *      var Obj = Object.create( Object );
 *  Or: 
 */
var Obj = Object.constructor;

// make p0 a property of the Obj prototype
Obj.prototype.p0 =  descriptor;

// add method to Obj prototype
 Obj.prototype.f = function() { 
    return ("hello " + this.p0.value); 
  };
  
console.log( Obj.f() );

Преимущество этого второго примера состоит в том, что все объекты, созданные из прототипа Obj, будут иметь метод f и свойство p0.

Обратите внимание: в re 'use strict', следует помнить, что не все браузеры поддерживают его; см. здесь.

  • 1
    Спасибо. Obj.p0 = decriptor действительно новый для меня!
  • 2
    Не совсем, f должен быть на прототипе Obj, а не на самом Obj. Obj.hasOwnProperty("f") должен быть ложным
Показать ещё 5 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню