defining an undefined global variable inside a function - javascript

This is messy stuff (not my code but I'm stuck to it). A function depends on a globally defined variable.
function variableIssues(){
alert(someGlobalString); // alerts "foo"
}
Sometimes this globally defined variable is, undefined. In this case we want to cast it for further processing. The function is modified.
function variableIssues(){
alert(someGlobalString); // undefined
if (!someGlobalString){
var someGlobalString = "bar";
}
}
However, if this function is now called with a defined someGlobalString, because of javascript evaluation the variable is set to undefined and always get set to bar.
function variableIssues(){
alert(someGlobalString); // "should be foo, but javascript evaluates a
// variable declaration it becomes undefined"
if (!someGlobalString){
var someGlobalString = "bar";
}
}
I would like to get some suggestions on how to handle undefined global variable. Any ideas?

Global variables are properties of the window object, so you can access them explicitly with window:
if (!window.someGlobalString) {
// depending on possible values, you might want:
// if (typeof window.someGlobalString === 'undefined')
window.someGlobalString = "bar";
}
If you are using global variables, then this is better style, since it is clear what you are doing and assigning to undefined global variables wouldn't throw an error in strict mode.

Related

javascript - access properties of this defined in outer function

I've experimented with closures and found unexpected behaviour. Can somebody explain why this code works this way, please?
function foo() {
this.a='hello';
return {
aaa:function() {
return a; // this suprises me, how can be here accessed 'a' ?
}
}
}
o=foo();
alert(o.aaa()); // prints 'hello' ! , I expected undefined
I don't understand, why I always use var that=this phrase, If it is possible to access function properties from inner functions directly.
jsfiddle https://jsfiddle.net/5co6f707/
It displays 'hello' because you're not in strict mode, so this is the global window object instead of undefined, and a becomes a global variable when you assign a value to this.a. Since a is a global variable it is accessible everywhere. You could just alert(a); at the very end of your script and it would also display 'hello': https://jsfiddle.net/5co6f707/1/.
It shouldn't work (and doesn't in strict mode) and it shouldn't be used. If you intend to use foo as a constructor then you should use the new keyword when you call it (which would break your code, but in a good way).
When this code is executed:
o=foo();
foo is executed in global context and so this line:
this.a='hello';
adds a property to the global object - window.
When you call your aaa function like this:
o.aaa()
the variable a is not defined within the function so it's looked up on up the scope chain and it's found on window:
function() {
return a; // found on window.a
}
and so window.a is returned.

Ways to break JavaScript Scope

JavaScript normally follows the function scope i.e. variables are accessible only within the function in which they are declared.
One of the ways to break this convention and make the variable accessible outside the function scope is to use the global window object
e.g.
window.myVar = 123;
My question is are there any other ways in JavaScript/jQuery to make the variable accessible outside the function scope?
Not with variable declarations, no. You can obviously declare a variable in an outer scope so that it's accessible to all descendant scopes:
var a; // Available globally
function example() {
a = "hello"; // References a in outer scope
}
If you're not in strict mode you can simply remove the var keyword. This is equivalent to your example:
// a has not been declared in an ancestor scope
function example() {
a = "hello"; // a is now a property of the global object
}
But this is very bad practice. It will throw a reference error if the function runs in strict mode:
function example() {
"use strict";
a = "hello"; // ReferenceError: a is not defined
}
As you wrote, variables are only visible inside the function in which they were defined (unless they are global).
What you can do is assign variables to the function object itself:
function foo() {
foo.myVar = 42;
}
console.log(foo.myVar); // outputs "undefined"
foo();
console.log(foo.myVar); // outputs "42"
But I would advise against it. You should really have a very good reason to do something like this.
You can define them as part of a global object, then add variables later
// Define your global object
var myObj = {};
// Add property (variable) to it
myObj.myVar = 'Hello world';
// Add method to it
myObj.myFunctions = function() {
// Do cool stuff
};
See the link below:
Variable declaration
Also, you can declare it without the var keyword. However, this may not be a good practice as it pollutes the global namespace. (Make sure strict mode is not on).
Edit:
I didn't see the other comments before posting. #JamesAllardice answer is also good.

