Должен ли я вкладывать конструкторы и прототипы в JavaScript?

Проект, над которым я работаю в настоящее время, призвал к типу объекта Chain, который сам создает тип объекта Link, который используется только им. В предыдущих проектах я вкладывал конструктор объекта и прототип Link в конструктор для Chain, однако на этот раз я начал задаваться вопросом, был ли это лучший способ сделать это, поскольку я фактически настраивал каждый Chain со своим ' собственное определение Link каждый раз.

Для ясности, это был исходный код, который у меня был:

var Chain = function() {
    var self = this;

    var Link = function(key) {
        this.prop = key;
    };
    Link.prototype.attach = function(args) {
        for (let value of args) {
            this[value.prop] = value.value;
        }
    };

    self.links = [];

}
Chain.prototype.add = function(key) {
    this.links.push(new Link(key));
}

Затем я начал задаваться вопросом, должен ли я просто хранить конструктор и прототип Link в дикой природе, как я сделал с Chain (кстати, он не совсем в дикой природе, он на самом деле содержится внутри объекта) или я должен использовать прототип Chain, чтобы определить Link и сохранить его там.

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

Поэтому я спрашиваю, каков наилучший/наиболее эффективный/разумный способ сделать это?


person dbr    schedule 11.06.2017    source источник
comment
Никогда не вкладывать их друг в друга. Цепляйте их, да, но никогда не вставляйте их друг в друга.   -  person Bergi    schedule 12.06.2017


Ответы (2)


В предыдущих проектах я вкладывал конструктор объекта и прототип Link в конструктор для Chain, однако на этот раз я начал задаваться вопросом, был ли это лучший способ...

Затем я начал задаваться вопросом, должен ли я просто хранить конструктор Link и прототип в дикой природе, как я сделал с Chain

Есть и третий вариант: один Link, который является частным для Chain:

var Chain = (function() {
    function Link() {
        // ...
    }
    // Link.prototype stuff here

    function Chain() {
        // ...
    }
    // Chain.prototype stuff here

    return Chain;
})();

Теперь Chain общедоступный, Link частный, но есть только один Link вместо создания нового для каждого Chain.

Это одинаково хорошо работает с синтаксисом ES2015+ class:

const Chain = (function() {
    class Link {
        // ...
    }

    class Chain {
        // ...
    }

    return Chain;
})();
person T.J. Crowder    schedule 11.06.2017
comment
Это интересный подход, который я не рассматривал, и он мне нравится. Любопытно, что вы также ответили на второй вопрос, который у меня возник некоторое время назад, который является самым аккуратным способом определения конструкторов объектов и их прототипов. Большое спасибо. - person dbr; 12.06.2017

На этот раз я начал задаваться вопросом, является ли это лучшим способом сделать это, поскольку я действительно каждый раз буду настраивать каждый Chain со своим собственным определением Link.

Да, именно по этой причине этого не делать. Вы не хотите создавать тысячи Link классов при создании тысячи цепочек. Всегда размещайте классы рядом друг с другом, а не один в конструкторе другого.

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

Должен ли я просто хранить конструктор Link и прототип, как я сделал с Chain?

Да, это нормально, насколько это возможно. Если «дикий» не является глобальной областью действия, в этом нет ничего плохого. Если вам нужна некоторая инкапсуляция, вы можете использовать модули ES6 для экспорта только «общедоступных» частей этой области или использовать IIFE (например, в ответе @T.J.Crowder).

Другой распространенный метод, который объединяет классы, когда один принадлежит другому, заключается в использовании класса в качестве объекта пространства имен:

var Chain = function() {
    this.links = [];
};
… // Chain.prototype

Chain.Link = function(key) {
    this.prop = key;
};
… // Chain.Link.prototype

То же самое работает с ES6 classes.

person Bergi    schedule 12.06.2017