How to set a localStorage item as function? - javascript

I would like to set a localStorage item as a function, but when I do it gets saved as a string.
localStorage.getData = function (key="def") {
let data = null;
if (this[key] && !_this.isDataAvailableInList(this[key])) {
data = this[key].data;
}
return data;
};
The above function get stored as string and not function.
Note: Kindly do not provide alternatives or other suggestions, I am well aware of alternatives and am curious to know how this works. I have not provided the entire context so lets just assume I am in need of setting a localStorage item as a function

Unfortunately local storage is only about strings. Even arrays or other data are always converted to strings.
For most dead data without cycles you can use of course JSON.stringify and JSON.parse, but in other cases or for code or other Javascript entities unsupported by JSON (like Infinity or undefined) you need to serialize and deserialize yourself.
Javascript provides eval, so you can store the function f converting it first to a string with f+"" and get back the function with eval(s).
This won't work with closures however and moreover you cannot even know if a function is indeed a closure or not in Javascript (so you cannot even raise an error if the impossible operation of serializing a closure is attempted).

Convert the function into a string via .toString(). When you read it, convert it back to a function via new Function(myString).
Example:
No pamameters:
(new Function('var a = 0; return a + 1;'))() === 1
With parameters:
(new Function(['param0'],'var a = param0; return a + 1;'))(100) === 101
Note: The scope of the original function will be lost.

Related

Sequelize.fn : Constructing the update argument outside the call