What is the correct way to check if a global variable exists?

JSLint is not passing this as a valid code:
/* global someVar: false */
if (typeof someVar === "undefined") {
var someVar = "hi!";
}
What is the correct way?
/*global window */
if (window.someVar === undefined) {
window.someVar = 123456;
}
if (!window.hasOwnProperty('someVar')) {
window.someVar = 123456;
}
/**
* #param {string} nameOfVariable
*/
function globalExists(nameOfVariable) {
return nameOfVariable in window
}
It doesn't matter whether you created a global variable with var foo or window.foo — variables created with var in global context are written into window.
If you are wanting to assign a global variable only if it doesn't already exist, try:
window.someVar = window.someVar || 'hi';
or
window['someVar'] = window['someVar'] || 'hi';
try
variableName in window
or
typeof window[variableName] != 'undefined'
or
window[variableName] !== undefined
or
window.hasOwnProperty(variableName)
I think this is actually a problem with JSLint. It will issue the following error:
Unexpected 'typeof'. Compare directly with 'undefined'.
I believe this is bad advice. In JavaScript, undefined is a global variable that is, usually, undefined. But some browsers allow scripts to modify it, like this: window.undefined = 'defined'. If this is the case, comparing directly with undefined can lead to unexpected results. Fortunately, current ECMA 5 compliant browsers do not allow assignments to undefined (and will throw an exception in strict mode).
I prefer typeof someVar === "undefined", as you posted, or someVar in window as Susei suggested.
if (typeof someVar === "undefined") {
var someVar = "hi!";
}
will check if someVar (local or global) is undefined.
If you want to check for a global variable you can use
if(window['someVar'] === undefined) {
...
}
assuming this is in a browser :)
As of ES6 most of other answers, including the accepted answer, are incorrect, because global variables defined by let or const, or resulting from a class declaration, do not have corresponding properties on the global object (window in a browser, or global in node.js). Several of them—mainly the ones which use typeof—can also be fooled by global variables which exist but which are set to undefined.
The only fully general way to test to see if a global variable exists—regardless of whether it has been declared using var, let or const, created via a function or class declaration, created by assignment (i.e., myVar = value at the top level of a program without any declaration for myVar) or by creating a property on the global object (i.e., window.myVar = value)—is to attempt to access it via a global eval and see if TypeError is thrown.
(This builds on an idea presented by Ferran Maylinch, but with a trick to ensure that it will work properly even when encapsulated in a function.)
function globalExists(varName) {
// Calling eval by another name causes evalled code to run in a
// subscope of the global scope, rather than the local scope.
const globalEval = eval;
try {
globalEval(varName);
return true;
} catch (e) {
return false;
}
}
undeclared = undefined;
const myConst = undefined;
let myLet;
var myVar;
globalExists('undeclared') // => true
globalExists('myConst') // => true
globalExists('myLet') // => true
globalExists('myVar') // => true
globalExists('nonexistent') // => false
globalExists('globalExists') // => true - can see itself.
globalExists('varName') // => false - not fooled by own parameters.
globalExists('globalEval') // => false - not fooled by local variable.
Note that this makes use of eval, so all the usual caveats apply: you should not supply an untrusted value as the parameter, and if you must use an untrusted value you should check to make sure that varName is a valid JavaScript identifier. Doing so is out of scope for this question, but it can be done using a (rather complex) regular expression—just beware that the correct regexp depends on the version of ECMAScript you are using, whether the code is a script or (ES6) module, whether it is in an async function, etc. etc.
bfavaretto is incorrect.
Setting the global undefined to a value will not alter tests of objects against undefined. Try this in your favorite browsers JavaScript console:
var udef; var idef = 42;
alert(udef === undefined); // Alerts "true".
alert(idef === undefined); // Alerts "false".
window.undefined = 'defined';
alert(udef === undefined); // Alerts "true".
alert(idef === undefined); // Alerts "false".
This is simply due to JavaScript ignoring all and any values attempted to be set on the undefined variable.
window.undefined = 'defined';
alert(window.undefined); // Alerts "undefined".
This would be a simple way to perform the check .
But this check would fail if variableName is declared and is assigned with the boolean value: false
if(window.variableName){
}
I think the best solution is the following:
if(window.hasOwnProperty('foo')) {
console.log('Variable is not declared');
}
The following solution will not work if the variables is declared but is not assigned (var foo;).
typeof foo === 'undefined'
If you are not sure whether a global variable is defined, you can always try accessing it and see what happens.
function node_env(name) {
try {
return process.env[name];
} catch (ignore) {}
}

