Реализация isInstance в Javascript - PullRequest
       14

Реализация isInstance в Javascript

0 голосов
/ 03 октября 2009

Я определяю, как две функции могут наследовать друг от друга, следующим образом:

Function.prototype.inherit = function(parent){

function proto() {}
proto.prototype = parent.prototype;

this.prototype = new proto();
this.prototype.constructor = this;
this.prototype.parent = parent; 

}

Затем мне нужно определить функцию isInstance, которая будет вести себя как Java instanceOf или PHP instanceof. По сути, isInstance можно использовать для определения того, является ли переменная экземпляром объекта функции, которая наследуется от родительской функции.

Вот что я написал:

Function.prototype.isInstance = function(func){
if(this == func){
    return true;
} else{
    if (this.prototype.parent == undefined || this.prototype.parent == null) {
        return false;   
    } else {
        return this.prototype.parent.isInstance(func);          
    }
}

}

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

Object2.inherit(Object1);

Object2.isInstance(Object1); //returns true

var obj2 = new Object2();

obj2.isInstance(Object1);// obj2.isInstance is not a function

Последний случай выше - это то, что я хочу заставить работать. Как я могу добавить isInstance к экземплярам, ​​а не только к функциям? И для всех гуру javascript, есть ли какие-либо улучшения в моем коде (возможно, в методе наследования)?

Спасибо.

Ответы [ 3 ]

6 голосов
/ 03 октября 2009

Затем мне нужно определить функцию isInstance, которая будет вести себя как Java instanceOf или PHP instanceof.

Что не так с собственным JavaScript instanceof?

Учитывая вашу наследуемую функцию,

function Shape() {};
function Square() {};
Square.inherit(Shape);
alert(new Square() instanceof Shape); // true

instanceof работает, проверяя, находится ли свойство prototype данного конструктора в цепочке прототипов экземпляра. Так, например.

function A() {};
function B() {};
var b= new B();
A.prototype= B.prototype;
alert(b instanceof A); // true

Вот почему instanceof Shape работает, хотя Square.prototype не был создан с использованием new Shape; вместо этого он был создан new proto(), но так как proto и Shape имеют одно и то же свойство prototype, JavaScript не может определить разницу.

Обычно вы не видите цепочку прототипов (хотя Firefox и WebKit делают ее доступной через свойство __proto__), но это способ, которым наследование фактически обрабатывается в JS; Свойство visible Function.prototype используется только для установки начального состояния цепочки прототипов в new -time.

Как добавить isInstance к экземплярам, ​​а не только к функциям?

Object.prototype.isInstance(c)= function() {
    return this instanceof c;
}

Я не уверен, что это действительно сильно тебя порадует! А создание прототипа в Object часто считается дурным тоном, поскольку оно затрагивает буквально каждый объект и может запутать другие сценарии, использующие Object для поиска.

Есть ли какие-либо улучшения в моем коде (может быть, метод наследования)?

Мне нравится ваш метод унаследованного, это один из более легких и JavaScripty способов создания объектной системы.

С instanceof вы можете потерять свойства parent и constructor, если вы не хотели их использовать в других удобных целях. Я бы поставил parent на функцию конструктора (так что это похоже на подкласс, зная его базовый класс), и я бы назвал constructor чем-то другим (уже есть свойство с именем constructor в Firefox, но оно не ' делать то, что вы думаете, и, как правило, лучше избегать).

Единственный недостаток, который я вижу, это то, что вы не можете наследовать функцию конструктора, поэтому каждый раз, когда вы создаете новый подкласс, вы должны написать конструктор, который вызывает базовый конструктор, даже если конструктор вашего подкласса вообще ничего не делает:

function Square() {
    Shape.apply(this, arguments);
}
Square.inherit(Shape);
4 голосов
/ 03 октября 2009

Зачем вам это нужно? У JavaScript нет понятия строгой иерархии классов по причине: это действительно невозможно сделать. Возможно, вы сможете найти решение, которое работает большую часть времени, но я не уверен, что вы сможете охватить все крайние случаи. Кроме того, поскольку в JavaScript нет понятия интерфейсов, тестирование на явное наследование приводит к высокой степени сцепления и может нарушать принципы SOLID .

Гораздо лучший (и более идиоматический) способ решения этой проблемы - использовать duck typing . Просто проверьте наличие необходимого вам метода и затем вызовите его. Просто будьте готовы поймать исключение, если это необходимо (что вы должны делать в любом случае).

1 голос
/ 03 октября 2009

Чтобы оставить на секунду хороший аргумент в пользу разработки и сосредоточиться на своей проблеме, проблема заключается в том, что вы устанавливаете isInstance() как метод для прототипа Function. Это означает, что объекты, которые Function s будут иметь его, в то время как объекты, которых нет (такие как Object1 и Object2 в вашем примере), не будут иметь его.

Я предлагаю вместо того, чтобы пытаться реализовать его как метод, у вас будет статическая функция:

function isInstance(object, ofClass) {
  // Same logic as you have, except use 
  // object.prototype instead of this.prototype
}

Затем вы можете вызвать его как

isInstance(obj2, Object2);
...