Issue Description
I'm currently trying to make updates on passwords using sequelize.fn.
I've seen numerous sites, including the Sequelize's manual, yet I found too few articles that approaches my case, and none of them seems to solve it.
Moreover, the function to encrypt the passwords need nested function, so I need to gradually construct the nested function
by putting the successive arguments into variables.
I have not found anything on constructing the functions, thus using sequelize.fn outside the arguments of the functions find and updates.
Additional context
In my case, " crypt('password', gen_salt('bf', 4)) " (in Postgres) needs to become
sequelize.fn('crypt', 'password', sequelize.fn('gen_salt', 'bf', 4)) and to be stored into a variable
When I inject it into the update function, an Fn Object is injected, and the result in the database seems to be a memory address instead of the result of the crypt function.
I may post a code example so you can have a better understanding of what I'm trying to do and I think should be added into the documentation
I did not made this doc issue to resolve my issue, only to point out what I think is lacking in the documentation
I will ask StackOverflow for help regarding my issue.
//Take a format and a value, and applies the functions inside the format onto the value
function recursSequelizeFn (format, value) {
const sequelize = db.sequelize;
let nextId = 0;
let matches;
let finalArgs = {};
//The RegEx finds the function calls of which parameters aren't functions themselves
//As the format string is modified on each loop, I need to initialize the RegEx on each loop
while ((matches = (/(\w+)\(([^(,)]+)?(?:,([^(,)]+))*\)/g).exec(format)) !== null) {
//matches[0] is the whole expression
//matches[1] is the function's name
//matches[>=2] are the arguments
let func = matches[1];
let args = matches.slice(2);
for (let argNo in args) {
//Transforms DB's columns into Sequelize-interpreted columns
//I do not check the column that is found, because I do not have others columns than the one that is being treated
args[argNo] = args[argNo].replace(/seqCol_(\w+)/g, (correspondance, p1, decalage, chaine)=>{return value;});
//If the parameter was previously saved, we replace its reference by its value
args[argNo] = args[argNo].replace(/(#\d+)/g, (correspondance, p1, decalage, chaine)=>{return finalArgs[p1];});
}
//finally, we save the value of the function and replace the whole expression by a reference
finalArgs['#'+nextId]=sequelize.fn(func, ...args);
format = format.replace(matches[0], '#'+nextId);
nextId++;
}
//When the treatment is finished, we return the last value saved into the array
//Or we return the original value if we have not made any change (the array will be empty)
return finalArgs['#'+(nextId-1)]||value;
}
Object.keys(req.message.attributes).map((key)=>{
//req.message.attributes[key] contains the formatting needed to be put onto the value
//e.g. crypt(password, gen_salt('bf', 4))
//req.body[key] contains the value
//e.g. '1234'
let seqValue = util.recursSequelizeFn(req.message.attributes[key], req.body[key]);
req.body[key] = seqValue;
});
//mainModel is a sequelize model
mainModel.update(req.body, {where: {id:req.params.id}, logging:console.log})
.then() //...

Is there a way to tell whether a function parameter was passed as either a literal or as a variable?

I have a function:
function hello(param){ console.log('param is '+param); }
And two calls. First:
hello(123)
Second:
var a=123; hello(a);
Is there any possible way to tell, from within the hello function, whether param was passed as a var or as a literal value?
NOTICE: I am not trying to solve a problem by this. There are many workarounds of course, I merely wanted to create a nice looking logging function. And also wanted to learn the boundaries of JavaScript. I had this idea, because in JavaScript we have strange and unexpected features, like the ability to obtain function parameter names by calling: function.toString and parsing the text that is returned.
No, primitives like numbers are passed by value in Javascript. The value is copied over for the function, and has no ties to the original.
Edit: How about using an object wrapper to achieve something like this? I'm not sure what you are trying to do exactly.
You could define an array containing objects that you want to keep track of, and check if its in there:
var registry = [] // empty registry
function declareThing(thing){
var arg = { value: thing } // wrap parameter in an object
registry.push(arg) // register object
return arg; //return obj
}
function isRegistered(thingObj){
return (registry.indexOf(thingObj) > -1)
}
var a = declareThing(123);
hello(a);
function hello(param){
console.log(isRegistered(param));
}

How to preserve hasOwnProperty on JSON.parsed responseText?

I am a very new developer working on a very simple application as part of my training process - so be gentle.
I have built a function in javascript that accepts arbitrary objects from elsewhere and builds a legal POST request string.
Code:
function postify(oPost){
var out = '';
for (key in oPost){
if (oPost.hasOwnProperty(key) && key >0){
if(oPost[key].value != 'Submit'){
out += '&' + oPost[key].name + '=' + oPost[key].value;
}
}
}
return out;
}
There are many like it, but this one is mine. I elected to use hasOwnProperty as a conditional, as the total list of inherited properties could be really quite long.
One of the objects I would like to pass to this function is a JSON parsed responseText object, which is retrieved like so.
function postData(str){
var http = new XMLHttpRequest();
http.open('POST', 'test.php',false);
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.setRequestHeader("Content-length", str.length);
http.setRequestHeader("Connection", "close");
http.send(str);
var response = JSON.parse(http.responseText);
responseHandle(response);
}
So, the problem - both of these functions do exactly what they are supposed to do, until my responseHandle function routes the response object to the postify function. Manual checking indicates that all expected properties are in place, but postify() won't concatenate a string because those properties seem to have been inherited.
I am fully aware that I could trivially brute force assign all necessary properties - the handler function would do what it needed to either way. I am also aware that my synchronous XMLHttpRequest is deprecated - right this second, it's what I need, and works fine.
So, then, some questions - is there a way to pass my JSON.parsed object such that hasOwnProperty() == true is maintained? Is there a different property or technique I could or should be using in postify() to look for deliberately set key value pairs? Should I just rig the POST to transmit ALL of the inherited properties of the object I am POSTING to PHP?
The problem isn't with hasOwnProperty, it's with key > 0. Unless oPost is an array, the keys will be strings. When you compare a string with a number, the string is converted to a number. But if the string isn't numeric, the conversion will return NaN, and comparing this with 0 is false.
Your function shouldn't have worked for any object, it doesn't matter if it came from JSON.parse(). When JSON.parse returns an object, all the properties are "own".
The fix is to change
if (oPost.hasOwnProperty(key) && key >0){
to
if (oPost.hasOwnProperty(key)){
Objects restored from JSON serialization have no identity beyond "being a plain object", so all you're getting back is a plain, prototype-less object.
However, instead of solving that issue, let's solve the real problem, the one you're trying to use .hasOwnProperty for, by using some modern JS (but not so modern as to use ES6/ES2015 syntax) instead:
function postify(inputObject) {
var keys = Object.keys(inputObject);
return keys.filter(function(key) {
return inputObject[key].value !== 'Submit';
}).map(function(key) {
var e = inputObject[key];
return '&' + e.name + '=' + e.value;
}).join('');
}
on the first line, we get the object's keys using the build in JavaScript Object.keys function. Then we filter the keys, discarding any key for which oPost[key].value is not the string 'Submit'. Then we build a mapping of ["remaining keys", ...] => ["&thing=whatever", "&thing2=moo", ...], and then we join those things without any glue.
Done, no var out required even!

JavaScript cache return value of a function with more than one parameter

I'm going through John Resig's snippets on advanced JavaScript. On #19 he mentions a method to cache the return value of a function. What's the best way to cache the return value of a function that has more than one parameter?
There has to be a much better way than stringify-ing the recieved arguments and using that as the key for the cache object:
function $$(selector, el) {
var cacheKey = JSON.stringify(arguments);
if ($$.cache[cacheKey]) return $$.cache[cacheKey];
return ($$.cache[cacheKey] = NodeListToArray( (el || document).querySelectorAll(s) ));
}
$$.cache = {};
You could use a custom hash function that can operate on objects. But hash functions cause collisions and would require significantly more code than your simple example.
Or you could make the cache n-dimensional, where n is the number of arguments. So essentially this:
function $$(selector, el) {
if ($$.cache[selector] && $$.cache[selector][el])
return $$.cache[cacheKey][el];
// etc.
That assumes that both selector and el are able to be used as object keys. You may need to stringify them in another manner.
Just consider an array element,
JSON (JavaScript Object Notation) works with generic platform, so for easy use you must create a function for your use,
Here, $$.cache[0] is your easy way after reading the cachekey,
If we make thing more easy, we might have security problem later.
I hope this will satisfy your requirement :)

Passing unknown amounts of variables using through a string string and eval and multiple functions and all sorts

In short, I want to use an object literal to allow me to pass a unknown amount of variables in any order to a function. Whilst this is not big deal in theory, in my code, this object literal is passed to a second function called on_change.
on_change works by comparing an element's innerHTML to a string; If it is the same, it sets a timeout to call the function again. If the element's innerHTML is different from the string, then the third parameter is executed, this will either be a function or a string. either way it will execute. I have tested this function plenty and used it for a while now.
However, I cannot seem to get the object literal to flow through the function calls...
var params = { xpos:'false'};
on_change('window_3_cont_buffer','','
if(Window_manager.windows[3].window_cont_buffer.getElementsByTagName(\'content\')[0].getElementsByTagName(\'p\')[0].innerHTML == \'ERROR\'){
alert(Window_manager.windows[3].window_cont_buffer.getElementsByTagName(\'content\')[0].getElementsByTagName(\'p\')[1].innerHTML);
return false;
} else {
Window_manager.windows[3].load_xml(\'location/view.php?location_ID=3\', \'\', ' + params + ' ); }
');
I call this as part of the form submission. After this line, I then call a function to load some content via ajax, which works fine and will trigger the code from the on_change function.
I have tested the load_xml function, it is able to call alert(param.xpos) and get the correct response. I can even added in a check for being undefined so that rest of the times I call load_xml I don't get swamped with alerts.
The load_xml function first sets up the on_change function, then calls the function to load the content to a hidden div. Once the AJAX request has updated that DIV, the on_change function should now call the parse_xml function. This pulls out the information from the xml file. However... The idea of this object literal param is that it can tell this parse_xml function to ignore certain things.
on_change("window_" + this.id + "_cont_buffer", "", "Window_manager.windows[" + this.id + "].parse_xml('" + param + "')");
This is part of load_xml, it works perfectly fine, even with the param bit in there. except, parse_xml does not seem to be able to use that parameter.
I have been able to get it to a point where parse_xml can alert(param) and give [object object] which I would of thought meant that the object literal had been passed through, but when I try and call alert(param.xpos) I get undefined.
I know this is a pig of a problem, and I could get around it by just having the function take a zillion boolean parameters, but its just not a very nice solution.
In effect, what you have is this:
var params = {param: "value"};
foo("bar('one', 'two', 'three');");
...where foo uses eval on that string, something like:
function foo(codestring) {
eval(codestring);
}
...and you're looking for how to embed params in that.
You could do this by serializing the object literal as a string so that when you combine it with the other string, and the total string is evaluated, it gets evaluated. Browsers are slowly getting JSON serialization built in, but for now you want to use jQuery, Prototype, or (if you just want this part) json2.js from Crockford, which offers JSON.stringify for turning objects that can be turned into JSON strings, into JSON strings. So:
var params = {param: "value"};
foo("bar(" + JSON.stringify(params) + ");");
But what you really want to do is refactor so that all of that logic is expressed as code, not code within a string. Then you could pass the literal directly, plus a whole raft of other benefits, including modularization, debugging, etc.
var params = {param: "value"};
function callBar() {
bar(params);
}
foo(callBar);
...changing foo so that it calls a function rather than evaling a string. (eval is to be avoided whenever possible, and to paraphrase the Dalai Lama, it's [almost] always possible.) My sample foo changes to:
function foo(func) {
func();
}
If foo needs to include additional information for bar (and if callBar is set up to handle those extra arguments), it can use Function#call or Function#apply to do that. (Those links are to MDC, but don't worry, they're not Firefox-specific, they've been in the ECMA spec for years and are nearly universally supported.)
You can't put an object inside a string. You would have to serialise the object, add it into the string, then parse it back into a structured object on the other side. The simplest way to do that would be to use JSON (via JSON.stringify or a library fallback for older browsers that don't have it), since JSON evaluates as simple JavaScript.
Note that you wouldn't get the exact same object back, but a new one with the same attributes and properties, and it only works for simple types, so you can't include a function in the object or anything.
However, in any case, passing JavaScript code around in strings is an anti-pattern to be strenuously avoided. Instead use inline functions, and you don't have to worry about what you can and can't put in a string, and you can get rid of all that unreadable wrapping and \-escaping:
var params = {xpos: 'false'};
on_change('window_3_cont_buffer', '', function() {
var w= Window_manager.windows[3];
var ps= w.window_cont_buffer.getElementsByTagName('content')[0].getElementsByTagName('p');
if (ps[0].innerHTML==='ERROR') {
alert(ps[1].innerHTML);
return false;
} else {
w.load_xml('location/view.php?location_ID=3', '', params);
}
});
Some general techniques which may be helpful for you:
// Example of calling function objects given as arguments:
function on_change(foo, callback1, callback2) {
if (foo)
callback1();
else
callback2.call(available_as_this);
}
on_change(foo, function() { your code }, function() { another code });
// Example of function taking arbitrary number of arguments:
function any_params() {
console.log('I got ' + arguments.length + 'arguments!');
console.log('First argument: ' + arguments[0]);
}
any_params('one', 'two', 'three', [], null, {});
See arguments variable and call().
I want to use object literal to allow me to pass a random amount of variables in any order to a function.
Why oh why don't you just create an object which contains the parameters and functions, and pass that around? The receiving function can just test to see if a property of the object is set before trying to use it.

Categories