it's been an hour I'm going crazy with this problem.
There is a page, with a javascript function:
<script>
function foofunction(foo){
dosomething(foo);
}
</script>
I have replaced this function with a greasemonkey script:
var scriptCode = new Array();
scriptCode.push('function foofunction(foo){ ');
scriptCode.push(' dosomething(foo); ');
scriptCode.push(' myinjectedcode; ');
scriptCode.push('}' );
var script = document.createElement('script');
script.innerHTML = scriptCode.join('\n');
scriptCode.length = 0;
document.getElementsByTagName('head')[0].appendChild(script);
//here I have to access to foo value
This works.
Now I have to access to foo value in my greasemonkey script, how can I?
Why are you making your JavaScript function inside a array? I'm assuming foofunction is a global function, why don't you just make a function inside window (or unsafeWindow, I think, for Greasemonkey)?
unsafeWindow.foofunction = function(foo){
dosomething(foo);
//myinjectedcode;
}
foo is a local variable, so it only exists inside the foofunction function. If you want access to it outside of that, you'd need to make it a global variable.
unsafeWindow.foofunction = function(foo){
dosomething(foo);
//myinjectedcode;
unsafeWindow.myFoo = foo;
}
unsafeWindow.myFoo; // will be set to `foo`, but only after `fooFunction` is ran
Problem with that is, myFoo will only be set after fooFunction is ran, and there's no good way for you to wait until then. I suggest making a "callback" function.
unsafeWindow.foofunction = function(foo){
dosomething(foo);
//myinjectedcode;
unsafeWindow.myFooCallback(foo);
}
unsafeWindow.myFooCallback(foo){
// this will be called with `foo` after `fooFunction` is ran.
}
But, this is kinda pointless as your injecting code into fooFunction anyway.
So, to answer your question, you cannot get the value of a local variable outside of the function. Since you're injecting code anyway, why don't you just put all code relating to foo inside fooFunction?
If what you are trying to do is keeping trace off the value in the process I recommend using Firebug to debug this type off scripts, just put a breakpoint anywhere you want in your script and at the time it stops it will give you the current values off all the variables being use.
Related
Why does this work,
function gettingValue() {
var holder = document.getElementById("testing").value;
document.getElementById("displayer").innerHTML = holder;
}
When the following doesn’t?
var holder = document.getElementById("testing").value;
function gettingValue(holder) {
document.getElementById("displayer").innerHTML = holder;
}
The language is Javascript, I was using Microsoft Edge and Opera browsers.
My guess is that the browser doesn’t perform code unless prompted. So var holder = document.getElementById(“testing”).value gets run in the first example because the function that contains it is called by a button.
When var holder = document.getElementById(“testing”).value is put inside a block of script with nothing ‘prompting’ it using the value holder returns undefined. Replaceing document.getElementById(“testing”) with a string “Blue” doesn’t work either. If a function calls holder the value returned is still undefined. So the browser did not create a varable.
I tried having the js document have;
function gettingValue(holder) {
document.getElementById("displayer").innerHTML = holder;
}
And passing the reference document.getElementById(“testing”).value to holder through the HTML document. It didn’t work, the function wasn’t even called because displayer stayed at Default instead of changing to undefined.
Oh experts of stackoverflow, please summarize how and when a browser reads/performs code.
//I realize this might be a 'discussion' which the tutorial said to avoid, if so I apologize. Tell me if this is so and I will not do it again.
Your guess is right - the variable definitions are run as soon as they are executed by the browser, so
var holder = document.getElementById("testing").value; is going to execute that instruction immediately, regardless whether the DOM structure is ready, since it's in outter-most scope. It all depends on where the code is placed in relation to the application entry point and runtime status.
This can obviously be correct, if that variable is defined in a correct place. Function body will only be executed when the containing function is called. It just 'sits' there, and until it is called, the only concern of the browser is if that code is syntactically correct(conforms to JavaScript specification syntax), i.e. can be parsed.
Your problem doesn't appear to have anything to do with when code is executed.
var holder = document.getElementById("testing").value;
The above defines a variable called holder. It is a global because it is outside of any function.
function gettingValue(holder) {
The function also defines a variable called holder by specifying it as an argument name. This variable is scoped to the function.
When you try to access the variable holder, you access the one in the nearest scope.
That's the argument to the function and not the global.
If you didn't mask it:
function gettingValue() {
Then you would be able to access the global.
Your question is very much about when code executes.
Let's look at each thing you tried. First
function gettingValue() {
var holder = document.getElementById("testing").value;
document.getElementById("displayer").innerHTML = holder;
}
That just tells the browser to create a function that is defined by that code in it. It really does not execute the contents of that function, just defines the function. In order for that function to get executed, you have to have some event or some other piece of code, that is executing, call that function. The call to that function, from some event (like a button press) or from other code, tells it to execute.
Now on your second attempt...
var holder = document.getElementById("testing").value;
function gettingValue(holder) {
document.getElementById("displayer").innerHTML = holder;
}
That first line of code is outside of any function definition and it will probably execute when the page loads. That holder variable DOES get created, and it has global scope, which means any function can access it. But, since you don't event have it inside a document_ready event handler, that "testing" control is probably still undefined (the page is not fully loaded when that statement executes) so you get undefined for the contents of "testing".
For your last example, it is hard to say what is going on without seeing the html that had those "testing" and "displayer" controls.
Bottom line, code gets executed when something calls it. When you load a page, any code that is outside of function declarations, executes and has global scope. Anything defined in a function gets executed when that function is called, either by an event or other code.
The issue with the code in the example is an issue with scope:
Your second example doesn't work as expected because you're referencing two different variables/pointers.
var holder = document.getElementById("testing").value;
function gettingValue(holder) {
document.getElementById("displayer").innerHTML = holder;
}
The following scope tree should explain this better:
GLOBAL SCOPE:
defined `holder` (through `var`)
gettingValue SCOPE
defined `holder` (as parameter)
Because you're defining holder as a parameter for gettingValue, you're no longer able to reference the global scope variable inside of gettingValue because they have the same name.
Specifying a parameter in a function definition is very similar to simply defining that variable within the function itself:
var holder = document.getElementById("testing").value;
function gettingValue(holder) {
document.getElementById("displayer").innerHTML = holder;
}
Is equivalent to:
var holder = document.getElementById("testing").value;
function gettingValue(firstParameter) {
var holder = firstParameter;
document.getElementById("displayer").innerHTML = holder;
}
Instead, you may have success doing one of the following:
function gettingValue(value) {
document.getElementById("displayer").innerHTML = value;
}
var holder = document.getElementById("testing").value;
gettingValue(holder);
OR
function gettingValue() {
var holder = document.getElementById("testing").value;
document.getElementById("displayer").innerHTML = holder;
}
gettingValue();
Notice in both examples above we have to call the function in order to execute it (using gettingValue()).
I hope this helps!
As a side note, Scotch.io has a great article that explains how scope works in JavaScript: https://scotch.io/tutorials/understanding-scope-in-javascript
Alright ; I had two misconceptions that were tripping me up.
I was assuming a local variable (used inside function) would be the same as a global variable if they had the same name. //Now that I realize that was the problem I remember reading about it.
I had thought document.getElementById(“blah”).value would be read from the ’s value every time it was used. This is not true, it is read only once when it is a global varable. As a local varable it is ‘read’ to whenever the function containing it is called.
I was blindsided by;
Global variables in javascript are read before the HTML document puts values into its elements. So that was why var holder = “Blue” returned “Blue” when var holder = document.getElementById(“testing”).value returned undefined. It was an order of operations thing. A value had not been put into the element yet. So my lesson is not to use document.getElement... in global variables.
Thank you all for your time and attention.
I'm using PhantomJS v2.0 and CasperJS 1.1.0-beta3. I want to query a specific part inside the page DOM.
Here the code that did not work:
function myfunc()
{
return document.querySelector('span[style="color:#50aa50;"]').innerText;
}
var del=this.evaluate(myfunc());
this.echo("value: " + del);
And here the code that did work:
var del=this.evaluate(function()
{
return document.querySelector('span[style="color:#50aa50;"]').innerText;
});
this.echo("value: " + del);
It seems to be the same, but it works different, I don't understand.
And here a code that did also work:
function myfunc()
{
return document.querySelector('span[style="color:#50aa50;"]').innerText;
}
var del=this.evaluate(myfunc);
this.echo("value: " + del);
The difference here, I call the myfunc without the '()'.
Can anyone explain the reason?
The problem is this:
var text = this.evaluate(myfunc());
Functions in JavaScript are first class citizen. You can pass them into other functions. But that's not what you are doing here. You call the function and pass the result into evaluate, but the result is not a function.
Also casper.evaluate() is the page context, and only the page context has access to the document. When you call the function (with ()) essentially before executing casper.evaluate(), you erroneously try to access the document, when it is not possible.
The difference to casper.evaluate(function(){...}); is that the anonymous function is defined and passed into the evaluate() function.
There are cases where a function should be called instead of passed. For example when currying is done, but this is not applicable to casper.evaluate(), because it is sandboxed and the function that is finally run in casper.evaluate() cannot use variables from outside. It must be self contained. So the following code will also not work:
function myFunc2(a){
return function(){
// a is from outer scope so it will be inaccessible in `evaluate`
return a;
};
}
casper.echo(casper.evaluate(myFunc2("asd"))); // null
You should use
var text = this.evaluate(myfunc);
to pass a previously defined function to run in the page context.
It's also not a good idea to use reserved keywords like del as variable names.
I have several script blocks depend on each other. I need to perform them in one scope.
My attempt:
var scopeWrapper = {};
with(scopeWrapper) {
(function() {
this.run = function(code) {
eval(code);
};
}).call(scopeWrapper);
}
scopeWrapper.run('function test() { alert("passed"); }');
scopeWrapper.run('test();');
I get 'test is not defined' error. It seems that the code is executed in different scopes.
Why is this happening?
Edit: Bergi pointed out my original answer was wrong, he is correct. Since eval runs in its own scope and the function constructor still runs in function scope according to the spec this is not possible with either.
While I have done this sort of thing myself several times with node.js using the vm module where you get much finer grain of control over where your code executes, it seems browsers require a different approach.
The only way you can share variables in such a way is to do so in the global scope of JavaScript execution (possibly, in an iframe). One way you could do this is script tag injection.
function run(code){
var sc = document.createElement("script");
sc.setAttribute("type","text/javascript");
sc.innerHTML = code;
document.body.appendChild(sc);
}
run("var x = 5");
run("document.write(x)");
(here is this code in action)
As for the scope wrapper, instead of injecting them in the same frame inject them in another iframe. That will scope their window object to that iframe and will allow you to share context.
I humbly apologize for my previous answer, I misread the spec. I hope this answer helps you.
I'm leaving my previous answer here because I still believe it provides some insight into how eval and the Function constructor work.
When running code in non-strict mode eval runs in the current context of your page
After your function declaration is done, the scope it was declared in dies, and with it the function.
Consider using the Function constructor and then .calling it
In your case that would be something like:
var scopeWrapper = {};
scopeWrapper.run = function(code){
var functionToRun = new Function(code);
functionToRun.call(scopeWrapper);
}
scopeWrapper.run('this.test = function() { alert("passed"); }');
scopeWrapper.run("this.test()")
Here is a reference directly from the spec:
If there is no calling context or if the eval code is not being evaluated by a direct call (15.1.2.1.1) to the eval function then,
Initialize the execution context as if it was a global execution context using the eval code as C as described in 10.4.1.1.
If this code is run in the node.js consider using the vm module. Also note that this approach is still not secure in the way it'll allow code you run to change your code.
test only exists in the scope of this.run and only at call time :
// global scope
(function(){
// local scope (equivalent of your "run" function scope)
eval('function f(){};');
console.log(f); // prints "function f(){}"
})();
console.log(f); // prints "ReferenceError: f is not defined"
Each call of run creates a new scope in which each code is evaluated separately.
// test.js //
var testObj = {};
testObj.init = function(){
console.log('google');
}
var onload = testObj.init;
/// what does it mean, does it mean it gets executed when script loaded or what, I just can't understand it as it is not looging into console anything under Google Chrome plugin...
Think of it like giving your dog 2 names:
var spot = new Dog();
var comeHereSpot = function () { return spot; }
var comeHereBoy = comeHereSpot;
Whether you call comeHereSpot or comeHereBoy the same dog will come running.
It just means that your variable onload now points to
function(){
console.log('google');
}
onload is just the name of a local variable here.
It means that variable onload is a reference to the function testObj.init. onload() will execute the function and output 'google' to the console.
No, it only means that you assign it to a variable named onload.
Depending on the scope of the code it might actually work, if the variable name collides with the onload property of the window object. In that case a variable would not be created, but it would use the existing property instead. You should not rely on this behaviour though, you should always specify it as a property of the object:
window.onload = testObj.init;
In your code, onload is simply the name of a local variable. The var keyword declares local variables. You're setting the value of onload to testObj.init, which is a function that prints 'google' to the console.
To make it run the function on page load, set window.onload to the value of the function.
window.onload = testObj.init;
Or, better yet, use event handlers to attach an "onload" event to the window object. (To make this easier, use a JavaScript library such as jQuery, but I recommend you first learn how it all works.)
Nothing is logged because you are simply setting onload to be a pointer to the function testObj.init which only gets the function's code. To actually run it, you must call testObj.init().
More about onload…
onload is a property of an HTML element that can be set to run javascript. For example:
<html>…
… <body onload="testObj.init()"> …
…</html>
This means that when the "body" element is loaded, the function testObj.init() is run.
The "onload" property can also be attatched by javascript, as in:
window.onload=myFunction();
I have made a Web page using jquery and php where all files are used in a modular style. Now I have two JavaScript files which must communicate with each other. One Script generates a variable (id_menu_bar) which contains a number. I want that this variable gets transported to the second JavaScript and is used there.
How do I make that?
Here the Script
menu_bar.js
$(document).ready(function() {
function wrapper_action(id_menu_bar) {
$(".wrapper").animate({height: "0px"});
$("#changer p").click(function() {
$(".wrapper").animate({height: "300px"});
});
}
$("#select_place li").live("click", function() {
var wrapper_id = $(".wrapper").attr("id");
var id_place = this.id;
if (wrapper_id != "place")
{
$("#select_level li").remove();
$("#select_building").load("menu_bar/menu_bar_building.php?placeitem="+id_place, function() {
$("#select_building li").click(function() {
var id_building = this.id;
if (wrapper_id != "building")
{
$("#select_level").load("menu_bar/menu_bar_level.php?buildingitem="+id_building, function() {
$("#select_level li").click(function() {
var id_level = this.id;
wrapper_action(id_level);
});
});
}
else if (wrapper_id == "building")
{wrapper_action(id_building);}
});
});
}
else if (wrapper_id == "place")
{wrapper_action(id_place);}
});
});
if the variable id_menu_bar is in global scope then it can be used by another script on the page.
jQuery's $.data() is also good for storing data against elements and means that you do not need to use a global variable and pollute the global namespace.
EDIT:
In response to your comment, there is a difference in how you declare variables that determines how they are scoped in JavaScript.
Global Variables
Outside of a function declaring a variable like
var myVariable;
or
myVariable;
will make no difference - both variables will have global scope. In fact, the second approach will give a variable global scope, even inside of a function. For example
function firstFunction() {
// Local scope i.e. scoped to firstFunction
var localVariable;
// Global scope i.e. available to all other JavaScript code running
// in the page
globalVariable = "I'm not really hiding";
}
function secondFunction() {
// I can access globalVariable here but only after
// firstFunction has been executed
alert(globalVariable); // alerts I'm not really hiding
}
The difference in this scenario is that the alert will fail and not show the value for globalVariable upon execution of secondFunction() until firstFunction() has been executed, since this is where the variable is declared. Had the variable been declared outside of any function, the alert would have succeeded and shown the value of globalVariable
Using jQuery.data()
Using this command, you can store data in a cache object for an element. I would recommend looking at the source to see how this achieved, but it is pretty neat. Consider
function firstFunction() {
$.data(document,"myVariable","I'm not really hiding");
globalVariable = "I'm not hiding";
}
function secondFunction() {
// alerts "I'm not really hiding" but only if firstFunction is executed before
// secondFunction
alert($.data(document, "myVariable"));
// alerts "I'm not hiding" but only if firstFunction is executed before
// secondFunction
alert(globalVariable);
}
in this scenario, a string value "I'm not really hiding" is stored against the document object using the key string myVariable in firstFunction. This value can then be retrieved from the cache object anywhere else in the script. Attempting to read a value from the cache object without having first set it will yield undefined.
Take a look at this Working Demo for more details.
For reasons not to use Global Variables, check out this article.
Does it have to ve a JavaScript variable?
Can you store the information using the .data() function against a relevant element?