How to retrieve a conditionally set variable from inside a function? - javascript

What can I do to retrieve a conditional variable from inside a function in the webpage being parsed by greasemonkey?
Something like this:
var myglobal = 5;
function myfunc() {
myglobal = myglobal -1;
if (myglobal == -1) {
var this1 = 'Test';
document.getElementById("mybutton").href = this1;
}
}
In this case I would like to read what is in 'this1', either directly or modifying 'myglobal', calling 'myfunc' and somehow getting the value of href from 'mybutton'... any ideas?

You usually can't get a variable value from outside a scope like that, but you may not have to in this case.
"myfunc is a counter, and I want to skip it, otherwise mybutton.href won't be set yet."
Based on the sample code, you might be able to cheat that timer just by using:
unsafeWindow.myglobal = 0;
(In fact, I use this exact technique on one very misguided training site.)
To answer the stated question further, you cannot get dynamic values from within such a scope but the initial state may be enough, as it appears to be for this question.
So you could get myfunc()s code and parse it with regex to obtain the desired value:
var theFunc = unsafeWindow.myfunc.toString ();
var desiredHref = theFunc.match (/var\s+this1\s*=\s*["']([^"']+)["']/);
if (desiredHref.length > 1) {
// Found!
desiredHref = desiredHref[1];
}

Related

How can I detect when a variable changes value in JavaScript?

