Должен ли я использовать полиморфизм в JavaScript? - PullRequest
32 голосов
/ 24 марта 2012

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

Теперь, как своего рода хобби-проект, я бы хотел портировать некоторые приложения, написанные на Java и C #, которые сильноиспользовать полиморфизм в Javascript.

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

Так есть ли альтернатива этому?

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

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?

Ответы [ 5 ]

43 голосов
/ 24 марта 2012

Как уже говорилось, 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, но вы можете легко использовать полифилл (см. Ссылку).

14 голосов
/ 24 марта 2012

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

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

7 голосов
/ 24 марта 2012

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

//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's 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());

1008 *

4 голосов
/ 24 марта 2012

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

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

4 голосов
/ 24 марта 2012

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...