Подтвердить что ты не робот

Должен ли я использовать полиморфизм в javascript?

Я программист, который запрограммирован на нескольких языках, как функциональных, так и ориентированных на OO. Я также запрограммировал некоторый Javascript, но никогда не использовал (или не использовал) полиморфизм в нем.

Теперь, как вид проекта для хобби, я хотел бы перенести некоторые приложения, написанные на Java и С#, которые сильно используют полиморпизм для Javascript.

Но на первый взгляд я читал много "Это возможно, но..."

Так есть альтернатива?

Пример того, что я хотел бы написать в JS в pseudolang:

abstract class Shape{ { printSurface() } ;  }

class Rect : Shape() {  printSurface() { print (sideA*sideB}}

class Circle : Shape() {  printSurface() { print { pi*r*r }}

TheApp { myshapes.iterate(shape s) {s.printSurface() } }

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

Я хотел бы добиться такого поведения. Я знаю, что это полиморфизм, но есть ли какие-либо другие "шаблоны", которые я пропускаю, чтобы достичь такого поведения или я должен изучить возможности наследования в Javascript?

4b9b3361

Ответ 1

Как сказано, JavaScript - это динамически типизированный язык, основанный на прототипном наследовании, поэтому вы не можете использовать один и тот же подход для типизированных языков. JS-версия того, что вы написали, может быть:

function Shape(){
  throw new Error("Abstract class")
}

Shape.prototype.printSurface = function () {
  throw new Error ("Not implemented");
}

function Rect() {
  // constructor;
}

Rect.prototype = Object.create(Shape.prototype);
Rect.prototype.printSurface = function() {
  // Rect implementation
}

function Circle() {
  // constructor;
}

Circle.prototype = Object.create(Shape.prototype);
Circle.prototype.printSurface = function() {
  // Circle implementation
}

Затем в вашем приложении:

var obj = new Circle();

if (obj instanceof Shape) {
    // do something with a shape object
}

Или с утиным типом:

if ("printSurface" in obj)
    obj.printSurface();

// or

if (obj.printSurface)
    obj.printSurface();

// or a more specific check
if (typeof obj.printSurface === "function")
    obj.printSurface();

У вас холод также есть Shape как объект без какого-либо конструктора, что он более "абстрактный класс" вроде:

var Shape = {
    printSurface : function () {
        throw new Error ("Not implemented");
    }
}

function Rect() {
  // constructor;
}

Rect.prototype = Object.create(Shape);
Rect.prototype.printSurface = function() {
  // Rect implementation
}

function Circle() {
  // constructor;
}

Circle.prototype = Object.create(Shape);
Circle.prototype.printSurface = function() {
  // Circle implementation
}

Обратите внимание, что в этом случае вы больше не можете использовать instanceof, так что или вы откажитесь от утиного ввода текста или используете isPrototypeOf, но доступны только в последних браузерах:

if (Shape.isPrototypeOf(obj)) {
    // do something with obj
}

Object.create недоступен в браузере, который не реализует спецификации ES5, но вы можете легко использовать polyfill (см. ссылку).

Ответ 2

"Шаблон" в игре здесь будет "интерфейсом". Пока все объекты в коллекции myshapes реализуют метод printSurface(), вы будете в порядке.

Поскольку Javascript является динамически типизированным языком, объекты в коллекции не обязательно должны быть связаны вообще.

Ответ 3

Я знаю, что это можно сделать с помощью прототипов, но я не мастер его использования. Я предпочитаю подход объектного литерала (проще визуализировать и имеет область "private")

//shape class
var shape = function() {
    //return an object which "shape" represents
    return {
        printSurface: function() {
            alert('blank');
        },
        toInherit: function() {
            alert('inherited from shape');
        }
    }
};

//rect class
var rect = function() {
    //inherit shape
    var rectObj = shape();

    //private variable
    var imPrivate = 'Arrr, i have been found by getter!';

    //override shape function
    rectObj.printSurface = function(msg) {
        alert('surface of rect is ' + msg);
    }

    //you can add functions too
    rectObj.newfunction = function() {
        alert('i was added in rect');
    }

    //getters and setters for private stuff work too
    rectObj.newGetter = function(){
        return imPrivate;
    }

    //return the object which represents your rectangle
    return rectObj;
}



//new rectangle
var myrect = rect();

//this is the overridden function
myrect.printSurface('foo');

//the appended function
myrect.newfunction();

//inherited function
myrect.toInherit();

//testing the getter
alert(myrect.newGetter());

Ответ 4

Как говорит Уэстон, если у вас нет необходимости в наследовании, тогда типичный тип динамического языка, такой как Javascript, дает вам полиморфизм, поскольку в самом языке нет требования для строго типизированного базового класса или интерфейса.

Если вы хотите использовать наследование и делать такие вещи, как легко реализовать реализацию суперкласса, то это может быть достигнуто с помощью прототипов или объектных литералов, как показано Joeseph.

Еще одна вещь - посмотреть Coffescript, поскольку это скомпилируется до Javascript, давая вам всю доброту OO в простом синтаксисе. Он напишет все материалы прототипирования bollerplate для вас. Недостатком является то, что он добавляет этот дополнительный этап компиляции. Тем не менее, написание простой иерархии классов, такой как ваш пример выше, а затем просмотр того, что javascript всплывает в результате, помогает показать, как все это можно сделать.

Ответ 5

В другой заметке. Если вы хотите запрограммировать Javascript в стиле OO с помощью классов, вы можете изучить многие "класс-системы" для Javascript. Одним из примеров является Joose (http://joose.it).

Многие клиентские рамки реализуют свою собственную систему классов. Примером этого является ExtJS.