almost all javascript books said that
always use var keyword when you
declare variables, because without
var, the variable will be declared as
global variable.
then, why not remove var keyword, make default declaration as local scope?
like Python, if you want to use global variables, you write:
global foo;
we use local variables almost all the time, don't we?
is there a good reason?
Thanks for any help.
edit:
Thanks for all your help, I thought there must be a good reason shows that using var is better, so I was not attempting to change the language what it was like.
var globalInt = 5;
function Hello()
{
// Hey, give me back my var keyword!
// I want to assign a global existing variable
globalInt = 7;
}
Another point is there is no easy way to remove something from JavaScript. Every feature (even hacks) is already used on thousands of sites and removing features will break those sites. JavaScript can only be extended. Or new JS should be created which will be incompatible with previous versions.
function A() {
var foo; // variable in the scope of function A
function B() {
foo; // variable still in the scope of function A
}
}
If the choice was "Narrowest scope" or "Global scope" then this wouldn't be possible.
This is just the way the language was designed. If a variable is auto-allocated it is allocated in the global scope.
It makes a lot of sense if you think about it. What scope should a variable be allocated in? The compiler has no way of knowing the programmers goal with an explicit declaration
For better or worse JS was designed the way it was. I believe allowing variables to auto-declare was a mistake but given that it exists in JS it makes sense to have them be global since JS does not have block level scope.
using var keyword inside a function declares the variable in local scope, hence preventing overwriting of any global variable. Idea is to play safe, and use var. If you know what you are doing (100% sure that you will not overwrite any global variable) feel free to discard var.
OK, i'll try to explain how it works again. There is a ECMAScript's Global object, which is "root" of everything else. In browsers window object implements Global. So:
function assert( condition, message ) {
if ( !condition )
if ( typeof message != 'undefined' ) alert( message );
else alert( 'Free Consulting just talks rubbish' );
}
// assuming global scope
assert( this == window, 'noes!' ); // and Global context
var spam = 'for all you python lovers'; // becomes a property of Global
assert( spam == window.spam, 'there not much spam in it' ); // same
function eggs () { // becomes a method of Global actually
assert( spam == window.spam, 'shut up!' ); // unqualified spam available here through closure
assert( arguments.callee == window.eggs ); // and again
}
eggs();
Mrs Conclusion: JavaScript is distinct language with own specific traits, so do not apply other language knowledge to JS (it makes Douglas Crockford a sad panda :)
Related
I am beginner at JavaScript and I am trying to understand the Global window object in JavaScript. So, is it ok if I just imagine that any code that I write in the console like var text = "Hello"; console.log(text) is put inside window object like this Window{var text = "Hello"; console.log(this.text)} with this referencing window object. Is it ok if I consider it like that or it is not correct? Thank you
Is not pretty safe to make assumptions about the global object or the default this context, as it can vary from one javascript runtime to another, and some features like the strict mode also change this behavior.
Keep in mind that javascript not only runs in the browser -and global in node.js for instance does not work as in the browser-, and that there are a lot of different browser implementations out there.
Also, while var does write to global by default in some environments, const and let doesn't.
In node, functions called freely with no previous reference won't call them from global, but will fail instead. This heavily affects also front-end code since much of javascript for the browser nowadays is pre-compiled in a node environment via webpack etc.
So, succintly: is usually difficult to assume things about global, window and default this bindings and get them right. It is probably safer to assume that you don't have a default global object available and always refer window explicitly, as:
config.js
window.config = {foo: 'bar'}
window.someGlobalFunction = function() {...}
user.js
// do:
const elen = new User(window.config);
window.someGlobalFunction();
// don't
const elen = new User(config);
someGlobalFunction();
"is it ok to use the global object?"
Of course it is. If you know about the pitfalls and use the global object by purpose and not by accident.
(function() {
name = 12; // Note: This *is* a global variable
console.log(typeof name); // string. WTF
})();
The pitfalls are:
1) All undeclared (!) variables, and global variables declared with var automatically get part of the global object. That is bad, as that happens without any good reason, so you should avoid that (use strict mode, and let and const).
2) All scripts you run do have the same global object, so properties can collide. Thats what happens in the example above, name collides with the global window.name getter / setter pair that casts the number to a string. So if you set properties in the global object, make sure that the name is only used by you, and not by others (the browser, libraries, other codepieces you wrote ...)
If you know about these pitfalls and avoid them, you can and should use the global object by purpose, if, and only if, you plan to share a certain function / variable between different scripts on the page, so if it should really be globally accessible.
let private = 1;
window.shared = 2;
Yes, any function or variable can be accessed from the window object example:
var foo = "foobar";
foo === window.foo; // Returns: true
function greeting() {
console.log("Hi!");
}
window.greeting(); // It is the same as the normal invoking: greeting();
I wrote a simple object destructuring function that declares variables in given scope through assigning properties to the scope object
Can I use this function in production and if not what are the pitfalls of using such a function?
function destructure(obj, scope) {
scope = scope || this;
Object.keys(obj).forEach(key => {
if (scope[key] === undefined) {
scope[key] = obj[key];
} else {
throw new Error(key + ' variable is already declared.');
}
});
}
var o = {
one: 1,
two: 2,
three: 3,
four: 4
};
destructure(o);
console.log(one); // 1
console.log(two); // 2
console.log(three); // 3
console.log(four); // 4
Are there any pitfalls of declaring variables through this keyword?
Yes: It doesn't really work.
There might be a misunderstanding about how this and scope work.
About scope
You can only declare variables by adding a property to an object is when the environment is backed by an actual object. This is only the case for two situations:
Global scope, which is (partially) backed by the global object (window in browsers)
The with statement
Examples:
// Global scope
window.foo = 42;
console.log(foo);
// with statement
var obj = {};
with (obj) {
obj.bar = 21;
console.log(bar);
}
Since you mention that you are using Node, I want to emphasize that function scope and module (which are just functions in Node anyway atm) scope are not backed by objects, thus there is no way to dynamically declare variables.
About this
The value of this depends on how a function is called. It could basically refer to any value.
Now, calling a(n unbound) function the "normal way", i.e. as f(), has this arbitrary behavior that this will refer to the global object, e.g. window in browsers. Of course being the global scope, any variable added there is accessible every else, but that's not necessarily a good thing.
So, while your solution may seem work, it really only works coincidentally when you run your code in global scope.
About strict mode
Strict mode changes some of the behaviors that were deemed incorrect or dangerous. Most importantly it changes how this inside normal function calls (f()) behaves. Instead of referring to the global object, it will simply be undefined. Thus if your function was declared in strict mode, your code would actually throw an error.
The with statement is also forbidden in strict mode.
With ES2016, new constructs such as classes and modules are strict by default, so you can see that that's the direction where the language is developing and you should not rely on behavior that doesn't work in strict mode.
declares variables in given scope through assigning properties to the scope object
No, that's not how a variable declaration works. Also, the only "scope object" that is available to JS - ignoring the with statement - is the global object (which you happened to use in your proof of concept), and you don't want to mess with that.
Can I use this function in production?
Absolutely not.
If you're sold on the idea, you probably can hack it with eval, but really you just should use real destructuring like everyone else:
var {one, two, three, four} = o;
This is the programmatic approach to:
this["one"] = 1
this["two"] = 2
this["three"] = 3
this["four"] = 4
While this theoretically fine, you may run into trouble by relying on this. It would be better to directly specify global, so that you don't run into trouble with .bind() and friends.
function destructure(obj, scope) {
scope = scope; // Remove the this
Object.assign(scope, obj);
}
destructure(o, global) // Explicitly declare global scope
As for memory leaks, performance, etc. (which I feel this question is more about), you have to remember that everything that you assign to global never gets Garbage Collected. You should really only add functions to global, and that's only if you really have to.
Why not use just Object.assign?
function destructure(obj, scope) {
scope = scope || this;
Object.assign(scope, obj);
}
I'm trying to improve my understanding of the global namespace in javascript and I'm curious about a few things:
is there a "GOD" (i.e. a parent) object that all objects (since all things except primitives are objects) to answer to and if so would that object be "window" ?
why is it bad idea to have vars/functions on a global level?
if it is really a bad idea to have vars/functions in global scope then would closures be the best way to avoid this? example:
function parent(){
var x = 'some value';//this var would be considered global to all children functions but not in the true global namespace
function child1(){
x.someMethod()
}
function child2(){
x*something;
}
function child3(){
x+=something;
child2()
child1()
}
child3()
}
parent()
Is there a god (i.e. a parent) object?
Yes. More technically, it's the global object that all these primitives are members of; it just happens that in the browser, the window object is the global object.
> window.String === String;
true
Why is it bad idea to have vars/functions on a global level?
Because if you're adding lots of 3rd party libraries/ scripts, they all share the same global object, there's the chance of name collisions. This is a real life problem with all the libraries which use $ as an alias (jQuery, Prototype and more).
If it is really a bad idea to have vars/functions in global scope then would closures be the best way to avoid this?
x shouldn't be considered global. It's part of the closure formed by declaring the child functions inside the parent() function. The problem part of your snippet is that parent() is global; what happens if some other code re-declared parent()? This would be better:
(function () {
function parent(){
var x = 'some value';
function child1(){
x.someMethod()
}
function child2(){
x*something;
}
function child3(){
x+=something;
child2()
child1()
}
child3()
}
parent()
}());
The fact x is accessible within the child functions isn't bad; you should have written those functions yourself, so you should be aware of the existence of x. Bear in mind that if you re-declare x within those child functions with var, you won't affect the x in parent().
Yes, in a browser environment the "god object" is window. It's typically called the global object, not god object though ;) In non-browser environments such as nodejs, the global object may use some other name than window.
If you put everything as globals, you risk running into colliding names. There is also the matter of encapsulation - in other words, by putting variables into only the scope where it's needed, your code is usually better off.
Yep, this is pretty much the preferred approach. You can also use IIFE's
As far as I know, I'd say yes, window is the parent object. However, inside an Iframe you have your own window object, distinct from surrounding window which you can access through window.parent
It's a bad idea to have a LOT of global var because of potential name collision and therefore hard to detect bugs. In general it's safer to design some namespace (see
the $ from jQuery, etc) and modularize code.
Be careful, parent is a potential existing field of window. This taken appart, function are object so the same observation than in 2) apply here.
If you NEED to put variables in the global namespace, and you likely will at some point, create a single object variable and add your other variables to it as properties or methods. Give the object a name that is not likely to be used by anyone else (admittedly, this is where collision problems arise, but that can be mitigated by careful, standardized naming).
e.g. Instead of:
var thing1 = 'table';
var anotherthing = 'chair';
var mypet = 'dog';
var count = 4;
var show_something: function( _txt ) { return _txt.trim(); };
Do this:
var cmjaimet_obj = {
thing1: 'table',
anotherthing: 'chair',
mypet: 'dog',
count: 4,
show_something: function( _txt ) { return _txt.trim(); }
};
Then later call them as properties:
e.g. Instead of:
count += 2;
anotherthing = 'sofa';
console.log( show_something( 'Thing: ' + anotherthing ) );
Do this:
cmjaimet_obj.count += 2;
cmjaimet_obj.anotherthing = 'sofa';
console.log( cmjaimet_obj.show_something( 'Thing: ' + cmjaimet_obj.anotherthing ) );
I'm new to JavaScript, and have a simple (I presume) question regarding best practices for accessing variables in functions:
When should I declare a global variable, as opposed to simple passing a value into a function?
Declaring a global variable should only be used as an option of last resort.
Global variables are bad in general and especially so in javascript. There is simply no way to prevent another piece of javascript from clobbering your global. The clobbering will happen silently and lead to runtime errors.
Take the following as an example.
// Your code
myParam = { prop: 42 };
function operateOnMyParam() {
console.log(myParam.prop);
}
Here i've declared 2 global variables
myParam
operateOnMyParam
This might work fine while testing your javascript in isolation. However what happens if after testing a user combines your javascript library with my javascript library that happens to have the following definitions
// My code
function myParam() {
console.log("...");
}
This also defines a global value named myParam which clashes with your myParam. Which one wins depends on the order in which the scripts were imported. But either way one of us is in trouble because one of our global objects is dead.
There are many, many reasons.. but an easy one is.. The argument of a function only exists in the function, while it's running. A global variable exists all the time, which means:
it takes up memory until you manually 'destroy' it
Every global variable name needs to be unique
If, within your function.. you call another function.. which ends up calling the first function, all of a sudden you may get unexpected results.
In short: because the function argument only lives for a really short time and does not exist outside the function, it's much easier to understand what's going on, and reduced the risk of bugs greatly.
When dealing with framework-less JavaScript I'll store my simple variables and functions in an object literal as to not clutter up the global namespace.
var myObject = {
variableA : "Foo",
variableB : "Bar",
functionA : function(){
//do something
//access local variables
this.variableA
}
}
//call functions and variables
myObject.variableA;
myObject.functionA();
I've noticed all over the place people mention "Just define a variable in the top of your JS code and it becomes global" in response to questions like, "How do I create a global variable from inside a function?". Most of the answers start by saying it isn't possible to achieve that. Of course it is possible to do this:
<script type="text/javascript">
window.spam = 'Hello World';
</script>
Then, later in your code, you can say:
<script type="text/javascript">
alert(spam);
</script>
This works perfectly fine in IE6+, Firefox, Chrome, Safari, etc. So why does nobody do this?
In my case I want people to access a global variable called fooBar from anywhere in their code and in my AJAX library, I want the variable to update behind the scenes automatically so that when they say $.do_some_magic() they can be sure that fooBar will reflect the changes made by $.do_some_magic() without having to think about it. I don't want them to have to create the variable up high in their code and I don't want to create the variable up high in my library code either. I suppose I just hate defining global variables at the top and would rather not unless there is a good reason not to. Is there?
Clarity
Its an explicit way of showing that you meant to create a global variable.
// Unclear: Intentional, or accident
function privateScope() {
spam = "hello";
function globalFunction() {
}
}
That will make a variable global simply because it was declared that way, though it is not immediately obvious the programmer intended the variable and the function to have a global scope.
// Clear: Intentional global use
function privateScope() {
window.spam = "hello";
window.globalFunction = function () {
}
}
This example is more obvious.
Best Practice
If you know ahead of time a variable will be used with the global scope, it should be declared at the top of your file, outside all your functions:
var spam;
If you are inside a self executing anonymous function, then explicitly use window.spam:
(function(){
// currently private to this scope
var spam;
... lots of code ...
// Expose the variable publically
window.spam = spam;
})();
Name Collision
anthares brought up the other side of this, which is name collision
A number of libraries expose a single top level object. You could either construct a function to do this, or use a simple object literal as a namespace:
(function(){
// Expose a single top level variable
window.YourCompany = { };
// Private:
var spam = "name";
... other code ...
// Make public
window.YourCompany.spam = spam;
})();
Sure, you can say window.spam. But you would only need to if you had also defined a local variable called spam. Otherwise just saying spam automatically refers to the global variable.
It's bad practice to refer to a global variable you haven't declared with var, but it'll work unless you use ECMAScript Fifth Edition ‘strict mode’.
Because var declarations are ‘hoisted’ and processed before code, there is no reason you have to define your globals “at the top”. This is perfectly valid even in strict mode:
function setFooTo6() {
fooBar= 6;
}
var fooBar;
although I'd hesitate to do that as it's not entirely clear.