Повышение эффективности памяти фабричного шаблона в JavaScript - PullRequest
0 голосов
/ 04 марта 2019

Простота и гибкость концепции JavaScript «объект» (на самом деле карта) всегда привлекала меня.По этой причине я предпочитаю полностью избегать концепции «прототипов объектов» (и «классов», которые являются просто синтаксическим сахаром для прототипов объектов) и вместо этого выбрать фабричный шаблон.

Я наткнулся на эту статью,заявив, что прототипы объекта сохраняют память по сравнению с фабричным шаблоном: https://medium.freecodecamp.org/class-vs-factory-function-exploring-the-way-forward-73258b6a8d15

"Все методы будут созданы только один раз в объекте-прототипе и будут использоваться всеми экземплярами"

Предположим, у меня есть веб-страница, которая много раз вызывает следующую функцию, чтобы "создать экземпляр" многих объектов AnglePointer:

var AnglePointer = function() {
    var privateMembers = {};
    privateMembers.angle = 0;

    var self = {};

    self.turn = function(degrees) {
        privateMembers.angle += degrees;
        while (privateMembers.angle > 359) {
            privateMembers.angle -= 360;
        }
        while (privateMembers.angle < 0) {
            privateMembers.angle += 360;
        }
    };

    return self;
};

Можно ли повысить эффективность использования памяти, введя такой "общий" объект, какследующее?

var AnglePointer = (function() {
    var sharedMembers = {};

    sharedMembers.turn = function(self, privateMembers, degrees) {
        privateMembers.angle += degrees;
        while (privateMembers.angle > 359) {
            privateMembers.angle -= 360;
        }
        while (privateMembers.angle < 0) {
            privateMembers.angle += 360;
        }
    };

    return function() {
        var privateMembers = {};
        privateMembers.angle = 0;

        var self = {};

        self.turn = function(degrees) {
            shared.turn(self, privateMembers, degrees);
        };

        return self;
    };
})();

Во второй версии реализация функции turn находится внутри объекта sharedMembers, оставляя каждый «экземпляр» AnglePointer с помощью лишь небольшой однострочной функции, вызывающейобщая функция.Будет ли это достигать эффективности памяти, аналогичной эффективности прототипа объекта?Или функция turn каждого экземпляра будет занимать столько же памяти, сколько раньше, несмотря на то, что она является однострочной функцией?Если последнее, как прототипы объектов позволяют избежать этой проблемы?

1 Ответ

0 голосов
/ 04 марта 2019

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

Это основано на недоразумении, что для каждого объекта будет создана новая функция.Это не правильно.Все функции в вашем коде анализируются только один раз и существуют только один раз.То, что создается при каждом создании, - это новое замыкание (спецификация называет его EnvironmentRecord).Если функция не имеет доступа к каким-либо внешним переменным, это закрытие может быть оптимизировано, что делает его более эффективным в использовании памяти (и, возможно, быстрее).

Поэтому ваш «новый шаблон» на самом деле ухудшает ситуацию (но немного),Основная проблема остается:

self.turn = function(degrees) {
   shared.turn(self, privateMembers, degrees);
};

Это невозможно оптимизировать, поскольку функция использует переменные из области видимости своего родителя, и поэтому необходимо создать замыкание.Следовательно, для каждого метода turn должно быть закрытие, и каждый объект должен хранить ссылку на свой собственный закрытый turn.

Закрытые члены могут быть реализованы достаточно точно с помощью символов:

const angle = Symbol.for("angle");

function AnglePointer() {
  return {
   [angle]: 0,
   turn(degrees) {
     this[angle] = (this[angle] + degrees) % 360;
   },
  };
}

Здесь можно надеяться, что turn можно использовать совместно, поскольку он не имеет доступа к каким-либо внешним переменным.

...