Why does an undefined variable in Javascript sometimes evaluate to false and sometimes throw an uncaught ReferenceError?

Everything I've ever read indicates that in Javascript, the boolean value of an undefined variable is False. I've used code like this hundreds of times:
if (!elem) {
...
}
with the intent that if "elem" is undefined, the code in the block will execute. It usually works, but on occasion the browser will throw an error complaining about the undefined reference. This seems so basic, but I can't find the answer.
Is it that there's a difference between a variable that has not been defined and one that has been defined but which has a value of undefined? That seems completely unintuitive.
What is a ReferenceError?
As defined by ECMAScript 5, a ReferenceError indicates that an invalid reference has been detected. That doesn't say much by itself, so let's dig a little deeper.
Leaving aside strict mode, a ReferenceError occurs when the scripting engine is instructed to get the value of a reference that it cannot resolve the base value for:
A Reference is a resolved name binding. A Reference consists of three
components, the base value, the referenced name and the Boolean valued
strict reference flag. The base value is either undefined, an Object,
a Boolean, a String, a Number, or an environment record (10.2.1). A
base value of undefined indicates that the reference could not be
resolved to a binding. The referenced name is a String.
When we are referencing a property, the base value is the object whose property we are referencing. When we are referencing a variable, the base value is unique for each execution context and it's called an environment record. When we reference something that is neither a property of the base object value nor a variable of the base environment record value, a ReferenceError occurs.
Consider what happens when you type foo in the console when no such variable exists: you get a ReferenceError because the base value is not resolvable. However, if you do var foo; foo.bar then you get a TypeError instead of a ReferenceError -- a subtle perhaps but very significant difference. This is because the base value was successfully resolved; however, it was of type undefined, and undefined does not have a property bar.
Guarding against ReferenceError
From the above it follows that to catch a ReferenceError before it occurs you have to make sure that the base value is resolvable. So if you want to check if foo is resolvable, do
if(this.foo) //...
In the global context, this equals the window object so doing if (window.foo) is equivalent. In other execution contexts it does not make as much sense to use such a check because by definition it's an execution context your own code has created -- so you should be aware of which variables exist and which do not.
Checking for undefined works for variables that have no value associated but if the variable itself hasn't been declared you can run into these reference issues.
if (typeof elem === "undefined")
This is a far better check as doesn't run the risk of the reference issue as typeof isn't a method but a keyword within JavaScript.
Is it that there's a difference between a variable that has not been defined and one that has been defined but which has a value of undefined?
Yes. A undeclared variable will throw a ReferenceError when used in an expression, which is what you're seeing.
if (x) { // error, x is undeclared
}
Compared to;
var y; // alert(y === undefined); // true
if (y) { // false, but no error
}
That seems completely unintuitive.
Meh... what I find unintuitive:
if (y) // error, y is undeclared
var x = {};
if (x.someUndeclaredAttribute) // no error... someUndeclaredAttribute is implictly undefined.
Here's an example of Jon's explanation regarding environment records:
var bar = function bar() {
if (!b) { // will throw a reference error.
}
},
foo = function foo() {
var a = false;
if (a) {
var b = true;
}
if (!b) { // will not throw a reference error.
}
};
In strict mode, it is an error:
function a() {
"use strict";
if (!banana) alert("no banana"); // throws error
}
It's always really been better to make an explicit test for globals:
if (!window['banana']) alert("no banana");
It doesn't make sense to perform such a test for non-global variables. (That is, testing to see whether the variable is defined that way; it's fine to test to see whether a defined variable has a truthy value.)
edit I'll soften that to say that it rarely makes sense to thusly test for the existence of non-globals.
When a variable is declared and not initialized or it's used with declaration, its value is "undefined". The browser complains exactly when this undefined variable is referenced. Here "reference" means some piece of javascript code is trying to visit an attribute or method of it. For example, if "elem" is undefined, this will throw an exception:
elem.id = "BadElem";
or you use try/catch:
try { x } catch(err){}
This way you're not doing anything in case of an error but at least your script won't jump off the cliff...
undefined = variable exists but has no value in it
ReferenceError = variable does not exist