Before I start, I'd just like to say that there are already answered questions on this topic, and I looked them up - but because I'm still somewhat of a beginner, I can't really figure out the answer as it's too complex for me. So I wanted to give my own example, a dead simple one, and try to understand based on that.
Essentially what I want to do is run a function when an already existing variable, with a defined value, changes its value. Something like this:
var testVar = 5;
function letMeKnow() {
console.log("The variable has changed!);
}
What I want is, when I go to the console and type, say testVar = 7, I want the letMeKnow() function to run, and print something out in the console. More specifically, I want JavaScript to detect that the variable has changed, and run the function automatically. I know that this used to be possible with Object.observe() or Object.watch(), but since those are deprecated I suppose that I have to use getters and setters to achieve this. My question is, how would I do that for this example, keeping it as simple as possible?
Thanks!
A simple example using getter/setter can be like:
var obj = {
value: '',
letMeKnow() {
console.log(`The variable has changed to ${this.testVar}`);
},
get testVar() {
return this.value;
},
set testVar(value) {
this.value = value;
this.letMeKnow();
}
}
console.log(obj.testVar)
obj.testVar = 5;
console.log(obj.testVar)
obj.testVar = 15;
console.log(obj.testVar)

HTML5 Web Storage Creating Variables

I'm looking to create quite a few variables in JavaScript for storing boolean variables in HTML5 Web Storage. I want the variables to be as follows:
localStorage.title1 = '0';
localStorage.title2 = '0';
localStorage.title3 = '0';
And so on ...
The problem I face is that I want to create these variables all the way to localStorage.title570.
I have tried the following code, of which I was suspect to it's failure:
function registerUser() {
for(i=1;i<571;i++)
{
var a = "title" + i;
localStorage.a = 0;
}
}
However, this doesn't appear to work. I'm looking for an easy way to create these 570 variables in order to track progress of a user. I have looked at PHP and MySQL but I feel this will hopefully prove slightly more easy. However, if not, I shall simply use PHP and MySQL.
Use something like this instead:
for(i=1;i<571;i++)
{
localStorage['title' + i] = 0;
}
or better:
for(i=1;i<571;i++){
localStorage.setItem('title' + i, '0');
}
A slightly different solution would be to use an array instead of indexing the variable names.
So...
function registerUser() {
localStorage.title=[];
for(i=0;i<570;i++)
{
localStorage.title.push(0);
}
}
Or if you didnt need to initiaise the values to 0 then it would just be.
function registerUser() {
localStorage.title=[];
}
Note that now the index starts at 0 instead of 1.

Javascript - Array of prototype functions

I'm a javascript newbie so I'm writing ugly code so far sometimes due to my lack of experience and how different it is to the languages I'm used to, so the code I'll post below works, but I'm wondering if I'm doing it the right way or perhaps it works but it's a horrible practice or there is a better way.
Basically, I have a little dude that moves within a grid, he receives from the server an action, he can move in 8 directions (int): 0:up, 1: up-right, 2: right... 7: up-left.
the server will send him this 0 <= action <= 7 value, and he has to take the correct action... now, instead of using a switch-case structure. I created a function goUp(), goLeft(), etc, and loaded them in an array, so I have a method like this:
var getActionFunction = actions[action];
actionFunction();
However, what to set all this up is this:
1) create a constructor function:
function LittleDude(container) {
this.element = container; //I will move a div around, i just save it in field here.
}
LittleDude.prototype.goUp() {
//do go up
this.element.animate(etc...);
}
LittleDude.prototype.actions = [LittleDude.prototype.goUp, LittleDude.prototype.goUpLeft, ...];
//In this array I can't use "this.goUp", because this points to the window object, as expected
LittleDude.prototype.doAction = function(action) {
var actionFunction = this.actions[action];
actionFunction(); //LOOK AT THIS LINE
}
Now if you pay attention, the last line won't work.. because: when i use the index to access the array, it returns a LittleDude.prototype.goUp for instance... so the "this" keyword is undefined..
goUp has a statement "this.element"... but "this" is not defined, so I have to write it like this:
actionFunction.call(this);
so my doAction will look like this:
LittleDude.prototype.doAction = function(action) {
var actionFunction = this.actions[action];
actionFunction.call(this); //NOW IT WORKS
}
I need to know if this is hackish or if I'm violating some sort of "DO NOT DO THIS" rule. or perhaps it can be written in a better way. Since it seems to me kind of weird to add it to the prototype but then treating it like a function that stands on its own.
What you are trying to do is one of the possible ways, but it is possible to make it more simple. Since object property names are not necessary strings, you can use action index directly on prototype. You even don't need doAction function.
LittleDude = function LittleDude(container) {
this.container = container;
}
LittleDude.prototype[0] = LittleDude.prototype.goUp = function goUp() {
console.log('goUp', this.container);
}
LittleDude.prototype[1] = LittleDude.prototype.goUpRight = function goUpRight() {
console.log('goUpRight', this.container);
}
var littleDude = new LittleDude(123),
action = 1;
littleDude[action](); // --> goUpRight 123
littleDude.goUp(); // --> goUp 123
actionFunction.call(this); //NOW IT WORKS
I need to know if this is hackish or if I'm violating some sort of "DO NOT DO THIS" rule. or perhaps it can be written in a better way.
No, using .call() is perfectly fine for binding the this keyword - that's what it's made for.
Since it seems to me kind of weird to add it to the prototype but then treating it like a function that stands on its own.
You don't have to define them on the prototype if you don't use them directly :-) Yet, if you do you might not store the functions themselves in the array, but the method names and then call them with bracket notation:
// or make that a local variable somewhere?
LittleDude.prototype.actions = ["goUp", "goUpLeft", …];
LittleDude.prototype.doAction = function(action) {
var methodName = this.actions[action];
this[methodName](); // calls the function in expected context as well
}

How to assign the value of 0 to a variable?

