save variables in local storage and then compare - javascript

Due to the site I am working on I need to first store some variables and then compare them.
I can't get my fiddle to work if my values are indeed equal. I have never used local storage before so not sure if I am doing it correctly.
Fiddle is http://jsfiddle.net/ktcle/QuLub/2/
I have just added in the values in the divs so that it is easy to see what they are and won't be in the code.
var userID = user(2, 7),
playerID = player(14),
savedUserid,
savedUPlayerid;
function user(a, b) {
return a * b
}
function player(a) {
return a
}
function saveData(x) {
localStorage.setItem('userID', x);
}
function saveData(x) {
localStorage.setItem('playerID', x);
}
savedUserid = parseInt(localStorage.getItem('userID'));
savedPlayerid = parseInt(localStorage.getItem('playerID'));
if (typeof savedUserid === typeof savedPlayerid) {
alert (true)
}
else {
alert (false)
}

There were a few problems... you werent saving the values, and you were comparing typeof instead of the actual values (as someone else pointed out). Anyway, this is working:
http://jsfiddle.net/QuLub/7/
var userID = user(2, 7),
playerID = player(14),
savedUserid,
savedUPlayerid;
function user(a, b) {
return a * b
}
function player(a) {
return a
}
function saveData(type, value) {
localStorage.setItem(type, value);
}
saveData('userID', userID);
saveData('playerID', playerID);
console.log(localStorage.getItem('userID'));
savedUserid = parseInt(localStorage.getItem('userID'));
savedUPlayerid = parseInt(localStorage.getItem('playerID'));
if (savedUserid === savedUPlayerid) {
alert (true)
}
else {
alert (false)
}
document.getElementById("user").innerHTML = savedUserid;
document.getElementById("player").innerHTML = savedUPlayerid;

The first and main problem I notice is that you never call the saveData function. Also, as you can see, you have 2 functions with the same name, so they will just replace one another.
function saveData(x) {
localStorage.setItem('userID', x);
}
function saveData(x) {
localStorage.setItem('playerID', x);
}
Because of this,
localStorage.getItem('userID')
and
localStorage.getItem('playerID')
are both null.
The second mistake is that you misspelled: savedPlayerid as savedPlayrerid.
Working jsFiddle with the modifications: http://jsfiddle.net/QuLub/3/

Related

Change a native function's body while keeping the same "identity"

I'm looking into a way to change a native JS function body, while making it not possible to see that it has been changed. Let's take an example with document.hasFocus():
document.hasFocus = ()=>true;
This method works well to spoof focus, but it can be easily detected that it was modified:
document.hasFocus.toString() // -> "()=>true"
Is there any way, in which I can modify such a function while making it impossible to see it has been tampered with?
You can overwrite toString method in Function prototype, and do something like that:
// https://stackoverflow.com/questions/1833588/javascript-clone-a-function
Function.prototype.clone = function() {
var that = this;
var temp = function temporary() {
return that.apply(this, arguments);
};
for (var key in this) {
if (this.hasOwnProperty(key)) {
temp[key] = this[key];
}
}
return temp;
};
Function.prototype.__oldToString = Function.prototype.toString.clone();
function __toStringHooked() {
if ((this.name == "")||(this.name == "hasFocus")) // on Firefox, hasFocus doesn't have any name
{
return eval+"" // this matches regexp
} else {
return this.__oldToString(); // we're returning default value
}
}
Function.prototype.toString = __toStringHooked
document.hasFocus = () => true
The code above is from Th3B0r3dD3v3l0p3r's GitHub repo, you can check it if you want: https://github.com/Th3B0r3dD3v3l0p3r/focus-spoofer/

Unexpected results from a function

