Частные нестатические переменные в полимере?

Как можно иметь частные нестатические переменные в полимере?

В:

<polymer-element name="component-one">
   <script>

       Polymer('component-one', {
       internalState = 1,    
       ready() {
               this.anotherInternalState = 1;
           }
           /* more variables and functions */
      });

   </script>

</polymer-element>

как internalState, так и anotherInernalState подвергаются внешней (например, доступной через что-то вроде:

document.querySelector('component-one').internalState

(что может быть нежелательным при изменении internalState извне, делает компонент неустойчивым.)

где как в:

<polymer-element name="component-two">
   <script>

    (function() { 

       var internalState = 1;


       Polymer('component-two', {
          /* some variables and functions */
      });
    })();

   </script>

</polymer-element>

internalState скрыт снаружи, но он статичен и разделен во всех экземплярах компонента.

Есть ли способ иметь частную нестатическую переменную внутри полимерного объекта?

Ответ 1

Это скорее вопрос с чисто JavaScript, чем вопрос Полимера. Начиная с ES5 в JavaScript нет "частных экземпляров", хотя ES6 предлагает несколько новых инструментов.

Мое предложение состоит в том, чтобы использовать старое соглашение о добавлении переменных частного экземпляра с подчеркиванием (_internalState).

В противном случае вам нужно запутаться с картами и закрытием.

Ответ 2

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

var instances = [];
Polymer('foo-bar', {
    // ...
    attached: function() {
        instances.push(this);
    },
    detached: function(){
        instances = instances.filter(function(instance){
            return instance !== this;
        }.bind(this));
    },
    // ...
});

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

var instances = [], contexts = [];
Polymer(/* ... */);
function getPrivateContext(instance){
    return contexts[instances.indexOf(instance)];
}

И соедините все это элегантно:

var instances = [];
Polymer('foo-bar', {
    // ...
    attached: function() {
        instances.push({
            element: this,
            context: {}
        );
    },
    detached: function(){
        instances = instances.filter(function(instance){
            return instance.element !== this;
        }.bind(this));
    },
    // ...
    whatever: function(){
        var privateThis = private(this);
    }
});
function private(element){
    return instances.filter(function(instance){
        return instance.element === element;
    })[0].context;
}

Не тестировал, но он должен работать.

Ответ 3

В ES6, где у вас есть символы, вы можете сделать

<polymer-element name="my-element">
    <script type="text/javascript">        
        (function () {
            // visible to all my-element instances
            var privateKey = Symbol('Symbol description');

            Polymer({
                ready: function () {
                    // initialize object containing private properties
                    this[privateKey] = {}; // only you can touch this

                    // only those with access to 'privateKey' can can access
                    // your new ContactCard
                    this[privateKey].contactCard = new ContactCard(this);
                },
                // public method
                publicMethod: function() {

                    // accessing private data
                    doSomethingWith(this[privateKey].contactCard);
                }
            };);
        })();
    </script>
</polymer-element>

с использованием символов. Это должно препятствовать доступу пользователей вашего элемента к определенным данным по вашему выбору. Поскольку все экземпляры могут просматривать ключ, данные все еще видны для всех экземпляров вашего элемента. Дополнительная информация: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol

Ответ 4

Здесь подход, который я сделал:

<script type="text/javascript">        
    (function () {
        var privateStatic = Math.random();

        function ContactCard(component) {
            var mouseoverTimer;
            var privateInstance = Math.random();

            component.addEventListener('mouseenter', function () {
                mouseoverTimer = setTimeout(function () {
                    alert(privateStatic);
                    alert(privateInstance);
                }, 250);
            });

            component.addEventListener('mouseleave', function () {
                clearTimeout(mouseoverTimer);
            });

            return {

            };
        };

        Polymer({
            ready: function () {
                new ContactCard(this);
            }
        });
    })();
</script>

Я не показываю его в примере, но вы все равно можете использовать способ component.$.someElementId доступа к элементам по идентификатору в корне тени.

Кроме того: я чувствую, что этот стиль программирования позволяет вам разделить ваши компоненты немного дальше от Polymer, если вы в этом заняты. Фактически вы можете использовать component.shadowRoot.getElementById('someElementId') и component.shadowRoot.querySelector('#someElementId'), а также другие тактики, если вы выберете, и они будут работать в других браузерах, кроме Chrome (включая IE9 и выше).

Ответ 5

Просто переместите назначение значения в одну из функций прототипа, например:

<polymer-element name="component-two">
    <script>

        (function() { 

            var internalState;

            Polymer('component-two', {

                ready: function() {
                    internalState = 1; // Replace static value with something instance specific
                }
            });
        })();

   </script>
</polymer-element>