Dynamic or Computed object creation in Add On SDK - javascript

I am creating an application that stores a unique object based on url of every page visited in Simple-Storage.
var ss = require("sdk/simple-storage");
ss.storage[naming()] = new entryConstructor;
naming() is a function that will churn out a custom name for each object.
You can usually declare variables as a property global object(Window). Is this possible for storage?

I don't really understand what's the question is. Is it :
can I create a variable that directly points to ss.storage ?
or can I access a storage member by using a function returning the name of that member ?
Short answer : Yes, you can and yes you can !
You can of course write without problem :
var ss = require("sdk/simple-storage");
var storage = ss.storage;
/* using 'storage' doesn't matter as long as you don't have identifyers collision */
storage[naming()] = new entryConstructor();
// and you still can refer to storage using ss.storage
ss.storage is much like a javascript object. You just can't add functions members to it (if I'm not mistaken).
If you have a function that returns a string, you can of course access/set a storage property/entry (that's how I like to name it) using that function, assuming the returned value is a javascript compliant member name :
ss.storage[naming()] = new entryConstructor();
where :
function naming() {
/* returns a valid javascript object property names */
// building of the property name here...
}
and entryConstructor is one of the allowed types (presumably an object of your own creation) I like to think of storage entries as JSON serializable datas.
Be carefull when you set entries in ss.storage. You should check for the existence of the entry before attempting to set its value in case you want persistent datas across multiple sessions. If you start by setting values each time a session has begun, old values registered on previous sessions would get lost forever :
let name = naming();
let myEntry;
if (ss.storage.hasOwnProperty(name)) {
// use stored value...
myEntry = ss.storage[name];
} else {
// create value...
myEntry = new entryConstructor()...
}
// make edits... then :
ss.storage[name] = myEntry;
// or handle update on user input, contentScript detach or exports.onUnload
Side notes :
carefull of syntax errors (missing parenthesis, etc.)
When you talk about property global object (window), you're actually talking about context.

Related

Convert var to const javascript

Is it possible to convert a var to a const?
Say in a scenario like this:
var appname = ''
function setAppName(name) {
appname = name // can I convert this to const now?
}
Basically, this is for a parameter level. Parameter needs to be accessible throughout the file and I want to make it const after first assignment. Is this possible?
To add: If there is any other way besides creating an object with to contain this parameter, it would be better (for a more straightforward solution). I will be working on multiple parameters like this and freezing an object will cause the entire object to freeze. I am hoping to do this on the parameter level.
So either change the parameter to become const. OR (this one I dont think is possible) change the scope of the paramter to global:
function setAppName(name) {
const appname = name // can I change the scope and make this global?
}
Thanks.
Put your app name in an object and freeze it.
let appSettings = { name: "" };
function setAppName(name) {
appSettings.name = name;
Object.freeze(appSettings);
}
Freezing prevents adding, removing and modifying the values of the properties in your object so you should call Object.freeze only once after all other settings (if there are more variables you want to make constant) have been set.
You can do this using a object.
const globals = {
appname: ''
}
function setAppName(name) {
globals.appname = name;
Object.freeze(globals)
// After this point, value of appname cannot be modified
}
Thank you for all your inputs.
I was able to find a workaround for what I was trying to achieve.
var appname = ''
function setAppName(name) {
if (appname === '') {
appname = name // can I convert this to const now?
}
}
Although this doesnt convert it to const, I just added a guard on the setter and it will not be able to overwrite the value now (unless otherwise I am going to initialize again to an empty string).
It is not fool-proof, but this will address my need.
Thanks all!

How do you get the value of localstorage, without setting it as a Variable

I know that's probably very confusing, but what I want is to get the value of a localstorage, without setting it like:
var cookies = localStorage.totalCookies
I'd want it to be like this:
var cookies = value of localstorage.totalCookies
I want this so that the var cookies doesn't equal localstorage as I want a one time change to the var cookies, not a constant localstorage updating.
The data type of what is stored in localStorage is always string, even if you wrote a numerical value to it.
To get back the numerical value, you just need to coerce it back to a number, for instance with the unitary +. You should also provide a default value for when the entry is not present in localStorage. If that default value is 0, then you can write it like this:
var cookies = +localStorage.totalCookies || 0;
Or, if you want to test for the presence of that entry, and do another test on whether it is numerical:
if (localStorage.totalCookies === undefined) {
console.log('The totalCookies entry was not found');
// etc..
} else {
var cookies = +localStorage.totalCookies;
if (isNaN(cookies)) {
console.log('The totalCookies entry is not numerical');
// etc...
}
}
This is happening because when you declare a variable to be an object, you're creating a reference to the object, not a duplicate of it. You can use the get & set methods of localStorage, as mentioned by War10ck in the comments above:
Get: localStorage.getItem('totalCookies')
Set: localStorage.setItem('totalCookies', 'some value')
Remove: localStorage.removeItem('totalCookies')
But in general, you need to find a way to clone an object to prevent subsequent tampering with the original. Here's a quick way:
var cloneOfA = JSON.parse(JSON.stringify(a));
You can see a larger discussion about this here:
How do I correctly clone a JavaScript object?

Persistence framework for JavaScript / Google v8

Is there any kind of persistence framework for JavaScript and/or the Google v8 engine?
I want to store (serialize) a whole graph of objects (including, e.g., functions) and re-load it later. JSON is not sufficient, since it does not permit functions to be stored and permits only a tree-like structure (i.e. no two objects referencing the same object).
I need to be able to do that generically (i.e. without knowing the JavaScript code at the time at which I write my program embedding v8), since I want the user of my program to be able to customize it with JavaScript, but I need to store the state of my program (including the state of the customization) and re-load it later. Hence I need to store the state of the JavaScript engine.
Edit:
Example:
Suppose we have the following code:
var obj = { a: 4, b: function (x) { return x + this.a; } }
// ...
if ( ... ) { obj.a = 5; }
// ...
if ( ... ) { var c = 1; obj.b = function (x) { return x + this.a + c; } }
// ...
// now I want to serialize obj
Then is it (without any meta-information about the logic of the program) possible to serialize obj and later deserialize it such that obj.b (2) delivers the same result after deserialization as it did before serialization?
Second Edit: Note the closure.
Unfortunately, what you're trying to do is not currently possible in Javascript. The reason is that closures are not just objects, they're objects bound to an execution context.
Getting past the "this can't be done in javascript" issue and moving into the "what if wrote a patch for V8 to allow this" phase of the answer, this is conceptually difficult. Essentially, for every closure you'd serialize, you would have to serialize the Context object that the closure exists in. It'd be nice to be able to just serialize the HandleScope, but the nature of closures is that you can't reach inside them.
Okay, so let's say you've written a function that can serialize the Context that the closure exists in, and you can even deserialize it. What do you do with it?
The answer to that is 'not much'. Javascript can only be executed in a single context at a time. The closure that you've deserialized doesn't exists in the context that you're trying to pull it back into. You can't really pass data between contexts, and if your function has data bound to free variables, do you use the ones that exist in the deserializer-invoking context, or do you overwrite it with the deserialized context? Conceptually, this is a nightmare.
Ecmascript Harmony had considered giving us nearly-first-class continuations, but it's been pushed form the discussion which I rant about here, but this isn't going to happen any time soon.
HTML5 local storage allows persistence at client level through javascript.
I'm not sure if it will fit your needings, as to being able to store a function you'll need to somewhat give it some markup that allows you to deserialize it when retrieving it from storage (or maybe just store it as plain text and try to eval it on retrieval)
http://diveintohtml5.info/storage.html
I don't think persisting functions is a good practice. I can suggest you the below approach. Turn your JSON data to lets say some class like "MyData". You can find two functions fromJSON, toJSON which will do the magic you want.
var MyData = function(props){
this.temp = "a";
this.getTemp = function(){
return this.temp;
}
this.fromJSON = function(props){
if(props){
this.temp = props.temp;
}
}
this.toJSON = function(){
var props = {};
props.temp = this.temp;
return props;
}
this.fromJSON(props);
}
var obj = new MyData({"temp" : "b"});
var state = obj.toJSON();
// persist state about the object as JSON string
LOCALSTORAGE.put(state); // You can write some HTML5 local storage stuff to persist
var persistedState = LOCALSTORAGE.get(); // You can use the above HTML5 local storage stuff to read the persisted stuff
var newBornObj = new MyData(persistedState);

Google Closure Advanced | Object property not recognized | Dynamic Properties?

Actual Error Code
JSC_INEXISTENT_PROPERTY
Summary
I get this error for the code listed and commented below.
I make the call like this. o_p.page holds user input and one of the properties is indeed tag
Mo.AppBAdder.image_element = vDomBMAdd(o_p.page);
o_p.page is populated by calling the object which hold user input like this:
o_p.page = text_object.getArray();
Is there a way I can do this so Google Closure does not feel the property does not exist?
Setting options is O.K. Also, I don't mind modifying the code a bit if needed.
The constructor for text reads in the user input like this:
Su.text = function (form_elements) {
this.text_object = {};
var key;
for (key in form_elements) { //*u
if (form_elements.hasOwnProperty(key)) {
this.text_object[form_elements[key].name] = form_elements[key].value;
}
}
return this;
};
Snippet of Code
function vDomBMAdd(bookmark_object) {
var link_element = document.createElement('a'),
image_element = document.createElement('img'),
page_element = $a('#' + bookmark_object.tag + '_page'), // error here - inexistent property
Reference
Inexistent means same thing as nonexistent
You have two options: create an extern file that declares the 'tag' property or, perhaps more appropriately given how the property is defined, use a quoted property access:
bookmark_object['tag']
Both of these approaches allow you to access "external" properties and are both compatible with ADVANCED optimizations but using an extern file allows you to declare the expected type of the value held by the property and thus provides better type checking.

Dynamic Javascript - Is This Valid?

can someone tell me if this is valid javascript? I know you couldnt do this sort of thing in c# but js is a much looser language..
var arrayToUse = "arr" + sender.value;
for (i = 0; i <= arrayToUse.length; i++) {
// something..
}
specifically - the dynamic generation of the array name..
update..
so i have an array called arrMyArray which is initialised on document ready. sender.value = "MyArray" - but could be something else eg MyArray2
I want to dyanimcally iterate over the array that is indicated by the sender.value value.
Yes, this is entirely valid.
arrayToUse will be a string (regardless of the value of sender.value — it will be converted to a string), and i will iterate from 0 to the string's length).
One minor note: it should be for (**var** i = 0; …), otherwise i will be treated as a global variable, which will almost certainly end badly if you've got multiple loops running at the same time.
Edit: you want to get the array based on the name? In that case you've got to look it up in whatever context the array is defined.
If it's a global array, use window.
For example:
var arrayName = "arr" + sender.value;
var array = window[arrayName];
…
To get a variable name defined by a variable, you need to use eval, like so:
var arrayToUse = eval("arr" + sender.value);
However, you must be very careful with this, because controlling sender.value would allow someone to hijack your entire application this way. You should usually try to find another solution.
If the variable is defined at the globally, you can look it up as window["arr" + sender.value] instead. This is still not ideal, but is less of a security risk.
What you need to do is access a variable with the name "arr" + sender.value. Accessing the variable whose contents are "arr + sender.value doesn't do what you want -- that's just a string.
To access the variable with that name, you can look it up as a global (globals are members of the window object in the browser):
window["arr" + sender.value]
This is safer and faster than using eval() because it doesn't run code in a JavaScript execution context to evaluate the string -- it just looks up a variable in the window object with that name.

Categories