68

i feel like im trying to do something super simple, but just being stupid about it.

all i want to do is see if a variable has been set previously, and if it has NOT, set it with a default value....here is a sample:

if(!embed_BackgroundColor) {
    var embed_BackgroundColor;
    embed_BackgroundColor = "#F4F4F4";
}

so, once you stop laughing at my code....WHY is it overwriting the variable no matter what?

please save my nerves;)

eyelidlessness
  • 62,413
  • 11
  • 90
  • 94
johnnietheblack
  • 13,050
  • 28
  • 95
  • 133

16 Answers16

107

Pro style:

var SomeVar = SomeVar || 'Default Value';
Pikachu
  • 1,973
  • 3
  • 20
  • 27
  • 2
    :\ Does this not reassign `SomeVar` to itself? Indeed it looks like a "pro" style, but it does - in fact - appear to be somewhat un-optimized (esp. for a for/while loop). I would just stick with an if. However, I could be wrong and the interpreter might recognize that it doesn't need to store a `var` back into *itself*. – dylnmc Oct 01 '15 at 13:35
  • 15
    A word of warning: If `SomeVar` can be a false-y value, this will fail. Things like `''`, `false`, and `0` will trip the `||` and set the default If you want `SomeVar` to be able to be 'false-y' values, then use a ternary, like in @Jhuni answer (but with the var keyword like in this one). Also agree with @dylnmc, this results in unnessary reassignment. @Paolo Berantino has what i feel is the 'correct' answer. I personally strongly disagree that "small and compact" is nessarily 'Pro Style'. We don't use punchcards anymore, and js minifiers equalize the rest. – Fodagus May 12 '16 at 17:10
  • 9
    Using this approach I receive `Uncaught ReferenceError: my_var is not defined` (Chrome -v 48.0) – Stelian May 13 '16 at 07:48
  • 1
    This is not very verbose. A new programmer would not be able to immediately decode what happens. I would not recommend this. – Mads Buch Jun 29 '16 at 11:56
  • 5
    This the wrong answer and a "pro" would certainly not do this due to the issues mentioned by @Fodagus. Also I suspect it might not work in some JS engines, with certain strict settings or linters since it's assigning a value that potentially does not exist (which could be the issue of @popas). Just use the proper way which is `typeof Somevar === 'undefined'` to avoid all these problems. – laurent Jul 06 '17 at 07:59
  • Just realized that this question raises (yet another) JS caveat. There are two types of "undefined" variables! 1. A declared variable with no value 2. A non declared variable This answer only catches (1) var x; typeof(x) === "undefined" // true y=x+1; NaN typeof(neverDeclared) === "undefined" // true y=neverDeclared+1 // ReferenceError: neverDeclared is not defined – Ronenz Aug 24 '17 at 11:05
  • If you are using modern JavaScript you should use the Nullish coalescing operator (??) instead of "||" – Eliaz Bobadilla Feb 24 '22 at 15:46
  • I remember seeing it all the way back in '00s for the first time, and after figuring out what it does, actually thinking it is a *pro style*. Ah, the good old [#vectorheart](https://twitter.com/vectorheart) days. I think for a quick test against a variable that shouldn't be false-y, this will work fine. Thumbs up! – ᴍᴇʜᴏᴠ Sep 14 '22 at 13:38
83
if (typeof variable === 'undefined') {
    // variable is undefined
    // eg:
    // var variable = "someValue";
}
Georg Schölly
  • 124,188
  • 49
  • 220
  • 267
