Наследование Javascript - instanceof не работает? - PullRequest
14 голосов
/ 30 июня 2010

Я пишу простую платформенную игру, используя javascript и html5. Я использую JavaScript в ОО манере. Чтобы заставить работать наследство, я использую следующее:

// http://www.sitepoint.com/blogs/2006/01/17/javascript-inheritance/
function copyPrototype(descendant, parent) {
    var sConstructor = parent.toString();
    var aMatch = sConstructor.match(/\s*function (.*)\(/);
    if (aMatch != null) { descendant.prototype[aMatch[1]] = parent; }
    for (var m in parent.prototype) {
        descendant.prototype[m] = parent.prototype[m];
    }
};

Ради этого поста рассмотрим следующий пример;

function A() {
 this.Name = 'Class A'
}
A.prototype.PrintName = function () {
 alert(this.Name);
}

function B() {
 this.A();
}
copyPrototype(B, A);

function C() {
 this.B();
}
copyPrototype(C, B);

var instC = new C();

if (instC instanceof A)
  alert ('horray!');

Насколько я понимаю, я ожидал увидеть окно с предупреждением об ужасе, потому что C является примером C & B & A. Я ошибаюсь? Или я просто использую неправильный метод для проверки? Или copyPrototype нарушил оператор instanceof?

Спасибо, как всегда, что нашли время, чтобы прочитать это!

Shaw.

Ответы [ 4 ]

16 голосов
/ 30 июня 2010

Проблема в том, что функция copyPrototype копирует только свойства из прототипа конструктора в другой, например, в конце, целевая ссылка [[Prototype]] C.prototype просто указывает на Object.prototype.

Цепочка прототипов instC и прототипы конструктора выглядят так:

                [[Prototype]]
    A.prototype -------------->|-------------------|
                               |                   |
    B.prototype -------------->|  Object.prototype | ---> null
                               |                   |
    C.prototype -------------->|-------------------|
        ^
        |
      <strong>instC</strong>

Оператор instanceof пересекает цепочку прототипов, ваш объект instC, как вы можете видеть, будет иметьтолько в цепочке прототипов C.prototype и Object.prototype.

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

function A() {
  this.Name = 'Class A'
}

A.prototype.PrintName = function () {
  alert(this.Name);
}

function B() {
  //..
}
B.prototype = new A();
B.prototype.constructor = B; // fix constructor property


function C() {
  //..
}

C.prototype = new B();
C.prototype.constructor = C; // fix constructor property

var instC = new C();
if (instC instanceof A)
  alert('horray!');

Теперь цепочка прототипов объекта instC выглядит следующим образом:

           ---------------        ---------------        ---------------
 <strong>instC</strong> --> | C.prototype | -----> | B.prototype | -----> | A.prototype |
           ---------------        ---------------        ---------------
                                                                |
                                                                V
                                                       --------------------
                                                       | Object.prototype |
                                                       --------------------
                                                                |
                                                                V
                                                               null

Рекомендуемая статья:

6 голосов
/ 06 августа 2014

В наши дни вам не нужно .prototype = new Thing (), я думаю, что я опоздал на вечеринку, но вы можете просто использовать Object.create на прототипе родителя, а затем переопределить интересующие вас методыв переопределении.Пример:

var IDataSource = function(){
    throw new Error("Not implemented, interface only");
};

IDataSource.prototype.getData = function(){
    throw new Error("Not implemented.");
};

var BasicDataSource = function(){};
BasicDataSource.prototype = Object.create(IDataSource.prototype);
BasicDataSource.prototype.getData = function(){
    //[do some stuff, get some real data, return it]
    return "bds data";
};

var MockDataSource = function(){};
MockDataSource.prototype = Object.create(IDataSource.prototype);
MockDataSource.prototype.getData = function(){
    //[DONT DO some stuff return mock json]
    return "mds data";
};

MockDataSource.prototype.getDataTwo = function(){
    //[DONT DO some stuff return mock json]
    return "mds data2";
};


var MockDataSource2 = function(){};
MockDataSource2.prototype = Object.create(MockDataSource.prototype);




var bds = new BasicDataSource();
console.log("bds is NOT MockDataSource:", bds instanceof MockDataSource);
console.log("bds is BasicDataSource:", bds instanceof BasicDataSource);
console.log("bds is an IDataSource:", bds instanceof IDataSource);
console.log("bds Data:", bds.getData());


var mds = new MockDataSource();
console.log("mds is MockDataSource:", mds instanceof MockDataSource);
console.log("mds is NOT a BasicDataSource:", mds instanceof BasicDataSource);
console.log("mds is an IDataSource:", mds instanceof IDataSource);
console.log("mds Data:", mds.getData());
console.log("mds Data2:",mds.getDataTwo());


var mds2 = new MockDataSource2();
console.log("mds2 is MockDataSource2:", mds2 instanceof MockDataSource2);
console.log("mds2 is MockDataSource:", mds2 instanceof MockDataSource);
console.log("mds2 is NOT a BasicDataSource:", mds2 instanceof BasicDataSource);
console.log("mds2 is an IDataSource:", mds2 instanceof IDataSource);
console.log("mds2 Data:", mds2.getData());
console.log("mds2 Data2:",mds2.getDataTwo());

Если вы запустите этот код в узле, вы получите:

bds is NOT MockDataSource: false
bds is BasicDataSource: true
bds is an IDataSource: true
bds Data: bds data
mds is MockDataSource: true
mds is NOT a BasicDataSource: false
mds is an IDataSource: true
mds Data: mds data
mds Data2: mds data2
mds2 is MockDataSource2: true
mds2 is MockDataSource: true
mds2 is NOT a BasicDataSource: false
mds2 is an IDataSource: true
mds2 Data: mds data
mds2 Data2: mds data2

Не беспокойтесь о параметрах для конструкторов или о любом таком безумии.

1 голос
/ 16 января 2012

Недавно нашел замечательную реализацию OO javascript Джона Резига (The jQuery Guy!), Которую я буду использовать для будущих проектов;http://ejohn.org/blog/simple-javascript-inheritance/

1 голос
/ 30 июня 2010

Хорошо. Я нашел решение, которое поддерживает работу функции instanceof, а также позволяет передавать параметры конструктора через цепочку наследования. Решение подробно здесь; https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Details_of_the_Object_Model - моя структура класса теперь выглядит так:

function A(p) {
 this.Position = p || new Vector2d(0,0);
}

function B(p) {
 this.base = A;
 this.base(p);
}
B.prototype = new A;

function C(p) {
 this.base = B;
 this.base(p);
}
C.prototype = new B;

if(C instanceof A)
  alert (' it worked!! '); // you now see this alert box!

Спасибо, CMS, за то, что подчеркнули мне, почему это не работает !!

Вы можете проверить полный проект (ну, более старая сборка, которая на момент написания еще не видела, чтобы этот новый метод ОО был полностью реализован) до http://8weekgame.shawson.co.uk/ - просто посмотрите мои последние сообщения.

...