No need to define a variable twice

If a variable could be defined in a function, even if no value is assigned, it becomes a local variable
so, is testB() better programming?
var test = 'SNAP!'
function testA(boolean) {
if (boolean) var test = 'OK';
else var test = null;
alert(test);
}
function testB(boolean) {
if (boolean) var test = 'OK';
alert(test);
}
testA(true); // 'OK'
testB(true); // 'OK'
testA(false); // null
testB(false); // undefined, no error
In my specific case test's global value ('SNAP!') is neither expected nor required.
You can't declare variables conditionally.
Why?
The variable instantiation process occurs before the actual code execution, at the time the function is executed, those variables will be already bound to the local scope, for example:
function foo () {
if (false) {
var test = 'foo'; // never executed
}
return test;
}
foo(); // undefined
When the function is about to be executed, identifiers of formal parameters, identifiers from variable declarations, and identifiers from function declarations within the function's body are bound to the local variable environment.
Variables are initialized with undefined.
Also, identifiers in the local scope shadow the others with the same name, higher in the scope chain, for example:
var test = 'global';
function bar () {
alert(test); // undefined, not "global", the local variable already declared
var test = 'xxx';
}
bar();
If the test variable were not declared anywhere, a ReferenceError will be thrown:
function foo () {
return test;
}
try {
foo(); // ReferenceError!!
} catch (e) {
alert(e);
}
That's one of the reasons about why for example, JSLint recommends only one var statement at the top of functions, because for example, the first snippet, will actually resemble this when executed:
function foo () {
var test; // var statement was "hoisted"
if (false) {
test = 'foo'; // never executed
}
return test;
}
foo(); // undefined
Another reason is because blocks don't introduce a new lexical scope, only functions do it, so having a var statement within a look might make you think that the life of the variable is constrained to that block only, but that's not the case.
Nested function declarations will have a similar behavior of hoisting, they will be declared before the code execution, but they are initialized in that moment also:
function foo () {
return typeof bar;
// unreachable code:
function bar() {
//..
}
}
foo(); // "function"
If the variable does not need to be manipulated by any other functions, keep the variable inside a function with var foo;.
Otherwise, if it does need to be accessed and read in multiple scopes, keep it outside. But remember that when you keep it outside, it becomes global. That is, unless you wrap everything in a self executing function, which is the best way:
(function() {
var president='bush';
function blah() {
president='reagan';
}
function meh() {
president= 'carter';
}
document.getElementById('reagan').onclick=blah;
document.getElementById('carter').onclick=meh;
})();
alert( president ) // undefined
The above is perfect for a variable accessed by functions defined inside of that scope. Since there are 2 elements i click to set the president, it makes sense to define it outside both functions because they set the same variable.
So, If you are not dealing with multiple functions changing the exact same variable, keep them local to the function.
Is testB better programming? No, because it gives an unexpected result of "undefined" (at least, I was surprised by that) and it is hard to read.
Generally, variables should be limited to the scope that requires them, so if the "test" variable is not needed outside the function it should be declared local. To avoid confusion, declare your variable before using it:
function testC(boolean) {
var test;
if (boolean) {
test = "OK";
}
else {
test = null;
}
alert(test);
}
Unless you genuinely want to change the global scope version of "test", in which case don't use the var keyword inside the function.
If you ever find yourself using the same name for a local variable and a global variable you might consider renaming one of them.

Categories