Paolo Bergantino
  • 480,997
  • 81
  • 517
  • 436
  • 1
    the problem is that no matter what the // var variable = "someValue" is overwriting the pre-defined value that DID exist – johnnietheblack Apr 02 '09 at 21:10
  • is that really three =s? (i don't know) – jedierikb Aug 04 '09 at 00:59
  • 3
    I'm not sure why this is accepted. It seems using the code above (with the `var variable = "someValue";` line uncommented results in `variable` always being equal to "someValue" even if it was already defined. – Mike Deck Sep 07 '11 at 21:44
  • 2
    @Mike if it was already defined, you would not get into the if condition. – pedz Dec 30 '12 at 15:20
  • 3
    @pedz it doesn't matter because the 'var' keyword will make the variable inside the if get redefined even if it never enters the if block. JS doesn't have a "block level scope variable definition". – xDaizu May 30 '16 at 11:00
  • 1
    @xDaizu declaration is hoisted but initialization/assignment is not. AFAIK repeated declaration doesn't have any negative side effects. https://jsbin.com/bibuneseno/edit?js,console,output – WD40 Mar 16 '19 at 17:28
53

It would be a good coding practice in this case to use the ternary operator. Also you don't need to have three equal signs when comparing with typeof. This is the most concise solution:

b = typeof(b) == 'undefined' ? 0 : b;

This hopefully will save your hands some time.

  • 1
    Similar to the comment on `calmbird`'s response (below ... maybe), it looks like b is being reassigned to itself when it is defined. That seems like it could be bad-ish (not terrible) in a loop. Again, I don't know how the interpreter will deal with this exactly, but it looks like it will be an unnecessary reassignment. – dylnmc Oct 01 '15 at 13:37
  • 7
    I thinks must use `===` instead of `==` – Nabi K.A.Z. Feb 19 '16 at 04:10
  • Should be accepted answer as it does not do _dirty_ equality checking – Jack Dec 27 '17 at 11:50
  • 1
    Sadly your answer is not entirely true, as double equa sign means the inter[reter will automatically try type conversion. Using `a === b` will always be faster, as the values are strictly compared, ommiting one step. – Shape Jan 15 '21 at 15:17
  • Technically correct and also multiple examples of poor style, right down to the single-char variable name and lack of declaration. Just wow. – tekHedd Oct 24 '22 at 18:38
32

To actually answer your question of WHY this is happening, it is because of variable hoisting.

Basically, there is a phase before executing code in the global scope or inside a function where the code is scanned for all var and function declarations (not to be confused with function expressions, but that's a different story).
All these variable and functions are then declared inside the current scope, and only afterwards does the code actually run.

This happens regardless of their position in the code, with scopes corresponding to function bodies, not blocks of statements. And what makes this even more counter-intuitive, even if you set an initial value to variables in their declarations, they will still remain "empty" until the declaration is reached again in normal execution flow.

So when you write:

if(!embed_BackgroundColor) {
    var embed_BackgroundColor;
    embed_BackgroundColor = "#F4F4F4";
}

what actually happens is this:

  1. Code is scanned for var declarations. embed_BackgroundColor is declared inside this scope, regardless of whether it was already declared or not. Its initial value is undefined.

  2. Execution of the code begins. The if statement is run. The variable is declared, but its value is undefined, so the condition is true. Using typeof wouldn't help you distinguish here between an undeclared and a declared-but-not-yet-set variable. It makes no difference anyway.

  3. The var declaration is reached by normal flow of the code. If you had given the variable an initial value it would have been set now. In this case nothing happens.

  4. embed_BackgroundColor is set to the value "#F4F4F4".

So, bottom-line is: you can use typeof variable == 'undefined' as seen in the other answers, or even plain '!variable' as you were initially using, but don't use var or that will ruin everything.

isherwood
  • 58,414
  • 16
  • 114
  • 157
Zecc
  • 4,220
  • 19
  • 17
  • Is it really in a state of being declared but evaluates as "undefined"? I thought the whole purpose of undefined was for things that are not declared! (ie. not defined). Do you mean null? – Moss Nov 02 '11 at 04:13
  • @Moss No, it really is `undefined`. It's the default for uninitialized variables in JS (by uninitialized I mean "without a value assigned to them"). Just try it on Firebug or whatever: `typeof blah` will evaluate to the string `'undefined'`. – Zecc Nov 02 '11 at 17:55
13

If it's a global variable, I like doing:

var defineMe = window.defineMe || 'I will define you now';

It's important to use the window namespace since referencing undefined variables will cause very bad errors, but referencing undefined properties will not.

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
user3803037
  • 138
  • 1
  • 4
  • Because the definition `var defineMe` gets hoisted, I don't think you need to use `window.` to access `defineMe`, even if it wasn't defined earlier. However, not that if defineMe is falsey (0, false, "") it will be assigned the default value. To avoid it check `typeof defineMe==='undefined'` instead – danbars Aug 05 '19 at 02:46
10

I prefer this syntax:

embed_BackgroundColor = embed_BackgroundColor || "#F4F4F4"

Can't get much more simple than that! And it seems to work even if it has been var'd.

Moss
  • 3,695
  • 6
  • 40
  • 60
2

Best option:

if (typeof someVar === 'undefined') someVar = someValue;
John Slegers
  • 45,213
  • 22
  • 199
  • 169
SergiWWW
  • 21
  • 2
1

If embed_BackgroundColor is a parameter in a function that didn't get passed, you can set a default with

embed_BackgroundColor ? embedBackgroundColor : embed_BackgroundColor = "#F4F4F4";

Full function example

function colorFunctionThing(embed_BackgroundColor) {
  embed_BackgroundColor ? embed_BackgroundColor : embed_BackgroundColor = "#F4F4F4";
  console.log(embed_BackgroundColor);
};
colorFunctionThing();

Outputs

#F4F4F4

Not exactly what you were looking for but still really good to know.

Mike Grace
  • 16,636
  • 8
  • 59
  • 79
1

As of ES2020 you can now use the nullish coalescing operator ??. This avoids reassigning falsy values to the default value.

var embed_BackgroundColor = embed_BackgroundColor ?? "#F4F4F4"

Note that if you are doing a oneliner like this you need to use var; let and const won't let you do it in one line.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator

Moss
  • 3,695
  • 6
  • 40
  • 60
1

Cleanest way in 2022 ECMA syntax!!

If you want to overwrite "nullish" values (see ref below), assign using let might_exist ||= default or pass value with (might_exist || default). (The parentheses are only there for clarity and to avoid operator precedence problems, delete if you'd rather.)

If you want to keep "nullish" values, assign using let might_exist ??= default or pass value with (might_exist ?? default).

On being nullish: ?? will only overwrite null and undefined, whereas || will also overwrite "nullish" values like '' and 0.

You're all very welcome, it's about time I gave back a lil

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_OR_assignment

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_nullish_assignment

1

As of ES2021 you can use, Logical Assignment Operators that looks like this.

embed_BackgroundColor ||= "#F4F4F4";

This is setup does the same as the following code but is shorter and reduces redundancy.

embed_BackgroundColor = embed_BackgroundColor || "#F4F4F4"

This syntax also works for other logical operators like && and ??.

Nils Kähler
  • 2,645
  • 1
  • 21
  • 26
0

I follow Chris West's blog and saw that he posted a pretty cool way at http://gotochriswest.com/blog/2012/07/02/javascript-define-if-undefined/.

Basically, you have the definition for the define function and then use it like this:

define("embed_BackgroundColor", "#F4F4F4");

The above code will define enbed_BackgroundColor in the global context if it is not already defined. The example that Chris used is a bit more useful and is as follows:

alert("jStuff is " + (typeof jStuff == "undefined" ? "un" : "") + "defined.");

define("jStuff.alert", function(msg) {
  alert(msg);
  return msg;
});

alert("jStuff is " + (typeof jStuff == "undefined" ? "un" : "") + "defined.");

var str = jStuff.alert("Show and save this message.");
  • The first alert statement will display, "jStuff is undefined."
  • The second alert statement will display, "jStuff is defined."
  • The final alert statement will display the specified alert and then that string will be stored in the str variable.
0

Because your if block will execute if embed_BackgroundColor is false, 0, "", null, undefined, or NaN.

But embed_BackgroundColor should not be overwritten if it has already been assigned to another non-empty string... Or at least, it doesn't on my end.

Perhaps it is a case of conflicting scopes, as Aaron Qian has pointed out.

Bella I.
  • 3
  • 1
0

I think your posted code should work. Unless your original value is 0.

The problem is somewhere else.

I'm guessing you defined 'embed_BackgroundColor' out of the scope of your code. And when you run your code, that variable is undefined with in the scope of your code, and will be assigned the default value.

Here is an example:

var embed_BackgroundColor = "#FF0000";

(function(){
  if(!embed_BackgroundColor) {
    var embed_BackgroundColor;
    embed_BackgroundColor = "#F4F4F4";
  }
  alert(embed_BackgroundColor); // will give you #F4F4F4
})();

alert(embed_BackgroundColor); // will give you #FF0000;
Aaron Qian
  • 4,477
  • 2
  • 24
  • 27
0

I prefer a general solution in PHP-like style:

function isset(x) { return typeof(x)!='undefined'; }

Thinker
  • 14,234
  • 9
  • 40
  • 55
  • this won't work. It'll give you a reference error: [x] is not defined. – KooiInc Apr 03 '09 at 07:30
  • It works, but you need to remember, that isset(obj.arr[x]) won't work if you don't check first for isset(obj) and then isset(obj.arr). – Thinker Apr 03 '09 at 13:59
-3
if(embed_BackgroundColor == "" || embed_BackgroundColor == 'undefined' || embed_BackgroundColor == null){
}
  • 1
    While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value. – Piotr Labunski Feb 19 '20 at 12:09