问题
How is it possible to have private non-static variables in polymer?
In:
<polymer-element name="component-one">
<script>
Polymer('component-one', {
internalState = 1,
ready() {
this.anotherInternalState = 1;
}
/* more variables and functions */
});
</script>
</polymer-element>
both internalState and anotherInernalState are exposed to outside (e.g. accessible through something like:
document.querySelector('component-one').internalState
(Which might be undesirable when changing internalState from outside makes the component unstable.)
where as in:
<polymer-element name="component-two">
<script>
(function() {
var internalState = 1;
Polymer('component-two', {
/* some variables and functions */
});
})();
</script>
</polymer-element>
internalState is hidden from outside but it is static and shared across all the instances of the component.
Is there a way to have a private non-static variable inside polymer object?
回答1:
This is more of a pure JavaScript question than a Polymer question. As of ES5 there are no 'private instance members' in JavaScript, although ES6 brings some new tools.
My suggestion is to use the old convention of prepending private instance variables with underscore (_internalState
).
Otherwise, you have to get tricky with maps and closures.
回答2:
You'd have to maintain a private static context for each instance of your element. There are some hints in the doc as to how to do that. First off I'd start with keeping track of live instances:
var instances = [];
Polymer('foo-bar', {
// ...
attached: function() {
instances.push(this);
},
detached: function(){
instances = instances.filter(function(instance){
return instance !== this;
}.bind(this));
},
// ...
});
Then you could add a private method to get access to your instance private context:
var instances = [], contexts = [];
Polymer(/* ... */);
function getPrivateContext(instance){
return contexts[instances.indexOf(instance)];
}
And wire it up all together more elegantly:
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;
}
Haven't tested it but it should work.
回答3:
In ES6 where you have symbols, you can do
<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>
using Symbols. This should prevent users of your element from accessing certain data of your choice. Since all instances can view the key, the data is still visible to all instances of your element. More info: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol
回答4:
Here's the approach I've taken:
<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>
I don't show it in the example, but you can still use the component.$.someElementId
way of accessing elements by id in the shadow root.
Aside: I feel like this style of programming allows you to decouple your components a little further from Polymer if you're into that sort of thing. You can actually use component.shadowRoot.getElementById('someElementId')
and component.shadowRoot.querySelector('#someElementId')
as well as other tactics if you choose and they will work in other browsers besides Chrome (including IE9 and up.)
回答5:
Just move the value assignment in one of the prototype functions, like:
<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>
来源:https://stackoverflow.com/questions/24461109/private-non-static-variables-in-polymer