I have the function:
isset = function(obj){
alert(obj !== undefined);
}
Then when I do isset(defined_variable) where defined_variable has been declared, the alert box shows true but when I do isset(undefined_variable) where undefined_variable has not been declared, the alert box does not show at all, while I expected the alert box to show false. What am I doing wrong? I have tried using typeof but the results are the same.
That's because there's a difference between undefined and undeclared.
var foo; // foo is undefined.
// bar is undeclared.
console.log(foo === undefined); // true
try {
console.log(bar === undefined);
} catch (e) {
console.error('I had an error!'); // gets invoked.
}
foo = 'something';
console.log(foo === undefined); // false
but when I do isset(undefined_variable) where udefined_variable has
not been declared, the alert box does not show at all, while I
expected the alert box to show false
because it throws an error in your console (check your console) that this variable that you are comparing is not defined.
Uncaught ReferenceError: 'c' is not defined
i tried with isset( c ) and c was not declared first
When you dereference an undeclared variable (meaning you try to use a symbol that was never wrote before), you get a Reference error.
There are several ways to deal with this, but you can't determine what are local variables in javascript. Thus, your problem can be solved dynamically only for global variables, or a given scope object.
No functions could handle local scope dynamically.
You can prefix it with window if you are in a browser context (for more context see this SO answer about global object in javascript)
This would not modify your isset function code:
isset(window.undefined_variable)
There would be another way, which would need that isset function changes, but uses the same principle (still in browser context):
isset('undefined_variable_name_wrawppped_in_a_string')
function isset(name) {
return name in window;
}
We can't really use typeof in isset, it's sad because it would be convenient since it doesn't throw a Reference Error when the variable was never declared. We could still use a form of eval to do it, but since I don't want us to go there, I won't implement it.
But now, what if you want to check several nested properties?
function isset (memoryPath, root) {
var nodeNames = memoryPath.split('.');
var expectedDepthReached = nodeNames.length;
var depthReached = 0;
var nodeName;
var node = root;
// we are gonna read it from left to right
// using Array.prototype.pop()
// reversing it will alow us to do so
nodeNames.reverse();
do {
nodeName = nodeNames.pop();
node = node[nodeName];
if (node) {
depthReached++;
}
} while (node);
return depthReached === expectedDepthReached;
}
And an exemple:
window.myGlobals = {
path: {
to: {
a: {
variable: true
}
}
}
};
isset('myGlobals.path.to.a.variable', window), // true
isset('myGlobals.path.foo', window) // false
Related
I know that to find if a variable is undeclared in javascript, I can use if (typeof variable === 'undefined'). If I declare a variable as undefined (var variable = undefined), the if statement still returns true. Is it possible, in JavaScript, to find the difference between undeclared variables and variables with a value of undefined? I know that they are similar, but doing const variable = undefined and then variable = "something else" will throw an error, so they must be different.
const variable = undefined
if (typeof variable === 'undefined') {
console.log('"variable" is undefined')
}
if (typeof undeclaredVariable === 'undefined') {
console.log('"undeclaredVariable" is undefined')
}
I wouldn't like to use a try catch block because I want to be able to assign another constant based on this. I would like a solution like this: const isVariableDeclared = variable === undeclared, except undeclared does not exist in javascript. I know I can use let with a try catch block but am looking for something more elegant.
At least in the time of writing... No, it does not seem that you can do something like this:
var a = undeclared(var) ? 'undeclared' : 'undefined'
The reason is that you cannot pass an undeclared variable to a function; It raises an error, even in non-strict mode.
The best we can do, is this:
var barIsDeclared = true;
try { bar; }
catch (e) {
if (e.name == "ReferenceError") {
barIsDeclared = false;
}
}
console.log(barIsDeclared);
Why?
Undefined: It occurs when a variable has been declared but has not
been assigned with any value. Undefined is not a keyword.
Undeclared: It occurs when we try to access any variable that is not
initialized or declared earlier using var or const keyword. If we use
‘typeof’ operator to get the value of an undeclared variable, we will
face the runtime error with return value as “undefined”. The scope of
the undeclared variables is always global.
For example:
Undefined:
var a;
undefined
console.log(a) // Success!
Undeclared:
console.log(myVariable) // ReferenceError: myVariable is not defined
When we try to log an undeclared variable, it raises an error. Trying to log an undefined variable does not. We make a try catch to check for just that.
'use strict'
Worth mentioning that adding 'use strict' in your code verifies that no undeclared variable is present, and raises an error if one is present.
function define() {
//'use strict' verifies that no undeclared variable is present in our code
'use strict';
x = "Defined";
}
define();
ReferenceError: x is not defined
Further reading:
Checking if a variable exists in javascript
What are undeclared and undefined variables in JavaScript?
JS Interview Question: What’s the difference between a variable that is: null, undefined or undeclared?
JavaScript check if variable exists (is defined/initialized)
Strict mode
As others already did point to, the OP might want to distinguish between declared but undefined references and undeclared reference names ...
let declaredButUnassignedAndStrictlyEqualToUndefinedValue;
const declaredAndHavingAssignedTheUndefinedValue = undefined;
// There is no way of telling the above two (un/)assignements appart.
console.log(
'(declaredButUnassignedAndStrictlyEqualToUndefinedValue === declaredAndHavingAssignedTheUndefinedValue) ?',
(declaredButUnassignedAndStrictlyEqualToUndefinedValue === declaredAndHavingAssignedTheUndefinedValue)
);
// the `typeof` operator is of no help
// if it comes to distinguish between
// declared but undefined references
// and undeclared reference names ...
console.log(
'typeof notDeclaredWithinScope :', typeof notDeclaredWithinScope
);
// ... just a try catch can do that.
try {
notDeclaredWithinScope;
} catch (err) {
// console.log(err.message);
console.log('`notDeclaredWithinScope` does not exist within this scope.')
}
.as-console-wrapper { min-height: 100%!important; top: 0; }
Thanks for all of the help! I've pieced together a simple solution that fits my needs from all of the answers if anyone wants it. The only drawback is that variable names must be passed as strings. It uses a try catch block but I can still use it for my original use case (assign a constant based on it).
function declared(variable) {
let declared = true;
try {
eval(variable);
} catch (e) {
if (e.name === "ReferenceError") {
declared = false;
}
}
return declared;
}
let declaredVar;
console.log(declared("declaredVar")); // true
console.log(declared("undeclaredVar")); // false
function typeOf(variable) {
return eval("typeof " + variable) === "undefined"
? declared(variable)
? "undefined"
: "undeclared"
: eval("typeof " + variable);
}
const stringVar = "string";
const undefinedVar = undefined;
console.log(typeOf("stringVar")); // string
console.log(typeOf("undefinedVar")); // undefined
console.log(typeOf("undeclaredVar")); // undeclared
I understood what your saying. There is no defined way to get the exact answer but there is a way to find whether it is defined or not. It is possible only if it referenced somewhere.
Eg:
// Lets think x is not defined
x.substring(1);
Output:
ReferenceError: "x" is not defined
So if you use try catch block method, with the help of catch error message you can identify whether it is defined or not!
I've given some thoughts on declaring a variable called undefined and evaluating a truthy if-else expression with it. I found out that it is not possible in global scope. But in MDN I've found some interesting insight about the undefined datatype. I am directly quoting from MDN
undefined is a property of the global object; i.e., it is a variable
in global scope.
It doesn't say anything about local scope. That means i can create one in local scope. So, I move on to put this insight to test. I have created an object and assign a method to it
var person = {
method : function(){
var undefined = 2
if(undefined){
console.log("undefined works as a variable")
}
}
}
person.method()
And guess what! the if statement passes the test and the string inside the console.log() gets printed on the console.This might be a dangerous thing and of course a bad practice. Is there any way to prevent the declaration of a variable named after undefined keyword in javascript's local scope ? Thanks!
To work around accidental modification of undefined, you should not write this dangerous word in your code at all.
Since you only need read access to undefined, it is recommended to always use void 0 instead, which returns undefined.
var person = {
method: function() {
var undefined = 2
if(void 0) {
console.log("this should never be printed")
} else {
console.log("void 0 is always undefined, no matter what you do")
}
}
}
person.method()
How to work with void 0 and completely get rid of the word "undefined"?
// Turn
if(myVariable === undefined) { ... }
if(typeof myVariable === "undefined") { ... }
// into
if(myVariable === void 0) { ... }
// Turn
if((myVariable === undefined) || (myVariable === null)) { ... }
// into
if(myVariable == null) { ... }
// Turn
myObject.someKey = undefined
// into
myObject.someKey = void 0
Welcome to the wonderful world of JavaScript!
There is no way to prevent someone from doing this, but there is a way to ensure that undefined will mean undefined if you set up your functions as follows (not that you should really have to do this because it would be very bad practice for anyone to actually set up a variable named undefined). Essentially smaller scoped functions could hide a higher scoped undefined variable.
// This is just a way to get a variable called "undefined"
function wrapper(){
var undefined = 10;
console.log("wrapper says undefined is: " + undefined);
// This function declared a parameter called "undefined",
// but if the function gets called with no argument, then
// the value of this, more local, argument will truly be
// undefined. If arguments are needed, just add "undefined"
// to the end of the list.
function foo(undefined){
// Formal test to ensure that undefined is what we believe it to be:
if(typeof undefined === "undefined"){
console.log("foo says undefined is: " + undefined);
}
}
// When foo is called with no arguments passed in, the parameter
// "undefined" will take on a value of undefined within the scope
// of that function.
foo();
}
wrapper();
Now, that's a bit contrived as you're not going to set up all your functions with a "fake" argument, but you could test to see if undefined has been altered with:
function wrapper(){
var undefined = 10;
console.log(undefined);
function foo(){
if(typeof undefined === "undefined"){
// undefined has not been altered
} else {
// undefined has been altered, so reset it for this scope:
let undefined;
console.log(undefined);
}
}
foo();
}
wrapper();
In the end though, you could simply prevent this from affecting your functions by adding var undefined in your functions. Hoisting will make sure that this kicks in at the top of your function, no matter where you declare it.
I can't see any way to stop it, but yes, You can restrict it passing the yes inside If you can make the scope local using ES6.
You will find how scope if changed now and it's not the same thing.
var person = {
method : function(){
let undefined = 2
if(undefined){
console.log("undefined works as a variable")
}
}
}
Does anyone know some tricks how to do it? I tried to use try-catch:
"use strict";
const a = 20;
var isConst = false;
try {
var temp = a; a = a+1; a = temp;
} catch (e) {
isConst = true;
}
But unfortunately it works only in "strict" mode. Without "use strict" it perform all statements silently, without modification of a. Also I cannot wrap this code into some handy function (isConstant(someConst) for example) as any argument I'll pass to that function will be a new variable. So anyone know how to create isConstant() function?
I don't think there is, but I also don't think this is a big issue. I think it might be useful to have the ability to know if a variable is const, and this exists in some other languages, but in reality since you (or someone on a team) will be defining these variables, you'd know the scope and the type of the variables. In other words, no you can't, but it's also not an issue.
The only case where it might be useful is if you could change the mutable property during runtime, and if changing this property had actual performance benefits; let, const, and var are treated roughly equally to the compiler, the only difference is that the compiler keeps track of const and will check assignments before it even compiles.
Another thing to note is that just like let, const is scoped to the current scope, so if you have something like this:
'use strict';
const a = 12;
// another scope
{
const a = 13;
}
it's valid. Just be careful that it will look up in higher scopes if you don't explicitly state const a = 13 in that new scope, and it will give a Read Only or Assignment error:
'use strict';
const a = 12;
{
a = 13; // will result in error
}
Based on some of the answers here I wrote this code snippet (for client side JS) that will tell you how a "variable" was last declared--I hope it's useful.
Use the following to find out what x was last declared as (uncomment the declarations of x to test it):
// x = 0
// var x = 0
// let x = 0
// const x = 0
const varName = "x"
console.log(`Declaration of ${varName} was...`)
try {
eval(`${varName}`)
try {
eval(`var ${varName}`);
console.log("... last made with var")
} catch (error) {
try {
eval(`${varName} = ${varName}`)
console.log("... last made with let")
} catch (error) {
console.log("... last made with const")
}
}
} catch (error) {
console.log("... not found. Undeclared.")
}
Interestingly, declaring without var, let or const, i.e x = 0, results in var getting used by default. Also, function arguments are re-declared in the function scope using var.
Just check if your reassignment actually did something:
var isConst = function(name, context) {
// does this thing even exist in context?
context = context || this;
if(typeof context[name] === "undefined") return false;
// if it does exist, a reassignment should fail, either
// because of a throw, or because reassignment does nothing.
try {
var _a = context[name];
context[name] = !context[name];
if (context[name] === _a) return true;
// make sure to restore after testing!
context[name] = _a;
} catch(e) { return true; }
return false;
}.bind(this);
You need the try/catch because reassign Could throw an exception (like in Firefox), but when it doesn't (like in Chrome), you just check whether your "this always changes the value" reassignment actually did anything.
A simple test:
const a = 4;
var b = "lol";
isConst('a'); // -> true
isConst('b'); // -> false
And if you declare the consts in different context, pass that context in to force resolution on the correct object.
downside: this won't work on vars declared outside of object scopes. upside: it makes absolutely no sense to declare them anywhere else. For instance, declaring them in function scope makes the const keyword mostly useless:
function add(a) {
return ++a;
}
function test() {
const a = 4;
console.log(add(a));
}
test(); // -> 5
Even though a is constant inside test(), if you pass it to anything else, it's passed as a regular mutable value because it's now just "a thing" in the arguments list.
In addition, the only reason to have a const is because it does not change. As such, constantly recreating it because you're calling a function that makes use of it more than once, means your const should live outside the function instead, so again, we're forced to put the variable in an object scope.
The question refers to incompliant behaviour in earlier ES6 implementations, notably V8 (Node.js 4 and legacy Chrome versions). The problem doesn't exist in modern ES6 implementations, both in strict and sloppy modes. const reassignment should always result in TypeError, it can be caught with try..catch.
There can't be isConstant function because const variable cannot be identified as such by its value.
It's preferable to run a script in strict mode and thus avoid problems that are specific to sloppy mode.
Even if a variable was defined in sloppy mode, it's possible to enable strict mode in nested function scope:
const foo = 1;
// ...
let isConst = false;
(() => {
'use strict';
try {
const oldValue = foo;
foo = 'new value';
foo = oldValue;
} catch (err) {
isConst = true;
}
})();
It's beneficial to use UPPERCASE_CONSTANT convention which is used in JavaScript and other languages. It allows to unambiguously identify a variable as a constant without aid from IDE and avoid most problems with accidental reassignments.
I am writing a script that deals with a variable gameRegion like so:
//In the main of the script
var variable= new work();
variable.onCrash(crashHandler,{xPos:650,yPos:300});
// In function work()
var gameRegion;
var onCrashCallback;
this.onCrash = function(crashCallback,fieldSize) {
gameRegion = fieldSize;
onCrashCallback = crashCallback;
};
crashHandler(){
//unimportant
}
this.atBottom = function(ypos) {
if(ypos>gameRegion.yPos) //line with the problem
return true;
return false;
};
I am getting the console error: TypeError: 'undefined' is not an object (evaluating 'gameRegion.yPos'). Presumably that means I am not properly defining gameRegion or its variable yPos. I've been looking at this code for a while now and I can't seem to find what the problem is.
Hopefully you'll see something that I don't, but if I'm not including necessary code for context, please tell me. Thanks for any help in advance.
You have to handle 'undefined'. Which can be done in these ways:
typeof(foo) == 'undefined'
typeof foo !== 'undefined'
window.foo !== undefined
'foo' in window
The first three should be equivalent (as long as foo isn't shadowed by a local variable), whereas the last one will return true if the global varible is defined, but not initialized (or explicitly set to undefined).
You can use typeof like so -
return (typeof (gameRegion) !== "undefined" &&
typeof(gameRegion.yPos) !== "undefined" &&
ypos > gameRegion.yPos);
How do I check whether a variable name is "in use"? Meaning: how do I check if a variable name has already been used in a var varname = 'something' statement?
Normally, I would just check if typeof varname == 'undefined', which seems to work fine. The issue is when there is an element on the page with id="varname". Now, when I check typeof varname == 'undefined', i get false regardless, because varname is some HTML element.
varname is not "in use", but it is not undefined either.
<body id="test1"></body>
<script>
//if <body> has an id of test1, how do i check if test1 is undeclared?
console.log(typeof test1 == 'undefined'); // the <body> element causes this to be true
console.log(typeof test2 == 'undefined'); // outputs true as expected
</script>
Additionally, can you check for the corner case: var test1 = document.getElementById('test1') has been executed?
The only possible way to achieve what you need is through the evil eval(), as it is not possible to access local variables through their name as strings. (Globals are possible using window["variableNameAsString"].)
The solution snippet presented below has the following effect:
Returns true if varName was declared and initialized (even if with null) and is readable from the current scope. Otherwise returns false.
DEMO jsFiddle here.
Source:
function removeIdOfAllElementsWithId(id) {
var element, elementsFound = [];
while ((element = document.getElementById(id)) !== null) {
element.removeAttribute('id')
elementsFound.push(element);
}
return elementsFound;
}
function assignIdToElements(elements, id) {
for (var i = 0, n = elements.length; i < n; i++) { elements[i].id = id; }
}
var isDefinedEval = '(' +
function (isDefinedEvalVarname) {
var isDefinedEvalResult;
var isDefinedEvalElementsFound = removeIdOfAllElementsWithId(isDefinedEvalVarname);
try {
isDefinedEvalResult = eval('typeof '+isDefinedEvalVarname+' !== "undefined"');
} catch (e) {
isDefinedEvalResult = false;
}
assignIdToElements(isDefinedEvalElementsFound, isDefinedEvalVarname);
return isDefinedEvalResult;
}
+ ')';
Usage:
To test if a variable with name variableName is defined:
eval(isDefinedEval + '("' + 'variableName' + '")') === true
To check if it is not defined:
eval(isDefinedEval + '("' + 'variableName' + '")') === false
In the fiddle you'll find lots of unit tests demonstrating and verifying the behavior.
Tests:
Several tests are included in the fiddle;
This snippet was tested in IE7, IE8 and IE9 plus latests Chrome and Firefox.
Explanation:
The function must be used through eval() because it needs to have access to the variables locally declared.
To access such variables, a function must be declared in the same scope. That's what eval() does there: It declares the function in the local scope and then calls it with varName as argument.
Aside that, the function basically:
- Removes the ID attribute of every element that has an ID === varName;
- Checks if the variable is undefined;
- And reassign the ID of those elements it removed the attribute.
Note: this answer was heavily edited, some coments may not be still appliable.
Not sure if this what you are looking for.
if(typeof test1 == "undefined" && document.getElementById("test1") == null) {
//There is no element with an id="test1" and a variable test1
}
In a context other than the global context in some browsers, it is impossible to reliably determine if a variable has been defined (either by being declared or otherwise initialised) or not other than using try..catch.
Therefore it's not a good strategy to need to do that.
In a global context, in non–IE browsers, you can do something like:
var global = this;
if (!global.hasOwnProperty('foo')) {
// there is no global foo
}
but IE doesn't implement hasOwnProperty on the global object. Note that DOM element names and IDs do not overwrite the value of declared global variables.
But anyway, all this is useless since you may well have:
var foo = document.getElementById('foo');
What now?