Есть ли «правильный» способ наследования в JavaScript? Если так, то, что это? - PullRequest
9 голосов
/ 22 октября 2008

Я пытался узнать, как добавить тестирование к существующему коду - сейчас читаю чтение Эффективная работа с устаревшим кодом . Я пытался применить некоторые принципы в JavaScript, и теперь я пытаюсь извлечь интерфейс.

В поиске создания интерфейсов в JavaScript я не могу найти много - и то, что я нахожу относительно наследования, кажется, что это несколько разных способов. (Некоторые люди создают свои собственные базовые классы, чтобы предоставить полезные методы, упрощающие наследование, некоторые используют функции, некоторые используют прототипы).

Какой правильный путь? Есть простой пример для извлечения интерфейса в JavaScript?

Ответы [ 5 ]

13 голосов
/ 22 октября 2008

Нет определенного правильного пути , потому что так много людей делают так много разных вещей ... Есть много полезных шаблонов.

Крокфорд предполагает, что вы «идете в ногу со временем» или пишете javascript таким образом, который соответствует прототипу javascript.

Конечно, он продолжает показывать, что оригинальная модель, предложенная Netscape, на самом деле сломана. Он называет его «псевдоклассическим» и указывает на большое заблуждение и ненужную сложность, которые связаны с следованием этой модели.

Он написал функцию «объект» как лекарство (теперь известное как Object.create ()). Это позволяет использовать некоторые очень мощные образцы прототипов.

Не всегда легко разработать чистый интерфейс, когда вам приходится работать с устаревшим javascript, особенно если вы работаете с большими системами, обычно с несколькими библиотеками, каждая из которых реализует уникальный стиль и свой шаблон наследования. В целом, я бы сказал, что «правильный способ» наследования - это тот, который позволяет вам написать чистый интерфейс, который ведет себя хорошо в контексте вашего унаследованного кода, но также позволяет вам реорганизовывать и устранять старые зависимости со временем .

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

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

С другой стороны медали, я уверен, вы могли бы поспорить за то, что вы выбрали библиотеку, применили ее в своей команде и соответствовали ее шаблонам наследования и соглашениям об интерфейсе.

6 голосов
/ 22 октября 2008

В javascript нет классов, только объекты.
Но если вы настаиваете на эмуляции объектно-ориентированной модели на основе классов, вы можете использовать это:

function ChildClass() {
    ParentClass.call(this);
    // Write the rest of your constructor function after this point.
};
ChildClass.prototype = jQuery.extend({}, ParentClass.prototype, ChildClass.prototype);

jQuery.extend - это функция «мелкого копирования» из библиотеки jQuery. Вы можете заменить его любой другой функцией копирования / копирования объектов.

5 голосов
/ 22 октября 2008

Вы смотрите на две разные вещи.

Сначала у вас есть интерфейсы. Наиболее приемлемым способом реализации этого является Duck Typing («если он выглядит как утка и крякает как утка, то это утка») Это означает, что если объект реализует набор методов интерфейса, то это тот интерфейс. Вы реализуете это, имея массив имен методов, которые определяют интерфейс. Затем, чтобы проверить, реализует ли объект, который мешает, вы видите, реализует ли он эти методы. Вот пример кода, который я написал:

function Implements(obj, inter)
{
    var len = inter.length, i = 0;
    for (; i < len; ++i)
    {
        if (!obj[inter[i]])
            return false;
    }
    return true;
}

var IUser = ["LoadUser", "SaveUser"];

var user = {
        LoadUser : function()
        {
            alert("Load");
        },

        SaveUser : function()
        {
            alert("Save");
        }
    };

var notUser = {
        LoadUser : function()
        {
            alert("Load");
        }
    };

alert(Implements(user, IUser));
alert(Implements(notUser, IUser));

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

function InheritObject(base, obj)
{
    for (name in base)
    {
        if (!obj[name])
            obj[name] = base[name];
    }
}

var Base = {
        BaseFunc : function() { alert("BaseFunc from base"); },
        InheritFunc : function() { alert("InheritFunc from base"); }
    }

var Inherit = {
        InheritFunc : function() { alert("InheritFunc from inherit"); },
        AnotherFunc : function() { alert("AnotherFunc from inherit"); }
    }

InheritObject(Base, Inherit);

Inherit.InheritFunc();
Inherit.BaseFunc();
Inherit.AnotherFunc();

Base.BaseFunc();
Base.InheritFunc();

Возможно, вы захотите взглянуть на http://www.mootools.net. У него есть моя любимая реализация классов. Вы также определенно хотите проверить "Pro Javascript Design Patterns"

http://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X

Эта книга подробно описывает, как эмулировать ООП в javascript.

3 голосов
/ 22 октября 2008

Также проверьте Base.js. Дина Эдвардса Вы можете взглянуть на это здесь , пост блога не требует пояснений.

0 голосов
/ 22 октября 2008

Прототип предлагает свой собственный вариант наследования от http://www.prototypejs.org/api/class/create:

var Animal = Class.create({
  initialize: function(name, sound) {
    this.name  = name;
    this.sound = sound;
  },

  speak: function() {
    alert(this.name + " says: " + this.sound + "!");
  }
});

// subclassing Animal
var Snake = Class.create(Animal, {
  initialize: function($super, name) {
    $super(name, 'hissssssssss');
  }
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...