Java script has many falsy values as I started learning. I have a program that gets values from a service and loads into an array like this:
function loadNames() {
Global.names = // what should I use here? undefined, null, "", 0, {} or anything else
var lnames = getLNames(); // this is doing some magic
if ( lnames.length !== 0 ) {
Global.names = new Array();
for ( var i = 0; i < lnames.length; ++i)
Global.names[i] = lnames[i];
}
}
I want to know the right way of resetting Global.names. What is most appropriate here? In code I only want to check like if ( Global.names )
PS: I can't just take the return value into Global.names as the returned object is destroyed later. Hence, I need to do a deep copy
Thanks
Taken from JavaScript: the good parts :
"The if statement changes the flow of the program based on the value of the expression. The then block is executed if the expression is truthy. Here are the falsy values:
false
null
undefined
the empty string ''
the number 0
the number NaN
"
So basically if you set your var to any of those values, you'll be able to do a if(var){...}
I think you should init
GLobal.names = [];
and than just check if Global.names.length != 0.
If you want to reset it just make it an empty array again.
I think you'd be better off to initialize it as an array and test as
if ( Global.names.length )
Also, if you're just storing strings in the array you can simplify the function as
function loadNames() {
Global.names = getLNames().concat();
}
You don't have to initialise it to anything. You can do:
if (!Global.names) Global.names = [];
// add members to Global.names
This can be one in one statement:
Global.names = Global.names : [];
If you want to reset it, then:
Global.names = [];
or
delete Global.names;
Setting it to null is good, as you know that the variable exists but hasn't been assigned a value. This way you can easily see the state - if it's undefined then you've forgotten to declare it, if it's null it has been declared but never assigned a value, and if it's an Array then you can test the length from there.
Related
I have a this._champ object (which is undefined by default).
I browser an array, and want to add this field with a value : this._champ[champ.name][ele.infos[0].StackableRangeName] = ele.value; but at the first iteration, [champ.name] is undefined, and [ele.infos[0].StackableRangeName] is always undefined, how to manage this?
I tried this ternary operator but it isn't working:
this.champ[champ.name] != undefined ? this._champ[champ.name].push({ele.infos[0].StackableRangeName: ele.value}) : this._champ.push({champ.name: {ele.infos[0].StackableRangeName: ele.value}})
This is a common idiom for initializing something with a default value if it's not yet set:
this.champ[champ.name] = this.champ[champ.name] || []
Just check for existence of the key. and then push value:
if(this.champ && !this.champ.hasOwnProperty(champ.name)) {
this.champ[champ.name] = [];
}
this._champ[champ.name].push({ele.infos[0].StackableRangeName: ele.value});
I have an object that I am creating that could potentially have undefined properties.
Is there a more concise way to set the property than what I am doing below:
var ruleObj = {
factor: (ruleArray[2] ? ruleArray[2].trim() : null),
resultElseTarget: (ruleArray[10] ? ruleArray[10].trim() : null)
}
Notice how I have to repeat the variable after the ternary operator twice. The reason I'm asking is that I've run into this same type of problem several times and it doesn't seem like the best way to handle it.
Here’s a function that wraps another function to do nothing on null and undefined values:
const liftMaybe = f => x => x == null ? null : f(x);
Then you can define a trim that does nothing to undefined:
const trimMaybe = liftMaybe(x => x.trim());
and make use of it:
var ruleObj = {
factor: trimMaybe(ruleArray[2]),
resultElseTarget: trimMaybe(ruleArray[10]),
};
It differs from your original in its handling of empty strings, but I don’t know if that was intentional or if it’s even relevant.
Conciseness is one thing but with Javascript the bigger concern is readability and type checking.
In your example, if the value of ruleArray[2] is a boolean then it'd evaluate to false and set factor to null. Maybe that's what you want but just looking at your example code right now, I'd assume your ruleArray contains bools and not potential undefines.
The better way is to write a function to do null check
EDIT: someone was faster than me :) https://stackoverflow.com/a/46436844/643084
EDIT2: the other answer is great but i'd like to just make a note. null should not be treated the same as undefined even though they evaluate the same most of the times.
Some things:
Since you're checking indexes, you'd need to make sure that you have a length of at least the size you want. Otherwise ruleArray[10] can throw you and out of range error.
Assuming you are certain that you have the right number of elements in your array, you can use this to check a var for undefined, this is common to check incoming arguments (say you had something like function ( arg1, arg2 ) ):
arg1 = arg1 || 'some_default';
In your case, again assuming your array is long enough:
factor: ( ruleArray[2] || 'some other default' );
(Why would you set it to null if that's what you are trying to avoid).
If you're wondering, "is there a way to access an index that doesn't exist and just return null", the answer is "maybe...but I wouldn't".
Note, if the value is indeed falsy (say, 0, '', or false), you may not get what you expect, in which case you'd want to check for something more explicit, like null.
I get a lot of use of out the terse "something = thisValIfNotFalsy || someOtherDefaultVal. Like anything though careful when and where, etc.
You could do something like:
var ruleArray = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine']
function formatRule(rule) {
if (!rule) return null
return rule.trim()
}
var ruleObj = {
factor: formatRule(ruleArray[2]),
resultElseTarget: formatRule(ruleArray[10])
}
console.log(ruleObj.factor)
console.log(ruleObj.resultElseTarget)
We created a pure function that is tasked with producing either null or a trimmed value, which avoids duplicating this logic elsewhere.
Is there a more concise way
So far all answers seem to assume your input is either a string or null / undefined. For me I'd say the check for null / undefined is the wrong way round. You can only call trim on a string, so why not check it's a string?. It would also mean NaN / Numbers / Arrays etc, would not error. I'm assuming what your wanting this function to do is trim a string if it's a string, so I would also say you should pass the original value if not a string.
Maybe that's what #zaftcoAgeiha meant when he talking about not treating null & undefined the same.
Anyway, here is an example. Notice how numbers are still passed, but hello gets trimmed.
const ruleArray = [];
ruleArray[2] = null;
ruleArray[5] = 7;
ruleArray[7] = 'Helllo ';
const trimIfString = (x) => typeof x === 'string' ? x.trim() : x;
var ruleObj = {
factor: trimIfString(ruleArray[2]),
resultElseTarget: trimIfString(ruleArray[5]),
hello: trimIfString(ruleArray[7])
}
console.log(ruleObj);
You can use a function pattern and set default parameter with AND && operator when passing the parameter to check if variable is defined, if not set element value to null. You can include further checks to determine if variable is passed is a string.
let ruleArray = [];
ruleArray[10] = "def ";
let ruleFn = (factor = null, resultElseTarget = null) =>
({factor, resultElseTarget});
let ruleObj = ruleFn(ruleArray[2] && ruleArray[2].trim()
, ruleArray[10] && ruleArray[10].trim());
console.log(ruleObj, ruleObj.factor === null);
What is different between two variable one is assigned a value undefined and second one is only declared a var not initiased ?
var a = undefined;
var b;
a === b; // returns true
What is different between two variable a and b?
var ar = new Array(4); // ar = 0[undefined × 4]
ar[0] = null; // ar = [null, undefined × 3]
ar[1] = undefined; // ar = [null, undefined, undefined × 2]
ar.filter(function(item, index, arr){
return item == undefined;
}); // [null, undefined]
I know Array's filter function runs for only initialized index.
How javascript internally check that ar[1] is assigend undefined so run filter for this and ar[2] is unassigned undefined so dont run for this ?
There are three separate issues going on here:
A regular variable that has just been declared, but not assigned a value will report undefined when you read that variable. That is essentially its default value.
You have to be very careful when comparing null with == because you will find that null == undefined is true because of auto-type conversion. So, if you want to filter on only undefined elements, you have to use item === undefined in the filter.
.filter() only iterates elements in the array that have actually been assigned a value. Unlike plain variables, there is a difference between an array element that has assigned a value and one that has never been assigned a value and .filter() knows to skip the ones that have never been assigned a value (the ones that are essentially "sparse").
Here's some more detail on these three issues:
A variable that has been declared, but not explicitly initialized, has a value of undefined. That is its default value.
This, this code is as expected:
var a = undefined;
var b;
a === b; // returns true
Then, in your second code block, if you want to truly test for whether something is undefined, then you need to use ===, not == to avoid any type conversion.
var ar = new Array(4); // ar = 0[undefined × 4]
ar[0] = null; // ar = [null, undefined × 3]
ar[1] = undefined; // ar = [null, undefined, undefined × 2]
var result = ar.filter(function(item, index, arr){
return item === undefined;
});
for (var i = 0; i < result.length; i++) {
document.write(i, ": ", result[i], "<br>");
}
Note: .filter() will skip elements of the array that have not been initialized to have any value, thus they will never even be considered in the .filter() operation. If you try to read their values, you will get undefined, but .filter() knows the difference between a "sparse" array value that has never been assigned anything. It has to do with whether the array key exists or not, not what the value is and thus it is different for array items than it is for plain variables.
From the MDN doc for .filter():
The range of elements processed by filter() is set before the first
invocation of callback. Elements which are appended to the array after
the call to filter() begins will not be visited by callback. If
existing elements of the array are changed, or deleted, their value as
passed to callback will be the value at the time filter() visits them;
elements that are deleted are not visited.
Here's a demonstration of how the array keys do not actually exist until someting is assigned to the array element. This is the information that .filter() uses to know what to iterate and what to skip:
var ar = new Array(4);
ar[1] = "foo";
ar[2] = undefined;
for (var index in ar) {
document.write(index, ": ", ar[index], "<br>"); // 1 foo, 2 undefined
}
Note that indexes 0 and 3 are not iterated with the for loop because those keys do not exist in the array. The array is "sparse". Only some elements actually exist.
I had a code problem when testing if some vars are empty or not, and decide to test it in a fiddle:
Testing null values
var result = "";
var Teste = new Object();
Teste.ObjectNew = new Object();
Teste.StringNew = new String();
Teste.NumberNew = new Number();
Teste.ArrayNew = new Array();
Teste.ObjectLiteral = {};
Teste.StringLiteral = "";
Teste.NumberLiteral = 0;
Teste.ArrayLiteral = [];
Teste.ObjectNull = Object(null);
Teste.StringNull = String(null);
Teste.NumberNull = Number(null);
Teste.ArrayNull = [null];
for (var i in Teste) {
if (Teste[i] == null) {
result += "<p>Type " + i + " is null: " + Teste[i] + "</p>";
} else {
result += "<p>Type " + i + " is not null: " + Teste[i] + "</p>";
}
}
document.getElementById("result").innerHTML = result;
<div id="result"></div>
The result is:
Type ObjectNew is not null: [object Object]
Type StringNew is not null:
Type NumberNew is not null: 0
Type ArrayNew is not null:
Type ObjectLiteral is not null: [object Object]
Type StringLiteral is not null:
Type NumberLiteral is not null: 0
Type ArrayLiteral is not null:
Type ObjectNull is not null: [object Object]
Type StringNull is not null: null
Type NumberNull is not null: 0
Type ArrayNull is not null:
I tested in Safari, same result.
I was coding in php altogether with JS and had problems in adjust my mind. In php, $var = array() returns NULL, but in JavaScript it seams there is never null value at any type. In EcmaScript definition, null is "primitive value that represents the intentional absence of any object value", but it seams impossible in JavaScript at list by my tests, excluding the case of v = null that i think is a Null type of var.
In addition, I believe AS3 follow the ecmascript concept by split type of for from it's values, the var statement "build" a var as an object apart from values.
So how do we correctly refer to a null value, if there is a way to?
EDIT
I did this test when I had this situation: I created a variable that has the relative directory of a graphic library. If this variable is null, it means I don't wish to change it from the default value (I have a table with default values) during initializing phase of my software, so the system just add the proper http base for the directory. If the variable is not null, it will assume the value was just assigned to it. But if it is an empty space, it means the directory is the root, but will be taken as null, generating an error.
Dinamyc:
var dir = new String(); // should be null
// initializing
dir = ""; // the directory will be the root
// finish ini
if(dir==null) … // assume the default value, but this doesn't work, so how can I know?
In EcmaScript definition, null is "primitive value that represents the intentional absence of any object value", but it seams impossible in JavaScript at list by my tests, excluding the case of v = null that i think is a Null type of var.
Well, all the test cases in your test had a value. I'm not sure why you did exclude
Teste.Null = null;
but it would have worked for it. Also, a Teste.Undefined = undefined would be compare as equal to null.
var result = "";
var Teste = {
Null: null,
Undefined: undefined,
ObjectNew: new Object(),
StringNew: new String(),
NumberNew: new Number(),
ArrayNew: new Array(),
ObjectLiteral: {},
StringLiteral: "",
NumberLiteral: 0,
ArrayLiteral: [],
ObjectNull: Object(null),
StringNull: String(null),
NumberNull: Number(null),
ArrayNull: [null]
}
for (var i in Teste) {
result += "<p>Type "+i+" is"+(Teste[i] == null?"":" not")+" null: "+Teste[i]+"</p>";
}
document.getElementById("result").innerHTML = result;
<div id="result"></div>
So how do we correctly refer to a null value, if there is a way to?
Use the value null. Don't wrap it in anything, or you'd get a wrapper around it (e.g. your array [null]).
If you want to test arrays ([]) or strings ("") for their emptyness (which is a different concept than non-existance of the value), you should check for their .length to be 0.
var dir = new String(); // should be null
No. You've created a Wrapper object (which you never should need) around an empty string here (which you don't seem to want). To declare a variable, but not initialise it, just use
var dir;
or
var dir = null;
and then they will have the value undefined or null, which both are == null in your if-condition.
In JavaScript, null is a special value an object (yes, object - the type of null is object) can have that represents it having no value - this is distinct from it being empty. You can think of {} (empty object) as an empty glass, while null would mean that the glass doesn't even exist. It's also distinct from the variable not being defined at all - when a variable is defined, but set to null, it has a place "reserved" to put the glass (or possibly something else) at some point, but right now that space is not occupied.
As for your test, comparing with either '', 0 or false will give you the is null messages (only when using == and not === for comparison of course). If that's what you're trying to achieve, probably the "proper" (easiest to understand) way to check if a variable has zero or empty value (similar to PHP's empty) is if (!variable) ...
==== edit ====
ok, my bad, undefined means its unitialized, and null means it points to nothing, has no value.
http://www.2ality.com/2013/10/typeof-null.html
==== /edit ====
there are no such thing as null-string, or null-type. null has no type, it means the variable is not initialized, in other words the variable points to nowhere. any kind of uninitialized variable is null.
like pointers in c++. a pointer can point to any type, but if its uninitialized it points to a quasi random place in memory.
SomeType* myVar;
its not null, if you use this object you mess things up big time and you have no way to tell if its a valid pointer, or not.
SomeType* myVar = 0;
this way you can tell that this is an uninitialized pointer by simply check if its 0 or not.
in higher level languages you don't have to deal with these issues directly so
var something:AnyObjectType;
is automatically null, a.k.a. uninitialized.
to test whether a string or an array is empty or not is an other question.
in php $var = array(); if($var) evaluates to true, since its an actual object, not null. empty($var) would be the check you use to see if the array actually has any content.
in js this would be if(myArray && myArray.length) to see if its a living object and to see if it has content.
strings could be more tricky, since a string with only whitespace in it is a completely valid object with actual content, yet you would consider it empty in most use-cases.
If we have an array that does not exists and we check the value of the array it gives me an error. "variable is not defined"
for example I have:
var arr = new Array();
arr['house']['rooms'] = 2;
and I use
if ( typeof arr['plane']['room'] != 'undefined' ) )
it says arr['plane'] not defined...
I don't want to use this:
if ( typeof arr['plane'] != 'undefined' ) ) {
if ( typeof arr['plane']['room'] != 'undefined' ) {
}
}
In php I use isset that works nice for me, I searched a lot on google to find the answer but I can't...
The thing to realize is that there are no multi-dimensional arrays in javascript. It is easy to make an array element contain an array, and work with that, but then all references you make have to use that consideration.
So, you can do
arr = []; // or more appropriately {}, but I'll get to that soon
arr['house'] = [];
arr['house']['rooms'] = 2;
But doing
arr['house']['rooms'] = 2;
should give you an error unless you've already defined arr and arr['house'].
If you've defined arr but not arr['house'], it's valid syntax to reference arr['house'] - but the return value will (appropriately) be undefined.
And this is where you're at when you're looking at arr['plane']['room']. arr is defined, so that's ok, but arr['plane'] returns undefined, and referencing undefined.['room'] throws an error.
If you want to avoid the errors and have multiple levels of reference, you're going to have to make sure that all the levels but the lowest exist.
You're stuck with if (arr && arr['plane'] && arr['plane']['room']).
Or perhaps if (arr && arr['plane'] && room in arr['plane'] would be more accurate, depending on your needs. The first will check if arr['plane']['room'] has a truthy value, while the second will check if arr['plane']['room'] exists at all (and could have a falsey value).
Arrays vs objects
Arrays and objects are very similar and can both be accessed with [] notation, so it's slightly confusing, but technically, you're using the object aspect of the array for what you're doing. Remember, all arrays (and everything other than primitives - numbers, strings and booleans) are objects, so arrays can do everything objects can do, plus more. But arrays only work with numeric indices, i.e. arr[1][2]. When you reference an array with a string, you're attempting to access the member of the underlying object that matches that string.
But still in this case, it doesn't matter. There are no multi-dimensional arrays - or objects.
The [] notation with objects is simply a way to check for members of objects using a variable. arr['plane']['rooms'] is actually equivalent to arr.plane.rooms. but perhaps the arr.plane.room notation will help make it more clear why you have to first check arr.plane (and arr).
Use the following if you want to test for existence in an object:
if ( 'plane' in arr && 'room' in arr.plane ) {
// Do something
}
That's not an array, but an object, aka associative array. You can declare it like this:
var aarr = { house: { rooms: 2 } };
Now you can do:
if (aarr.house && aarr.house.rooms) {/* do stuff */ }
or uglier, but shorter:
if ((aarr.house || {}).rooms) {/* do stuff */ }
See also...
To more generally traverse an object to find a path in it you could use:
Object.tryPath = function(obj,path) {
path = path.split(/[.,]/);
while (path.length && obj) {
obj = obj[path.shift()];
}
return obj || null;
};
Object.tryPath(aarr,'house.rooms'); //=> 2
Object.tryPath(aarr,'house.cellar.cupboard.shelf3'); //=> null
JsFiddle