Javascript function 1:
var count = 0;
function myFunction()
{
count++;
document.getElementById("count").innerHTML=count;
}
Javascript function 2:
function demo() {
var y=document.getElementById("count").innerHTML;
if(y=="0") {
alert("There's nothing to be reset.");
}
else {
var count=0;
alert("Reset.");
// alternative code I used: document.getElementById("count").innerHTML="0";
}
}
HTML code:
Click here
<p>Total:<span id="count">0</span></p>
<button onclick="demo()">reset</button>
Is there a way to reset the variable to 0 in this code?
I've tried to reset the variable count to zero using document.getElementById() and adding =0; to the variable. Neither of these work. For example, if the user was to click the link the count would increase to 1. When they click the reset button it would appear to reset to 0 (unless using `var count=0;). However, if the user were to click the link again the count would be return the value 2, as it could simply continue to increment from the previous time.
I'm sorry if this has already been answered somewhere else, but it's very difficult to search for the terms = and ++.
You made it a local variable by using var
else {
var count=0;
alert("Reset.");
should be
else {
count=0;
alert("Reset.");
Two things:
Get rid of var where you reset the variable. That's giving you a separate local variable with the same name.
Using "count" as a variable name, if it's global, will cause problems if you've also got an element whose id is "count" in the DOM. Use a different variable name or a different id, or make sure that the variable is not global (can't tell from posted code).
The things you need to chnage in the code are:
And make the comparison to
if(parseInt(y) === 0) // You are converting it to integer and doing a strict check
the else construct to
else {
count = 0;
alert('Reset');
}

Variable Dependency with knockoutJS

I'm building an application with KnockoutJS with a component that essentially acts as a sequential spreadsheet. On different lines users may define variables or use them to represent a value.
So for example
x =2
x //2
x = 4
x //4
I have this working in the straightforward case of continuing adding new lines. The output function for each line checks and iterates backwards to see if the variable was ever defined previously. If it was it uses the first example it finds and sets that as the value. This works when initially defining the lines, and also works when you edit a line after a previous line has changed.
However, I would like variables to update if a previous definition of that variable has changed, been removed, or been added. That behavior does not exist right now. I have tried adding my own custom dependency handling code using a map to track the variables, but it badly impacted performance. I would like to tap into Knockouts dependency management to solve this, but I'm not sure of the best way to do so. Here is a brief summary of my code structure, I would be happy to add more detail if needed.
calcFramework is the view-model object I bind to the map. It consists of an observable list of Lines, a varMap, and other unrelated properties and functions
Line is a custom object. The relevant code is below
var Line = function (linenum,currline) {
var self = this;
self.varMap = {};
self.input = ko.observable("");
self.linenum = ko.observable(linenum);
self.lnOutput = ko.computed({
read:function(){
return outputFunction(self,self.input());
},
write:function(){},
owner:self
});
};
function outputFunction(self,input) {
try{
var out = EQParser.parse(input,10,self);
return out.toString();
}
catch(ex){
//error handling
}
}
Line.prototype.getVar = function (varName, notCurrentLine) {
if(typeof varName === "undefined"){
return null;
}
//Actually don't want ones set in the current varMap, only past lines
if(varName in this.varMap && notCurrentLine){
return this.varMap[varName];
}
if (this.linenum() > 0) {
var nextLine = calcFramework.lines()[this.linenum() - 1];
return nextLine.getVar(varName,true);
} else {
//eventually go to global
return calcFramework.varMap[varName];
}
};
Line.prototype.setVar = function(varName,value){
this.varMap[varName] = value;
};
SetVar and getVar are passed to eqParser, which gets the value of the expression, calling those functions as needed if a variable is referenced. So the variable value is not explicitly passed to the function and thus knockout does not view it as a dependency. But I'm not sure how I would pass the variable as a parameter without traversing the list every time.
So my question is, given this setup, what is the best way to track changes to a variable assignment (and/or new assignments) and update the lines that reference that variable, while maintaining good performance.
I recognize my question is lengthy and I have attempted to trim out all unnecessary detail. Thanks for your patience in reading.
I would be tempted to use a publish/subscribe model, using something like Peter Higgins' PubSub jquery plugin
Your overall app would subscribe/listen out for lines publishing an event that they have a variable definition. This would store any variable names in a standard javascript hashtable, along with the value. When a variable found event is published by a line, the app would check through all the known variables, and if it finds that it is a change to an existing variable value, it would publish a variable changed event. All the lines would subscribe to that event. They can then check whether they have a variable matching that name, and update the value accordingly.
Here's some untested code to give you an idea of what I mean:
var app = function()
{
var self = this;
self.variables = {};
$.subscribe('/variableAssigned', function (key, value)
{
// I think that this is the best way of checking that there is a variable
// in the object
if(self.variables.hasOwnProperty(key))
{
if(self.variables[key] !== value)
{
$.publish('/variableChanged', [ key, value ]);
}
}
});
}
In your Line object:
$.subscribe('/variableChanged', function (key, value)
{
// loop through varMap and see if any of them need updating.
});

Categories

Resources