I have the following two blocks of code that I am trying to debug.
function getSectionId(target){
let element = target;
if(element.hasAttribute('id')){
console.log(element.id);
return element.id;
}
else {
getSectionId(element.parentElement);
}
};
function coverageLimitHandler(event) {
const target = event.target;
if (target.getAttribute('data-status') !== 'set') {
let itemBlock = addLineItem();
let sectionId = getSectionId(target);
let attribute = '';
console.log(sectionId);
}
}
The event fires and the functions run, but the above gives the unexpected following results
//first-coverage-section (this one is expected.)
//undefined (this is expected to be the same, but is not.)
And I cannot for the life of me figure out why this is happening.
the problem is that your recursive call is not returning anything.
when you do:
getSectionId(element.parentElement);
it will call the function and maybe some day, the if above
if(element.hasAttribute('id')){
console.log(element.id);
return element.id;
}
will return something, but that won't be returned to the previous calls therefore your main call wont have anything to return, so to solve this you need to do this:
function getSectionId(target){
let element = target;
if(element.hasAttribute('id')){
console.log(element.id);
return element.id;
}
else {
// add this return and your function will work correctly.
return getSectionId(element.parentElement);
}
};
basically you have something like this:
function recursiveNotWorking(n) {
if (n === 5) {
return "something"
} else {
// you dont return anything, then something never bubbles up
recursiveNotWorking(n + 1);
}
}
function recursiveWorking(n) {
if (n === 5) {
return "something"
} else {
// we return something
return recursiveWorking(n + 1);
}
}
console.log("NW: ", recursiveNotWorking(1));
console.log("Working: ", recursiveWorking(1));
You need to return the result of the recursive call:
const getSectionId = target => {
if (target.hasAttribute('id') {
return target.id;
}
// You should also check that parentElement exist
// Otherwise you might reach the root node and then parentElement could become null
return getSectionId(target.parentElement);
};
Alos, this can be re-written as well as one liner:
const getSectionId = t => t.id || getSectionId(t.parentElement)
You don't have return in the first function and you don't check on undefined. Also you don't need to use the element variable. It's useless.
Maybe this will work:
function getSectionId(target){
if (typeof target === 'undefined') return null;
if(target.hasAttribute('id')){
console.log(target.id);
return target.id;
}
return getSectionId(target.parentElement);
}

localStorage returning undefined until refresh?

I've noticed a bug, or what I believe to be a bug, in the localStorage which is hard to explain but I'll try.
I'm writing a simple local shopping cart. In order for things to work properly I check if the storage already exists and put an empty array into it if that isn't the case.
However, even after this check localStorage still remains undefined untill the second time I refresh the page. See the code below:
const cart = function(name) {
this.storageNamespace = name;
this.get = store.get(this.storageNamespace);
};
cart.prototype.set = function (data) {
store.set(this.storageNamespace, data);
}
cart.prototype.add = function (item) {
if (this.get === undefined) {
store.set(this.storageNamespace, []);
}
let cart = this.get;
if (cart.length !== 0) {
for (let i = 0; i < cart.length; i++) {
if (cart[i].id === item.id) {
cart[i].ammount = Number(cart[i].ammount) + Number(item.ammount);
this.set(cart);
break;
} else if (i === cart.length - 1) {
cart.push(item);
this.set(cart);
break;
}
}
} else {
cart.push(item);
this.set(cart);
}
}
A few things. Yes, this.get returns undefined, I have tested it from the console. Hence I don't understnad why the code inside of the if statement isn't running. I've put the if statement in several places, including the constructor. Same behaviour everywhere.
It all works fine on the second visit though.
To be clear the code that is doing nothing even though it seems to evaluate to true is:
if (this.get === undefined) {
store.set(this.storageNamespace, []);
}
const cart = function(name) {
this.storageNamespace = name;
this.get = store.get(this.storageNamespace); /* store.get is function
call, value be will initialized once instance of this function is created */
};
When you create instance of this function for the first time, an object with "get" property - undefined is created, because you don't have any value in localstorage initially.
cart.prototype.add = function (item) {
if (this.get === undefined) {
store.set(this.storageNamespace, []); /* Here, you insert value in
localstorage,but object's 'get' property is still undefined,i.e there is
value in localstorage but not in this object's property */
// *** Missed this -> this.get = store.get(this.storageNameSpace)
}
let cart = this.get; /* undefined, hence 'if' is not executed */
if (cart.length !== 0) {
for (let i = 0; i < cart.length; i++) {
if (cart[i].id === item.id) {
cart[i].ammount = Number(cart[i].ammount) + Number(item.ammount);
this.set(cart);
break;
} else if (i === cart.length - 1) {
cart.push(item);
this.set(cart);
break;
}
}
} else {
cart.push(item);
this.set(cart);
}
}

How to accomplish this without using eval

Sorry for the title but I don't know how to explain it.
The function takes an URI, eg: /foo/bar/1293. The object will, in case it exists, be stored in an object looking like {foo: { bar: { 1293: 'content...' }}}. The function iterates through the directories in the URI and checks that the path isn't undefined and meanwhile builds up a string with the code that later on gets called using eval(). The string containing the code will look something like delete memory["foo"]["bar"]["1293"]
Is there any other way I can accomplish this? Maybe store the saved content in something other than
an ordinary object?
remove : function(uri) {
if(uri == '/') {
this.flush();
return true;
}
else {
var parts = trimSlashes(uri).split('/'),
memRef = memory,
found = true,
evalCode = 'delete memory';
parts.forEach(function(dir, i) {
if( memRef[dir] !== undefined ) {
memRef = memRef[dir];
evalCode += '["'+dir+'"]';
}
else {
found = false;
return false;
}
if(i == (parts.length - 1)) {
try {
eval( evalCode );
} catch(e) {
console.log(e);
found = false;
}
}
});
return found;
}
}
No need for eval here. Just drill down like you are and delete the property at the end:
parts.forEach(function(dir, i) {
if( memRef[dir] !== undefined ) {
if(i == (parts.length - 1)) {
// delete it on the last iteration
delete memRef[dir];
} else {
// drill down
memRef = memRef[dir];
}
} else {
found = false;
return false;
}
});
You just need a helper function which takes a Array and a object and does:
function delete_helper(obj, path) {
for(var i = 0, l=path.length-1; i<l; i++) {
obj = obj[path[i]];
}
delete obj[path.length-1];
}
and instead of building up a code string, append the names to a Array and then call this instead of the eval. This code assumes that the checks to whether the path exists have already been done as they would be in that usage.

Have a javascript function privately track it's number of calls

I'm trying to figure out how I can have a javascript function privately track the number of times it has been called. The objective is to be able to query this value in the console during debugging by doing func.run
My first attempt:
function asdf() {
if (!asdf.run) {
asdf.run = 0;
} else {
asdf.run++;
console.error('run: ' + asdf.run);
}
console.error('asdf.run def: ');
console.error(asdf.run);
}
asdf();
This is a good lesson of why one should ALWAYS aim to use === in nearly all javascript booleans, cause they could secretly be ==
Closures are the way to go here:
var asdf = (function () {
var runs = 0;
var f = function () {
++runs;
// your function here
};
f.runs = function () {
return runs;
};
return f;
}());
Usage:
asdf();
asdf();
asdf.runs(); // 2
asdf();
asdf.runs(); // 3
Or, you could use a mocking framework like (shameless self plug) Myrtle.
Your first try would work fine except you've forgotten that 0 is a "falsy" value in JavaScript, so on the first run and every run thereafter !this.run will evaluate to true and your else block will never be reached. This is pretty easy to work around.
function foo() {
if(typeof(foo.count) == 'undefined') {
foo.count = 0;
} else {
foo.count++;
}
console.log(foo.count);
}
foo(); # => 0
foo(); # => 1
foo(); # => 2
# ...
I haven't actually tried this, but I looked up "static function variables in JavaScript", and I found this resource. I think the main difference between what you wrote and what's in that solution is how the first run of the function is detected. Perhaps your !asdf.run test is not working the way you thought it was, and you should use typeof asdf.run == 'undefined' to test instead.
OK, here is a method that I came up with that does not require the function to be modified at all.
So if you have this.
function someFunction() {
doingThings();
}
you could add a counter like this...
addCounter(this, "someFunction");
where this is the scope you are in, you could use any object that has a method you want to count.
Here's the code for it.
<html>
<head>
<script>
function someFunc() {
console.log("I've been called!");
};
// pass an object, this or window and a function name
function wrapFunction(parent, functionName) {
var count = 0, orig = parent[functionName];
parent[functionName] = function() {
count++;
return orig.call(this, Array.prototype.slice(arguments));
}
parent[functionName].getCount = function() {
return count;
};
}
var someObj = {
someFunc: function() {
console.log("this is someObj.someFunc()");
}
}
wrapFunction(this, "someFunc");
wrapFunction(someObj, "someFunc");
someFunc();
someObj.someFunc();
someObj.someFunc();
someObj.someFunc();
console.log("Global someFunc called " + someFunc.getCount() + " time" + (someFunc.getCount() > 1 ? "s" : "")) ;
console.log("Global someObj.someFunc called " + someObj.someFunc.getCount() + " time" + (someObj.someFunc.getCount() > 1 ? "s" : "")) ;
</script>
</head>
So, !asdf.run is a form of the double equals operator == and I had set asdf.run to 0 so it was false.
Using the triple equals === :
typeof asdf.run === "undefined" for the boolean solves my issue.
So a final usable and useful version:
function sdf() {
if (typeof sdf.run === "undefined") { sdf.run = 0; }
sdf.run++;
}
To query the number of times sdf has been called:
sdf.run;
To actually make this variable private and protect it from change, one would implement a closure.
//using a closure and keeping your functions out of the global scope
var myApp = (function() {
//counter is a private member of this scope
var retObj = {}, counter = 0;
//function fn() has privileged access to counter
retObj.fn = function() {
counter++;
console.log(counter);
};
//set retObj to myApp variable
return retObj;
}());
myApp.fn(); //count = 1
myApp.fn(); //count = 2
myApp.fn(); //count = 3
You don't necessarily need a closure. Just use a static variable.
var foo = function(){
alert( ++foo.count || (foo.count = 1) );
}
// test
function callTwice(f){ f(); f(); }
callTwice(foo) // will alert 1 then 2
or
callTwice( function bar(){
alert( ++bar.count || (bar.count = 1) );
}); // will alert 1 then 2
the second one is a named anonymous function. And note this syntax:
var foo = function bar(){ /* foo === bar in here */ }

Categories

Resources