I want to determine when a particular variable is changed. I have had great success using this code to watch any property of any object that I can access, but can it be used for a variable declared like this?:
$( // line 1
function(){ // line 2
var A; // line 3
// ... lots of code that uses A as if it were a global. I wanna see what part of this code sets A ...
} // line 5999
); // line 6000
Surely A does not end up as a property of window. Is it perhaps a property of the anonymous function object which spans lines 2 thru 5999? So if I name the function so I can reference it am I able to use watch on the A var/prop somehow?
What other methods are available to me to figure out where the var gets set?
This might seem bit insane but, with a little modification, you'll be able to watch the variables pointer.
(function() {
window.ox = x = {};
x.y = 5;
})();
alert(ox.y);
This pulls it into the global territory, and should allow you to observe variable x from the global variable ox.
You can't use Object.prototype.watch on that variable, simply because it's a variable, not an object property. Regardless of its scope (which is the anonymous function you mentioned).
If you're trying to do that for debugging purposes, I believe you can watch it from your browser's developer tools.
Related
Have you ever taken a look under the hood at the jQuery 1.4 source code and noticed how it's encapsulated in the following way:
(function( window, undefined ) {
//All the JQuery code here
...
})(window);
I've read an article on JavaScript Namespacing and another one called "An Important Pair of Parens," so I know some about what's going on here.
But I've never seen this particular syntax before. What is that undefined doing there? And why does window need to be passed and then appear at the end again?
The undefined is a normal variable and can be changed simply with undefined = "new value";. So jQuery creates a local "undefined" variable that is REALLY undefined.
The window variable is made local for performance reasons. Because when JavaScript looks up a variable, it first goes through the local variables until it finds the variable name. When it's not found, JavaScript goes through the next scope etc. until it filters through the global variables. So if the window variable is made local, JavaScript can look it up quicker.
Further information: Speed Up Your JavaScript - Nicholas C. Zakas
Undefined
By declaring undefined as an argument but never passing a value to it ensures that it is always undefined, as it is simply a variable in the global scope that can be overwritten. This makes a === undefined a safe alternative to typeof a == 'undefined', which saves a few characters. It also makes the code more minifier-friendly, as undefined can be shortened to u for example, saving a few more characters.
Window
Passing window as an argument keeps a copy in the local scope, which affects performance: http://jsperf.com/short-scope. All accesses to window will now have to travel one level less up the scope chain. As with undefined, a local copy again allows for more aggressive minification.
Sidenote:
Though this may not have been the intention of the jQuery developers, passing in window allows the library to be more easily integrated in server-side Javascript environments, for example node.js - where there is no global window object. In such a situation, only one line needs to be changed to replace the window object with another one. In the case of jQuery, a mock window object can be created and passed in for the purpose of HTML scraping (a library such as jsdom can do this).
Others have explained undefined. undefined is like a global variable that can be redefined to any value. This technique is to prevent all undefined checks from breaking if someone wrote say, undefined = 10 somewhere. An argument that is never passed is guaranteed to be real undefined irrespective of the value of the variable undefined.
The reason to pass window can be illustrated with the following example.
(function() {
console.log(window);
...
...
...
var window = 10;
})();
What does the console log? The value of window object right? Wrong! 10? Wrong! It logs undefined. Javascript interpreter (or JIT compiler) rewrites it this way -
(function() {
var window; //and every other var in this function
console.log(window);
...
...
...
window = 10;
})();
However, if you get the window variable as an argument, there is no var and hence no surprises.
I don't know if jQuery is doing it, but if you are redefining window local variable anywhere in your function for whatever reason, it is a good idea to borrow it from global scope.
window is passed in like that just in case someone decides to redefine the window object in IE, I assume the same for undefined, in case it's re-assigned in some way later.
The top window in that script is just naming the argument "window", an argument that's more local that the global window reference and it what the code inside this closure will use. The window at the end is actually specifying what to pass for the first argument, in this case the current meaning of window...the hope is you haven't screwed up window before that happens.
This may be easier to think of by showing the most typical case used in jQuery, plugin .noConflict() handling, so for the majority of code you can still use $, even if it means something other than jQuery outside this scope:
(function($) {
//inside here, $ == jQuery, it was passed as the first argument
})(jQuery);
Tested with 1000000 iterations. This kind of localization had no effect in performance. Not even a single millisecond in 1000000 iterations. This is simply useless.
I need to emulate in firefox the behavior of activeXobject in last versions of ie. I write addon with contentScript and want to implement to pages such variable. It is exactly what I want - It is a challenge in itself.
Example of IE 11 working code:
if (window.ActiveXObject == undefined) {
var but = new window.ActiveXObject; // [ActiveXObject object]
}
I need exactly same behavior in firefox with my variable
For example what i want
<script>
console.log(window.variable) // undefined
console.log(new window.variable); // [object Variable]
console.log(new variable) // [object Variable] if not possible previous string
</script>
for solving, you can change the addon sdk or a browser source, change realization of all getters or something else
In browser Javascript, there is no such thing as a global variable that is not a property of the window object. So, if that's truly what you are trying to do, then it cannot be done. Yes, you might be able to create a getter on the window object with Object.defineProperty(), but that's still a property on the window object so I'm not sure how that helps you.
Likewise, there is no structure in Javascript such that:
window.ActiveXObject === undefined
and this works:
var x = new window.ActiveXObject;
Javascript just simply doesn't work that way. The property either exists or it doesn't. It can't be undefined for one way of accessing it and defined for some other way of accessing it.
You might also be able to create the property on the window object so it is not enumerable if you want it to be less visible for some reason.
If you explained what you're really trying to accomplish, there may be some work-arounds by enclosing the relevant code in a closure and defining the variable in the closure, but without knowing more details about what the actual problem to be solved is, we can't help more specifically than that.
If you just want the variable defined for YOUR code only, then you can just put it in a closure:
(function() {
var myVar = "foo";
// other parts of your code
// elsewhere in your code
console.log(myVar);
})();
Your code can treat it like a global, but it's really not a global, it's just defined within the scope that your code lives and not available to any other code outside this scope.
Theoretically, this is possible with lexically declared variables in ES6:
let variable = 5;
console.log(variable); // 5
console.log(window.variable) // undefined
However, the current let support in FF is not as advanced, and still treats this a property of the global object.
If the variable only needs to be accessible by your project code, wrap all of your project code in a self executing anonymous function.
(function(){
var internalGlobalVar = "some value";
//All your code gets wrapped in here...
})();
Then if you tried to alert(window.internalGlobalVar) you would get undefined.
We use google closure compiler with plovr and wrap all of our code in a self executing anonymous function so basically all of our global variables are project scope, not on the window "output-wrapper": "(function($){%output%})(jQuery);"
I get a js error when I declare the following script.
<script>
window.onload=init;
init = function(){alert("Yahoo!");}
</script>
It works when I declare init as:
<script>
window.onload=init;
var init = function(){alert("Yahoo!");}
</script>
Shouldn't the top level init should implicitly become the property of window object? Please help me understand the concept.
JavaScript tracks variables and function declarations before executing the code. Lots of languages do this, actually, so it's a good thing to get used to.
It does not, however, track assignments. That counts as executing the code. Even though when a variable that is not defined is assigned, it becomes a property of window, it is not a variable! It can be deleted from window, unlike real variables.
var i = 2;
n = 2;
delete window.i; //false
delete window.n; //true
Thus, they can not be used before they are defined like variables. Instead, they must be defined first, and then used. Otherwise, they will not be defined.
//OK, but not recommended because init is now not a variable. It makes more sense to make init a variable instead.
init = function(){alert("Yahoo!");}
window.onload=init;
<script>
window.onload=init;
var init = function(){alert("Yahoo!");}
</script>
This is organized by Javascript as such (variable declarations first):
<script>
var init;
window.onload=init;
init = function(){alert("Yahoo!");}
</script>
Thus, init is present when used for onload.
The one without the var doesn't include a variable declaration but an assignment to a property of window. Assignments are not changed during preprocessing. So, nothing named init is found and execution fails.
this is related to the fact that javascript engine makes two passes over a function. at first pass, it moves all the local variables to the top of the function, and in second pass it runs the function.
So, when you define init with var, it is a local variable, therefore defined in the first pass and successfully run in the second pass.
I'm not sure if i could make it clear, but if you want to get more information on this topic, it was very well covered in Single Page Web Applications by Michael S. Mikowski and Josh C. Powell.
I already know how to make this code work, but my question is more about why does it work like this, as well as am I doing stuff right.
The simplest example I can make to showcase my issue is this :
Lets say I have a function that increments the value of an input field by 10 on the press of a button.
var scopeTest = {
parseValue : function( element, value ) {
value = parseInt( element.val(), 10 );
//Why does this not return the value?
return value;
},
incrementValue : function( element, button, value ) {
button.on('mousedown', function (e) {
//Execute the parseValue function and get the value
scopeTest.parseValue( element, value );
//Use the parsed value
element.val( value + 10 );
e.preventDefault();
});
},
init : function () {
var element = $('#test-input'),
button = $('#test-button'),
value = '';
this.incrementValue( element, button, value );
}
};
scopeTest.init();
The above code doesnt work because the parseValue method doesn't properly return the value var when executed inside the incrementValue method.
To solve it apparently I have to set the scopeTest.parseValue( element, value ); parameter to the value variable like this:
value = scopeTest.parseValue( element, value );
Than the code works.
But my question is why? Why is this extra variable assignment step necessary, why the return statement is not enough? Also I am doing everything right with my functions/methods, or is this just the way JavaScript works?
Working example here => http://jsfiddle.net/Husar/zfh9Q/11/
Because the value parameter to parseValue is just a reference. Yes, you can change the object, because you have a reference, but if you assign to the reference it now points at a different object.
The original version is unchanged. Yes, the return was "enough", but you saved the new object in a variable with a lifetime that ended at the next line of code.
People say that JavaScript passes objects by reference, but taking this too literally can be confusing. All object handles in JavaScript are references. This reference is not itself passed by reference, that is, you don't get a double-indirect pointer. So, you can change the object itself through a formal parameter but you cannot change the call site's reference itself.
This is mostly a scope issue. The pass-by-* issue is strange to discuss because the sender variable and the called functions variable have the same name. I'll try anyway.
A variable has a scope in which it is visible. You can see it as a place to store something in. This scope is defined by the location of your function. Meaning where it is in your source code (in the global scope or inside a function scope). It is defined when you write the source code not how you call functions afterwards.
Scopes can nest. In your example there are four scopes. The global scope and each function has a scope. The scopes of your functions all have the global scope as a parent scope. Parent scope means that whenever you try to access a name/variable it is searched first in the function scope and if it isn't found the search proceeds to the parent scope until the name/variable is found or the global scope has been reached (in that case you get an error that it can't be found).
It is allowed to define the same name multiple times. I think that is the source of your confusion. The name "value" for your eyes is always the same but it exists three times in your script. Each function has defined it: parseValue and incrementValue as parameter and init as local var. This effect is called shadowing. It means that all variables with name 'value' are always there but if you lookup the name one is found earlier thus making the other invisible/shadowed.
In this case "value" is treated similar in all three functions because the scope of a local var and a parameter is the same. It means that as soon as you enter one of the methods you enter the function scope. By entering the scope the name "value" is added to the scope chain and will be found first while executing the function. And the opposite is true. If the function scope is left the "value" is removed from the scope chain and gets invisible and discarded.
It is very confusing here because you call a function that takes a parameter "value" with something that has the name "value" and still they mean different things. Being different there is a need to pass the value from one "value" to the other. What happens is that the value of the outer "value" is copied to the inner "value". That what is meant with pass-by-value. The value being copied can be a reference to an object which is what most people make believe it is pass-by-reference. I'm sorry if that sounds confusing but there is too much value naming in here.
The value is copied from the outer function to the called function and lives therefor only inside the called function. If the function ends every change you did to it will be discarded. The only possibility is the return your "side effect". It means your work will be copied back to a variable shortly before the function gets discarded
To other alternative is indeed leaving of parameters and work with the scope chain, e.g. the global scope. But I strongly advize you not to do that. It seems to be easy to use but it produces a lot of subtle errors which will make your life much harder. The best thing to do is to make sure variables have the most narrow scope (where they are used) and pass the values per function parameters and return values.
This isn't a scoping issue, it's a confusion between pass-by-reference and pass-by-value.
In JavaScript, all numbers are passed by value, meaning this:
var value = 10;
scopeTest.parseValue( element, value );
// value still == 10
Objects, and arrays are passed by reference, meaning:
function foo( obj ){
obj.val = 20;
}
var value = { val: 10 }
foo( value );
// value.val == 20;
As others have said it's a pass-by-ref vs pass-by-val.
Given: function foo (){return 3+10;} foo();
What happens? The operation is performed, but you're not setting that value anywhere.
Whereas: result = foo();
The operation performs but you've stored that value for future use.
It is slightly a matter of scope
var param = 0;
function foo( param ) {
param = 1;
}
foo(param);
console.log(param); // still retains value of 0
Why?
There is a param that is global, but inside the function the name of the argument is called param, so the function isn't going to use the global. Instead param only applies the local instance (this.param). Which, is completely different if you did this:
var param = 0;
function foo() { // notice no variable
param = 1; // references global
}
foo(param);
console.log(param); // new value of 1
Here there is no local variable called param, so it uses the global.
You may have a look at it.
http://snook.ca/archives/javascript/javascript_pass
Before actually asking anything, I'll go ahead and say this is a theoretical question; however, it might be implemented on a website later on.
Anyway, I have a variable, any variable. Let's say it's a and its scope is global. Now, for a specific function, I want to set that variable's value to something other than it's global value, but based on it, and without changing its value globally. For example:
a = {something: "Safe", other: "Foo"}
function hello(){
var a = a.other; // Foo
a.something; // Undefined
}
a.something; // Safe
a.other; // Foo
The issue with the above code is that when I define var a in the function, it will have already cleared the value of the global a locally before setting it; in other words, it would return something like Can't access property [other] of undefined [a].
Again, a should still be a (so using another variable name is not an option, or at least not the ideal one). In fact, the global a should not be accessible from the function hello.
Edit: window will also be overwritten with null, regarding Milan Jaric's answer.
Thanks in advance!
Every global can be accessed using window object, with a little changing your code here is example
a = {something: "Safe", other: "Foo"}
function hello(){
var a = window.a.other; // Foo
console.log(window.a.something); // Safe
}
a.something; // Safe
a.other; // Foo
hello();
or
a = {something: "Safe", other: "Foo"}
function hello(){
var a = this.a.other; // Foo
delete a;
console.log(this.a.something); // Safe
}
a.something; // Safe
a.other; // Foo
hello();
This is what I was looking for...now, before you think I had the answer before I asked, I didn't, I was only able to reach a tangible solution based on Milan Jaric's answer (thanks btw).
a = {something: "Safe", other: "Foo"}
function hello(b){
var window = null;
var a = b; // a.other;
a.something; // Undefined
}
a.something // Safe
a.other // Foo
hello(a.other)
(I never really said what could or couldn't go outside the function).
Let's say it's a and its scope is global.
You mean "a is a global variable".
... for a specific function, I want to set that variable's value to
something other than it's global value, but based on it, and without
changing its value globally.
Impossible. You can create a variable with the same name that is on a scope chain, however you can't conditionally create properties of variable objects (i.e. the objects used for identifier resolution on the scope chain). You can only declare local varaibles, which means they exist before any code is run and so can't be conditional, or you can assign directly to an undeclared identifier at which point it becomes a global variable.
[snipped code]
The issue with the above code is that when I define var a in the
function, it will have already cleared the value of the global a
locally before setting it;
The code doesn't in any way "clear" the value of a. It creates a local variable a so that the identifier a will resolve to that variable, not to the global a. To differentiate betweent the two, you can access the global a as a property of the global object:
var a = 'whatever';
var myFunction = (function(global) {
return function() {
var a; // local a
global.a; // global a
}
}(this));
Again, a should still be a (so using another variable name is not an
option, or at least not the ideal one). In fact, the global a should
not be accessible from the function hello.
Impossible, though it might be almost possible in ES5 strict mode provided the code attempting to access the global a is inside another function and can't get a reference to the global object.
But I don't think you can guarantee that.