Можно ли назначить прототип на существующий объект в JavaScript? - PullRequest
2 голосов
/ 28 августа 2011

если у меня есть:

function Base (){
    this.sayHi = function(){
        alert('hi');
    }
}

function Thing (val){
    this.value = val;
}

var bob = new Thing("bob");

Есть ли какой-нибудь способ, которым я могу теперь сказать, что Боб наследует от Base, чтобы я мог вызвать:

bob.sayHi();

В основном есть все методы исвойства базового класса, доступные для этого экземпляра?

Более актуальный пример с решением на основе сообщения CMS:

Здесь элементы могут представлять данные, возвращаемые сервером ..

var Items = [
    { sku: 123, type:'buggy', title:'This is a title', description: 'this is a description' },
    { sku: 234, type: 'baby-monitor', title: 'This is a title 2', description: 'this is a description 2' }
]

function ItemMethods() {
    this.BannerHTML = function () {
        return '<div class="banner _item_' + this.type + '_' + this.sku + '"><h2>' +
            this.title + '</h2><p>' +
            this.description + '</p></div>';
    };
}

Items.GetBySKU = function (code) {
    for (var i = 0; i < Items.length; i++) {
        if (Items[i].sku == code) {
            return Items[i];
        }
    }
};

$.each(Items, function (i, item) {
    ItemMethods.apply(item);
});

alert(Items.GetBySKU(234).BannerHTML());

Любые дальнейшие комментарии или решения с радостью принимаются .. всегда заинтересованы в возможных решениях проблемы; -)

Ответы [ 4 ]

6 голосов
/ 28 августа 2011

Нет. Невозможно назначить другой [[прототип]] существующего существующего объекта , по крайней мере, в соответствии со спецификацией. [[prototype]] является объектом, полученным в результате оценки (иначе называемой «содержится в») конструкторов prototype свойство во время создания нового объекта и не может быть переназначен позже,(Хотелось бы, чтобы он был официально изменен, но, увы, это неподдерживаемая операция, и обычно можно эмулировать различными способами.)

Некоторые браузеры / среды могут выбрать выставление после создания [[прототип]] присвоение с нестандартными подходами.Объект [[prototype]] может быть изменен (например, добавлен в String.prototype), или к целевому объекту могут быть добавлены одноэлементные функции (см. Ответ CMS), или существующие объекты могут быть обернуты(по сути, динамический «подкласс») - в зависимости от требований и ограничений.

Кроме того, в Javascript нет «классов»: хотя «классические ориентированные на единственное наследование классы, ориентированные на наследование», могут быть реализованы в Javascript, ясчитаю ограничивающим ограничивать себя моделью или использовать такую ​​терминологию в целом.Язык хочет быть таким, какой он есть.

Удачного кодирования.

2 голосов
/ 28 августа 2011

В javascript вы можете создать подкласс другого, установив прототип подкласса для экземпляра базового класса:

function BaseClass() {
    this.baseFunction = function() {
    };
};

function SubClass() {
};
SubClass.prototype = new BaseClass;
SubClass.prototype.someFunction = function() {
};

// create an instance of SubClass
var obj = new SubClass;

// SubClass truly extends BaseClass
obj instanceof BaseClass // true
obj instanceof SubClass // true

// the instance has both methods of BaseClass and SubClass
typeof obj.someFunction // Function
typeof obj.baseFunction // Function

Это эквивалент class SubClass extends BaseClass в Java.


Если после этого вы также измените прототипы.

Если вы добавите функции и свойства в прототип конструктора объекта, функции и свойства будут доступны во всех экземплярах.

Вот пример:

function Thing (val){
    this.value = val;
}

var bob = new Thing("bob");

console.log(bob.foo); // undefined

Thing.prototype.foo = function() {
    console.log('foo!');
};

console.log(bob.foo); // function()
bob.foo(); // foo!

Теперь, если вы хотите расширить все экземпляры Thing с помощью Base, вы можете сделать это следующим образом:

var base = new Base;
for (var k in base) {
    Thing.prototype[k] = base[k];
}

Или если вы хотите, чтобы экземпляры Thing расширяли Base: (т.е. не переопределяйте методы, которые уже есть в Thing)

var base = new Base;
for (var k in base) {
    if (Thing.prototype[k]) continue;
    Thing.prototype[k] = base[k];
}

Если вы хотите расширить только уникальный экземпляр объекта, просто присвойте ему:

var bob = new Thing("bob");
var base = new Base();

bob.sayHi = base.sayHi;

bob.sayHi();

Вы также можете вызывать функцию в контексте объекта, даже не назначая функцию объекту:

var base = new Base();
base.sayHi.call(bob);
1 голос
/ 29 августа 2011

Да.

1) Вы можете добавить определение конструктора Base непосредственно к экземпляру bob

Base.call(bob);
bob.sayHi(); //hi

2) Или вы можете дополнить Thing.prototype определением конструктора Base.Экземпляр bob может получить доступ к новым свойствам своего прототипа, даже если он был создан до того, как они были добавлены

var bob = new Thing("bob");
Base.call(Thing.prototype);
bob.sayHi(); //hi
1 голос
/ 28 августа 2011

Обратите внимание, что свойства, которые вы создаете в конструкторе, не имеют ничего общего с prototype конструктора, они собственные свойства объекта, который вы создаете с помощью new Base();, они не наследуются Однако я думаю, что вы хотите сделать это для применения функции конструктора Base к вновь созданному объекту Thing:

function Base (){
    this.sayHi = function(){
        alert('hi');
    }
}

function Thing (val){
    Base.apply(this, arguments);
    this.value = val;
}

var bob = new Thing("bob");
bob.sayHi();

Обратите внимание, что bob не будет наследоваться от Base (у него не будет доступа к свойствам, добавленным к Base.prototype)

bob instanceof Base;  // false
bob instanceof Thing; // true
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...