79

JSLint is not passing this as a valid code:

/* global someVar: false */
if (typeof someVar === "undefined") {
    var someVar = "hi!";
}

What is the correct way?

Ebrahim Byagowi
  • 10,338
  • 4
  • 70
  • 81
  • 1
    Note that the `var` is not scoped to the `if` block. It's as if you had written `var someVar` above the `if`. Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var#var_hoisting – leewz Oct 11 '16 at 05:41
  • 3
    Went down a huge rabbit-hole after reading only the code in the answers here, and not the one in the question. If you want to write code that works on both Nodejs and the browser, this *is* the correct way to check if a variable is undefined, regardless of what JSLint may think about it. – Tobias Cohen Jun 14 '19 at 02:15

11 Answers11

99
/*global window */

if (window.someVar === undefined) {
    window.someVar = 123456;
}

if (!window.hasOwnProperty('someVar')) {
    window.someVar = 123456;
}
antonagestam
  • 4,532
  • 3
  • 32
  • 44
user124
  • 1,632
  • 1
  • 11
  • 11
  • 6
    Instead of `/*global window */`, you could use `/*jslint browser: true */`. – XP1 Jul 24 '12 at 23:58
  • 13
    To have the same result, the second solution should actually be `if(!window.hasOwnProperty('someVar'))` – aaaaaa Oct 11 '12 at 09:48
  • 2
    what if a the page runs this script before yours : `undefined = 'some value'` ? – gion_13 Nov 27 '12 at 13:11
  • 2
    @gion_13 `undefined = 'some value'; console.log(undefined);` still gives `undefined`. – Glen Solsberry Dec 19 '12 at 13:55
  • 1
    @gms8994 newer browsers don't let you overwrite the `undefined` *constant*. – gion_13 Dec 19 '12 at 20:00
  • @EbrahimByagowi: Don't use `.hasOwnProperty()` for this. It can fail. –  Jul 14 '13 at 14:24
  • `.hasOwnProperty()` is [a lot slower](http://jsperf.com/check-for-declared-global-in-vs-typeof). – Alex W Apr 16 '14 at 02:56
  • 3
    Note that "window" itself is not defined in a web worker. For max compatibility, check the presence of window first. – Offirmo Oct 14 '14 at 22:54
  • @CrazyTrain it can fail specifically because it might be overridden in the scope chain. There are ways to get around it, and to @alex-w's point, even if it is a lot slower, it also returns the correct value. Solution: `Object.prototype.hasOwnProperty.call(window, 'someVar')` – skeggse Jan 07 '15 at 19:17
  • this assumes that the javascript code in question is running in a browser – Michael Oct 20 '15 at 01:54
  • 1
    Why are there two conditions in this answer? Are both really required, and why? – Flimm Jan 28 '16 at 11:25
  • 7
    @Offirmo Any thoughts on how to do that? In that case, `window` is a global variable, whose existence we want to check - which of course is the problem we'd like to solve in the first place. – James_pic Jul 19 '16 at 16:35
  • Backbone does it. Here is URL to annotated 'backbone' source (see "root", at very beginning of code): https://backbonejs.org/docs/backbone.html – IAM_AL_X May 29 '21 at 19:24
15
/**
 * @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.

gvlasov
  • 18,638
  • 21
  • 74
  • 110
  • 5
    Of course, you don't have to use a function, you can simply use `"foo" in window` anywhere – gvlasov Jul 21 '12 at 22:33
  • 3
    Hrmmm, JSlint says: `Unexpected 'in'. Compare with undefined, or use the hasOwnProperty method instead.` Then, I guess, the right way is: `window.hasOwnProperty("nameOfVar")` – gvlasov Jul 22 '12 at 03:39
  • 2
    @Susei: jsLint is incorrect. The `.hasOwnProperty()` is faulty because there can be a global that is further down the prototype chain of `window`. It's still a global variable, but `.hasOwnProperty()` won't see it. The `in` or `undefined` tests are the way to do it. –  Jul 14 '13 at 14:22
  • 1
    This won't work in a NodeJS terminal; `window` is undefined there. – cst1992 Feb 07 '17 at 11:55
  • good answer for a React app where you might want to have an inline check in your JSX – Felipe May 16 '21 at 18:10
13

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';
mrak
  • 494
  • 5
  • 10
  • This is the most elegant and cleanest solution. – Christian Dec 07 '16 at 01:05
  • 1
    This will not work as expected if the global variable is falsy. If `someVar` contains a value like `0` or `''`, it will assign `'hi'` to it instead of using the existing value. – hungerstar Aug 03 '18 at 17:21
9

try

variableName in window

or

typeof window[variableName] != 'undefined'

or

window[variableName] !== undefined

or

window.hasOwnProperty(variableName)
gion_13
  • 41,171
  • 10
  • 96
  • 108
  • 2
    Did you try to test these on JSLint? "'someVar' in window", "typeof window['someVar'] !== 'undefined'", "window['someVar'] !== undefined" (without converting it to "window.someVar !== undefined) are not Okay on JSLint. But anyway, thanks for your great answer :) – Ebrahim Byagowi Jul 22 '12 at 03:46
  • 1
    `"prop" in object` is absolutely legal JavaScript. Remember, JSLint is for you, not you for JSLint, and JSLint is not a JavaScript. For me `if ('prop' in obj) { do_it(); }` is more clear (i.e. readable and maintainable), then `if (obj.prop !== undefined) { do_it(); }`. I would suggest you to ignore JSLint in this case. Also see http://stackoverflow.com/questions/6824895/jslint-error-unexpected-in-compare-with-undefined-or-use-the-hasownproperty. – kstep Nov 27 '12 at 11:44
  • You are absolutely right but I rather to keep my codes JSLint validated because it is easier to maintain. – Ebrahim Byagowi May 23 '13 at 12:51
8

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.

bfavaretto
  • 71,580
  • 16
  • 111
  • 150
  • 3
    Particularly relevant today because not all JS will run in a browser. If you are writing a library you want your code to work both against the browsers as well as runtimes like nodejs where window does not exist. – Chris Wininger Sep 29 '16 at 13:46
6
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 :)

Vatev
  • 7,493
  • 1
  • 32
  • 39
5

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.

cpcallen
  • 1,834
  • 1
  • 16
  • 27
  • Interesting, good catch on `log` and `const`. I was curious about `eval` and, if `varName` is not provided by a user, I guess it should not be a dangerous usage to evaluate a variable name? How can it be weaponized? Anyway I found this interesting part on [MDN: never_use_eval!](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval#never_use_eval!) and `eval` can be replaced with ```Function(`"use strict";return ${varName}`)(); ``` I've tested it and works just as fine! – Gruber Jun 20 '22 at 08:43
  • @Gruber: globalExists has the same safety properties as `eval`: that is, it is perfectly safe as long as its argument is never controlled by a hostile actor. If you only ever pass string literals that are valid variable names, for example, then it is harmless. I think [never use eval](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval#never_use_eval!) is not a highlight of the MDN documentation: the `Function` constructor is no safer than `eval`, I am skeptical about the claimed speed advantage, and the `globalEval` trick is just as good for scope control. – cpcallen Jun 21 '22 at 10:07
1

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".
Michael
  • 19
  • 1
  • 4
    You shouldn't use the Answers section just to disprove another person's answer. If you don't think another person's answer works, either comment on their answer as to the problem(s) you foresee so they can fix it, or offer your own valid solution to the question. – Scott Sep 24 '12 at 13:03
  • 1
    This is relevant, but it doesn't answer the question. I realize this is too long to post as a comment, perhaps you could also _answer_ the question below your disagreement? – Tim Post Sep 24 '12 at 13:50
  • 1
    You could have left a comment on my answer just to let me know you disagree, I only saw your answer by accident. You're kind of right about our "favorite browsers", the problem is that older browsers didn't prevent that. I'll edit my answer to make it more clear. – bfavaretto Oct 01 '12 at 02:58
  • Unfortunately, despite restrictions in modern browsers, `undefined` can still be modified: this function is perfectly legal: `function foo(undefined, x) { if (x === undefined) { alert('undefined!'); } }`. It will _not_ alert if you call, for instance, `foo(3)`. The lesson is that 'undefined' is not always a reference to the global property. – Ted Hopp Mar 03 '13 at 23:25
1

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){

}
Gwenc37
  • 2,064
  • 7
  • 18
  • 22
Prem Anand
  • 19
  • 2
  • This does not work if `variableName` has any falsy value (for example emtpy string), so this might not be a sufficient solution. – Hinrich Jul 17 '19 at 08:11
1

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'
Arthur Rubens
  • 4,626
  • 1
  • 8
  • 11
  • I swore I've seen code that threw an error on `typeof` when the variable is undefined, But `typeof` seems to work everywhere now. Interactively from node (`node -e "console.log(typeof foo === 'undefined')"`), in the devtools console (`console.log(typeof foo === 'undefined') // true`) and from a file (`node test.js // true`) Even in with `"use strict";` – Shanimal Nov 05 '21 at 16:21
-1

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) {}
}
diachedelic
  • 2,195
  • 1
  • 24
  • 28