Cannot Read Property 'get' of Undefined Angular 2
Most of the mod languages similar Ruby, Python, or Java accept a single null value (nil
or null
), which seems a reasonable approach.
But JavaScript is different.
null
, but also undefined
, represent in JavaScript empty values. So what'southward the exact difference between them?
The brusk answer is that JavaScript interpreter returns undefined
when accessing a variable or object holding that is not nevertheless initialized. For example:
javascript
let visitor ;
visitor ; // => undefined
let person = { name: 'John Smith' };
person . age ; // => undefined
On the other side, cypher
represents a missing object reference. JavaScript doesn't initialize variables or object properties with null
.
Some native methods like Cord.prototype.match()
can render zippo
to denote a missing object. Take a await at the sample:
javascript
allow array = null ;
array ; // => null
let picture = { name: 'Starship Troopers' , musicBy: null };
movie . musicBy ; // => null
'abc' . match ( / [ 0-9 ] / ); // => zero
Because JavaScript is permissive, developers have the temptation to access uninitialized values. I'1000 guilty of such bad practise likewise.
Frequently such risky actions generate undefined
related errors:
-
TypeError: 'undefined' is not a role
-
TypeError: Cannot read belongings '<prop-name>' of undefined
- and alike type errors.
JavaScript developer can understand the irony of this joke:
javascript
function undefined () {
// trouble solved
}
To reduce such errors, yous have to understand the cases when undefined
is generated. Permit's explore undefined
and its effect on code safety.
Table of Contents
- 1. What is undefined
- 2. Scenarios that create undefined
- 2.one Uninitialized variable
- two.two Accessing a not-existing property
- 2.iii Function parameters
- two.4 Function return value
- 2.5 void operator
- 3. undefined in arrays
- 4. Departure between undefined and null
- 5. Decision
1. What is undefined
JavaScript has 6 primitive types:
- Boolean:
truthful
orfalse
- Number:
ane
,6.7
,0xFF
- String:
"Gorilla and banana"
- Symbol:
Symbol("name")
(starting ES2015) - Null:
null
- Undefined:
undefined
.
And a separated object type: {proper noun: "Dmitri"}
, ["apple", "orange"]
.
From 6 archaic types undefined
is a special value with its own blazon Undefined. According to ECMAScript specification:
Undefined value primitive value is used when a variable has non been assigned a value.
The standard conspicuously defines that you lot will receive undefined
when accessing uninitialized variables, non-existing object properties, non-existing array elements, and alike.
A few examples:
javascript
let number ;
number ; // => undefined
allow film = { proper name: 'Interstellar' };
movie . twelvemonth ; // => undefined
let movies = [ 'Interstellar' , 'Alexander' ];
movies [ three ]; // => undefined
The to a higher place instance demonstrates that accessing:
- an uninitialized variable
number
- a non-existing object property
moving picture.year
- or a non-existing array element
movies[iii]
are evaluated to undefined
.
The ECMAScript specification defines the blazon of undefined
value:
Undefined type is a blazon whose sole value is the
undefined
value.
In this sense, typeof
operator returns 'undefined'
string for an undefined
value:
javascript
typeof undefined === 'undefined' ; // => true
Of course typeof
works nicely to verify whether a variable contains an undefined
value:
javascript
let zilch ;
typeof cypher === 'undefined' ; // => true
two. Scenarios that create undefined
2.i Uninitialized variable
A declared variable but not nonetheless assigned with a value (uninitialized) is by default
undefined
.
Plain and uncomplicated:
javascript
permit myVariable ;
myVariable ; // => undefined
myVariable
is declared and not yet assigned with a value. Accessing the variable evaluates to undefined
.
An efficient approach to solve the troubles of uninitialized variables is whenever possible assign an initial value. The less the variable exists in an uninitialized state, the ameliorate.
Ideally, you would assign a value right away after declaration const myVariable = 'Initial value'
. Merely that's not ever possible.
Tip one: Favor const
, otherwise use let
, but say goodbye to var
In my opinion, one of the all-time features of ECMAScript 2015 is the new style to declare variables using const
and let
. It is a big step forward.
const
and let
are cake scoped (reverse to older function scoped var
) and exist in a temporal dead zone until the declaration line.
I recommend const
variable when its value is not going to change. Information technology creates an immutable binding.
One of the overnice features of const
is that you must assign an initial value to the variable const myVariable = 'initial'
. The variable is not exposed to the uninitialized country and accessing undefined
is impossible.
Allow's check the function that verifies whether a word is a palindrome:
javascript
part isPalindrome ( discussion ) {
const length = discussion . length ;
const half = Math . flooring ( length / ii );
for ( let index = 0 ; index < one-half ; index ++) {
if ( word [ index ] !== word [ length - index - 1 ]) {
return false ;
}
}
return true ;
}
isPalindrome ( 'madam' ); // => true
isPalindrome ( 'hello' ); // => false
length
and half
variables are assigned with a value one time. It seems reasonable to declare them equally const
since these variables aren't going to change.
Apply allow
annunciation for variables whose value can change. Whenever possible assign an initial value right abroad, eastward.g. permit index = 0
.
What about the erstwhile school var
? My suggestion is to stop using it.
var
declaration problem is the variable hoisting within the part telescopic. You tin can declare a var
variable somewhere at the stop of the part scope, but still, you can access it before annunciation: and y'all'll go an undefined
.
javascript
function bigFunction () {
// code...
myVariable ; // => undefined
// code...
var myVariable = 'Initial value' ;
// code...
myVariable ; // => 'Initial value'
}
bigFunction ();
myVariable
is accessible and contains undefined
even before the proclamation line: var myVariable = 'Initial value'
.
Contrary, a const
or let
variable cannot be accessed earlier the annunciation line — the variable is in a temporal dead zone before the annunciation. And that's nice because you take less run a risk to access an undefined
.
The to a higher place instance updated with allow
(instead of var
) throws a ReferenceError
because the variable in the temporal dead zone is not accessible.
javascript
function bigFunction () {
// code...
myVariable ; // => Throws 'ReferenceError: myVariable is not defined'
// code...
permit myVariable = 'Initial value' ;
// lawmaking...
myVariable ; // => 'Initial value'
}
bigFunction ();
Encouraging the usage of const
for immutable bindings or allow
otherwise ensures a exercise that reduces the advent of the uninitialized variable.
Tip 2: Increase cohesion
Cohesion characterizes the degree to which the elements of a module (namespace, class, method, block of code) vest together. The cohesion can exist high or low.
A high cohesion module is preferable because the elements of such a module focus solely on a single chore. It makes the module:
- Focused and understandable: easier to empathize what the module does
- Maintainable and easier to refactor: the change in the module affects fewer modules
- Reusable: being focused on a single task, it makes the module easier to reuse
- Testable: you would easier test a module that's focused on a unmarried task
High cohesion accompanied past loose coupling is the characteristic of a well-designed system.
A code block can be considered a pocket-size module. To profit from the benefits of loftier cohesion, keep the variables as shut as possible to the code block that uses them.
For example, if a variable solely exists to form the logic of cake scope, so declare and brand the variable alive only within that cake (using const
or let
declarations). Practice not expose this variable to the outer block scope, since the outer block shouldn't care about this variable.
I classic instance of the unnecessarily extended life of variables is the usage of for
bike within a role:
javascript
role someFunc ( array ) {
var index , particular , length = array . length ;
// some code...
// some lawmaking...
for ( index = 0 ; alphabetize < length ; index ++) {
item = assortment [ index ];
// some lawmaking...
}
render 'some outcome' ;
}
index
, item
and length
variables are declared at the first of the function body. However, they are used but near the finish. What's the problem with this approach?
Between the announcement at the top and the usage in for
argument the variables alphabetize
, particular
are uninitialized and exposed to undefined
. They accept an unreasonably long lifecycle in the unabridged function scope.
A better approach is to move these variables as close as possible to their usage place:
javascript
function someFunc ( assortment ) {
// some code...
// some code...
const length = array . length ;
for ( let index = 0 ; index < length ; alphabetize ++) {
const item = array [ index ];
// some
}
return 'some result' ;
}
index
and item
variables exist only in the block scope of for
statement. They don't have whatsoever meaning outside of for
.
length
variable is declared shut to the source of its usage too.
Why is the modified version better than the initial i? Permit'southward encounter:
- The variables are not exposed to uninitialized state, thus you accept no risk of accessing
undefined
- Moving the variables as close as possible to their usage identify increases the code readability
- Loftier cohesive chunks of code are easier to refactor and extract into separate functions, if necessary
2.two Accessing a non-existing property
When accessing a non-existing object property, JavaScript returns
undefined
.
Let'south demonstrate that in an example:
javascript
permit favoriteMovie = {
championship: 'Blade Runner'
};
favoriteMovie . actors ; // => undefined
favoriteMovie
is an object with a unmarried belongings title
. Accessing a non-existing holding actors
using a property accessor favoriteMovie.actors
evaluates to undefined
.
Accessing a not-existing holding does not throw an error. The problem appears when trying to get data from the non-existing property, which is the most mutual undefined
trap, reflected in the well-known mistake bulletin TypeError: Cannot read property <prop> of undefined
.
Let's slightly alter the previous code snippet to illustrate a TypeError
throw:
javascript
let favoriteMovie = {
title: 'Bract Runner'
};
favoriteMovie . actors [ 0 ];
// TypeError: Cannot read property '0' of undefined
favoriteMovie
does not take the property actors
, so favoriteMovie.actors
evaluates to undefined
.
Equally a result, accessing the first item of an undefined
value using the expression favoriteMovie.actors[0]
throws a TypeError
.
The permissive nature of JavaScript that allows accessing non-existing properties is a source of nondeterminism: the property may be set or not. The good manner to bypass this problem is to restrict the object to have always defined the properties that it holds.
Unfortunately, often you lot don't have command over the objects. Such objects may accept a different fix of properties in diverse scenarios. So y'all take to handle all these scenarios manually.
Let'south implement a office suspend(array, toAppend)
that adds at the beginning and/or at the cease of an array of new elements. toAppend
parameter accepts an object with properties:
-
first
: element inserted at the beginning ofassortment
-
last
: element inserted at the finish ofarray
.
The office returns a new array instance, without altering the original array.
The first version of append()
, a scrap naive, may look similar this:
javascript
function suspend ( assortment , toAppend ) {
const arrayCopy = [... array ];
if ( toAppend . offset ) {
arrayCopy . unshift ( toAppend . first );
}
if ( toAppend . concluding ) {
arrayCopy . push ( toAppend . concluding );
}
return arrayCopy ;
}
append ([ 2 , 3 , four ], { showtime: 1 , last: 5 }); // => [1, ii, three, 4, v]
suspend ([ 'Hullo' ], { last: 'World' }); // => ['Howdy', 'World']
suspend ([ 8 , 16 ], { first: 4 }); // => [four, 8, 16]
Considering toAppend
object can omit starting time
or final
properties, information technology is obligatory to verify whether these properties exist in toAppend
.
A holding accessor evaluates to undefined
if the belongings does not be. The outset temptation to check whether get-go
or last
backdrop are present is to verify them against undefined
. This is performed in conditionals if(toAppend.start){}
and if(toAppend.concluding){}
...
Not so fast. This arroyo has a drawback. undefined
, as well as false
, zip
, 0
, NaN
and ''
are falsy values.
In the current implementation of append()
, the office doesn't allow to insert falsy elements:
javascript
suspend ([ x ], { starting time: 0 , last: fake }); // => [10]
0
and false
are falsy. Considering if(toAppend.kickoff){}
and if(toAppend.last){}
actually compare confronting falsy, these elements are non inserted into the array. The role returns the initial array [10]
without modifications, instead of the expected [0, 10, false]
.
The tips that follow explicate how to correctly check the property'south beingness.
Tip 3: Check the property existence
Fortunately, JavaScript offers a bunch of ways to determine if the object has a specific holding:
-
obj.prop !== undefined
: compare againstundefined
directly -
typeof obj.prop !== 'undefined'
: verify the property value type -
obj.hasOwnProperty('prop')
: verify whether the object has an own property -
'prop' in obj
: verify whether the object has an ain or inherited property
My recommendation is to use in
operator. It has a curt and sweet syntax. in
operator presence suggests a articulate intent of checking whether an object has a specific property, without accessing the actual belongings value.
obj.hasOwnProperty('prop')
is a dainty solution also. It's slightly longer than in
operator and verifies only in the object's own properties.
Let's improve append(array, toAppend)
function using in
operator:
javascript
office append ( array , toAppend ) {
const arrayCopy = array . slice ();
if ( 'kickoff' in toAppend ) {
arrayCopy . unshift ( toAppend . first );
}
if ( 'terminal' in toAppend ) {
arrayCopy . push button ( toAppend . final );
}
return arrayCopy ;
}
append ([ ii , 3 , iv ], { showtime: 1 , last: v }); // => [i, ii, 3, 4, 5]
append ([ 10 ], { first: 0 , last: false }); // => [0, x, simulated]
'first' in toAppend
(and 'last' in toAppend
) is true
whether the corresponding belongings exists, faux
otherwise.
in
operator fixes the problem with inserting falsy elements 0
and false
. Now, adding these elements at the offset and the end of [10]
produces the expected result [0, 10, imitation]
.
Tip iv: Destructuring to access object properties
When accessing an object property, sometimes information technology's necessary to set a default value if the property does not exist.
You might use in
accompanied with ternary operator to accomplish that:
javascript
const object = { };
const prop = 'prop' in object ? object . prop : 'default' ;
prop ; // => 'default'
Ternary operator syntax becomes daunting when the number of backdrop to check increases. For each holding, you lot have to create a new line of code to handle the defaults, increasing an ugly wall of similar-looking ternary operators.
To use a more than elegant approach, allow's get familiar with a great ES2015 feature called object destructuring.
Object destructuring allows inline extraction of object property values straight into variables and setting a default value if the property does not exist. A convenient syntax to avoid dealing directly with undefined
.
Indeed, the property extraction is now precise:
javascript
const object = { };
const { prop = 'default' } = object ;
prop ; // => 'default'
To run into things in activity, let's define a useful function that wraps a string in quotes.
quote(subject field, config)
accepts the kickoff argument equally the string to be wrapped. The second argument config
is an object with the properties:
-
char
: the quote char, e.one thousand.'
(unmarried quote) or"
(double quote). Defaults to"
. -
skipIfQuoted
: the boolean value to skip quoting if the cord is already quoted. Defaults totrue
.
Applying the benefits of the object destructuring, permit's implement quote()
:
javascript
function quote ( str , config ) {
const { char = '"' , skipIfQuoted = true } = config ;
const length = str . length ;
if ( skipIfQuoted
&& str [ 0 ] === char
&& str [ length - 1 ] === char ) {
render str ;
}
render char + str + char ;
}
quote ( 'Hello Globe' , { char: '*' }); // => '*Hello Earth*'
quote ( '"Welcome"' , { skipIfQuoted: truthful }); // => '"Welcome"'
const { char = '"', skipIfQuoted = true } = config
destructuring consignment in one line extracts the properties char
and skipIfQuoted
from config
object.
If some properties are missing in the config
object, the destructuring assignment sets the default values: '"'
for char
and false
for skipIfQuoted
.
Fortunately, the function still has room for comeback.
Let'due south motion the destructuring assignment into the parameters section. And ready a default value (an empty object { }
) for the config
parameter, to skip the second statement when default settings are enough.
javascript
function quote ( str , { char = '"' , skipIfQuoted = true } = {}) {
const length = str . length ;
if ( skipIfQuoted
&& str [ 0 ] === char
&& str [ length - 1 ] === char ) {
return str ;
}
return char + str + char ;
}
quote ( 'Hello World' , { char: '*' }); // => '*Hello World*'
quote ( 'Sunny day' ); // => '"Sunny day"'
The destructuring assignment replaces the config
parameter in the function'south signature. I like that: quote()
becomes one line shorter.
= {}
on the correct side of the destructuring assignment ensures that an empty object is used if the 2nd argument is not specified at all quote('Sunny twenty-four hour period')
.
Object destructuring is a powerful characteristic that handles efficiently the extraction of backdrop from objects. I similar the possibility to specify a default value to be returned when the accessed property doesn't be. As a effect, you avoid undefined
and the hassle around it.
Tip 5: Fill the object with default properties
If there is no need to create variables for every property, as the destructuring assignment does, the object that misses some properties tin can exist filled with default values.
The ES2015 Object.assign(target, source1, source2, ...)
copies the values of all enumerable own properties from one or more source objects into the target object. The function returns the target object.
For instance, you demand to access the properties of unsafeOptions
object that doesn't ever incorporate its full gear up of properties.
To avert undefined
when accessing a not-existing belongings from unsafeOptions
, let'due south make some adjustments:
- Define an object
defaults
that holds the default property values - Call
Object.assign({ }, defaults, unsafeOptions)
to build a new objectoptions
. The new object receives all properties fromunsafeOptions
, but the missing ones are taken fromdefaults
.
javascript
const unsafeOptions = {
fontSize: 18
};
const defaults = {
fontSize: xvi ,
color: 'blackness'
};
const options = Object . assign ({}, defaults , unsafeOptions );
options . fontSize ; // => xviii
options . color ; // => 'black'
unsafeOptions
contains only fontSize
property. defaults
object defines the default values for backdrop fontSize
and color
.
Object.assign()
takes the first statement every bit a target object {}
. The target object receives the value of fontSize
property from unsafeOptions
source object. And the value of color
property from defaults
source object, considering unsafeOptions
doesn't contain color
.
The order in which the source objects are enumerated does matter: afterwards source object properties overwrite before ones.
Yous are now prophylactic to access any property of options
object, including options.colour
that wasn't available in unsafeOptions
initially.
Fortunately, an easier alternative to fill the object with default backdrop exists. I recommend to utilize the spread backdrop in object initializers.
Instead of Object.assign()
invocation, use the object spread syntax to copy into target object all ain and enumerable properties from source objects:
javascript
const unsafeOptions = {
fontSize: 18
};
const defaults = {
fontSize: 16 ,
color: 'blackness'
};
const options = {
... defaults ,
... unsafeOptions
};
options . fontSize ; // => xviii
options . colour ; // => 'blackness'
The object initializer spreads properties from defaults
and unsafeOptions
source objects. The order in which the source objects are specified is important: later source object backdrop overwrite earlier ones.
Filling an incomplete object with default property values is an efficient strategy to brand your code safety and durable. No affair the situation, the object always contains the full set of properties: and undefined
cannot exist generated.
Bonus tip: nullish coalescing
The operator nullish coalescing evaluates to a default value when its operand is undefined
or nada
:
javascript
const value = nullOrUndefinedValue ?? defaultValue ;
Nullish coalescing operator is convenient to admission an object holding while having a default value when this belongings is undefined
or zero
:
javascript
const styles = {
fontSize: xviii
};
styles . color ?? 'black' ; // => 'black'
styles . fontSize ?? 16 ; // => eighteen
styles
object doesn't take the belongings color
, thus styles.color
property accessor is undefined
. styles.color ?? 'black'
evaluates to the default value 'black'
.
styles.fontSize
is 18
, so the nullish coalescing operator evaluates to the belongings value xviii
.
2.iii Function parameters
The function parameters implicitly default to
undefined
.
Ordinarily a function defined with a specific number of parameters should be invoked with the aforementioned number of arguments. That'due south when the parameters get the values you await:
javascript
function multiply ( a , b ) {
a ; // => 5
b ; // => iii
return a * b ;
}
multiply ( 5 , 3 ); // => 15
When multiply(5, 3)
, the parameters a
and b
receive 5
and respectively iii
values. The multiplication is calculated as expected: 5 * 3 = fifteen
.
What does happen when you omit an argument on invocation? The corresponding parameter inside the function becomes undefined
.
Permit'southward slightly modify the previous example past calling the function with just one argument:
javascript
function multiply ( a , b ) {
a ; // => 5
b ; // => undefined
return a * b ;
}
multiply ( five ); // => NaN
The invocation multiply(5)
is performed with a single argument: every bit event a
parameter is 5
, only the b
parameter is undefined
.
Tip vi: Use default parameter value
Sometimes a office does not require the full set of arguments on invocation. You can set defaults for parameters that don't have a value.
Recalling the previous example, let'southward brand an comeback. If b
parameter is undefined
, let default it to ii
:
javascript
function multiply ( a , b ) {
if ( b === undefined ) {
b = two ;
}
a ; // => 5
b ; // => 2
render a * b ;
}
multiply ( 5 ); // => 10
The function is invoked with a single argument multiply(5)
. Initially, a
parameter is two
and b
is undefined
.
The conditional argument verifies whether b
is undefined
. If it happens, b = 2
assignment sets a default value.
While the provided way to assign default values works, I don't recommend comparing directly against undefined
. It's verbose and looks similar a hack.
A better approach is to use the ES2015 default parameters feature. It's short, expressive and no direct comparisons with undefined
.
Adding a default value to parameter b = 2
looks amend:
javascript
function multiply ( a , b = 2 ) {
a ; // => five
b ; // => 2
render a * b ;
}
multiply ( five ); // => 10
multiply ( 5 , undefined ); // => 10
b = 2
in the function signature makes sure that if b
is undefined
, the parameter defaults to 2
.
ES2015 default parameters feature is intuitive and expressive. E'er use information technology to set up default values for optional parameters.
two.four Office return value
Implicitly, without
render
statement, a JavaScript function returnsundefined
.
A function that doesn't take return
statement implicitly returns undefined
:
javascript
function square ( 10 ) {
const res = x * x ;
}
foursquare ( two ); // => undefined
square()
office does not render whatsoever ciphering results. The function invocation result is undefined
.
The aforementioned situation happens when render
statement is present, just without an expression nearby:
javascript
function foursquare ( x ) {
const res = 10 * x ;
render ;
}
foursquare ( 2 ); // => undefined
return;
argument is executed, but it doesn't return whatsoever expression. The invocation result is too undefined
.
Of course, indicating nearly render
the expression to be returned works as expected:
javascript
function square ( ten ) {
const res = x * x ;
render res ;
}
square ( 2 ); // => iv
Now the function invocation is evaluated to 4
, which is 2
squared.
Tip 7: Don't trust the automated semicolon insertion
The following list of statements in JavaScript must end with semicolons (;
):
- empty statement
-
let
,const
,var
,import
,export
declarations - expression argument
-
debugger
statement -
keep
statement,break
statement -
throw
statement -
return
statement
If y'all employ 1 of the to a higher place statements, exist sure to betoken a semicolon at the cease:
javascript
office getNum () {
// Discover the semicolons at the end
let num = 1 ;
return num ;
}
getNum (); // => ane
At the stop of both let
declaration and render
statement an obligatory semicolon is written.
What happens when you don't desire to indicate these semicolons? In such a state of affairs ECMAScript provides an Automatic Semicolon Insertion (ASI) mechanism, which inserts for you the missing semicolons.
Helped past ASI, y'all can remove the semicolons from the previous example:
javascript
office getNum () {
// Notice that semicolons are missing
let num = 1
return num
}
getNum () // => i
The above text is a valid JavaScript code. The missing semicolons are automatically inserted for y'all.
At first sight, it looks pretty promising. ASI mechanism lets you skip the unnecessary semicolons. Y'all can make the JavaScript lawmaking smaller and easier to read.
In that location is one small, simply annoying trap created by ASI. When a newline stands betwixt return
and the returned expression return \n expression
, ASI automatically inserts a semicolon before the newline return; \northward expression
.
What information technology does hateful inside a office to have return;
statement? The function returns undefined
. If you don't know in detail the mechanism of ASI, the unexpectedly returned undefined
is misleading.
For instance, let'south written report the returned value of getPrimeNumbers()
invocation:
javascript
office getPrimeNumbers () {
return
[ ii , iii , 5 , 7 , eleven , 13 , 17 ]
}
getPrimeNumbers () // => undefined
Between return
statement and the array literal expression exists a new line. JavaScript automatically inserts a semicolon after return
, interpreting the code as follows:
javascript
function getPrimeNumbers () {
return ;
[ 2 , three , v , 7 , 11 , 13 , 17 ];
}
getPrimeNumbers (); // => undefined
The statement return;
makes the function getPrimeNumbers()
to return undefined
instead of the expected array.
The problem is solved by removing the newline between render
and array literal:
javascript
function getPrimeNumbers () {
return [
2 , three , 5 , 7 , 11 , 13 , 17
];
}
getPrimeNumbers (); // => [2, three, five, vii, eleven, 13, 17]
My recommendation is to report how exactly Automatic Semicolon Insertion works to avoid such situations.
Of course, never put a newline between return
and the returned expression.
2.5 void operator
void <expression>
evaluates the expression and returns undefined
no thing the outcome of the evaluation.
javascript
void 1 ; // => undefined
void ( false ); // => undefined
void {name: 'John Smith' }; // => undefined
void Math . min ( 1 , 3 ); // => undefined
Ane use case of void
operator is to suppress expression evaluation to undefined
, relying on some side-effect of the evaluation.
three. undefined in arrays
You become undefined
when accessing an array element with an out of bounds alphabetize.
javascript
const colors = [ 'blue' , 'white' , 'red' ];
colors [ v ]; // => undefined
colors [- one ]; // => undefined
colors
array has 3 elements, thus valid indexes are 0
, ane
, and ii
.
Because there are no assortment elements at indexes 5
and -1
, the accessors colors[5]
and colors[-1]
are undefined
.
In JavaScript, you might encounter and so-called sparse arrays. Theses are arrays that accept gaps, i.e. at some indexes, no elements are defined.
When a gap (aka empty slot) is accessed inside a sparse array, you also get an undefined
.
The following example generates sparse arrays and tries to access their empty slots:
javascript
const sparse1 = new Array ( 3 );
sparse1 ; // => [<empty slot>, <empty slot>, <empty slot>]
sparse1 [ 0 ]; // => undefined
sparse1 [ 1 ]; // => undefined
const sparse2 = [ 'white' , , 'blue' ]
sparse2 ; // => ['white', <empty slot>, 'bluish']
sparse2 [ i ]; // => undefined
sparse1
is created by invoking an Array
constructor with a numeric start statement. Information technology has 3 empty slots.
sparse2
is created with an array literal with the missing second element.
In whatever of these sparse arrays accessing an empty slot evaluates to undefined
.
When working with arrays, to avert undefined
, be certain to apply valid array indexes and forbid the creation of sparse arrays.
4. Divergence between undefined and zip
What is the master difference between undefined
and aught
? Both special values imply an empty state.
undefined
represents the value of a variable that hasn't been nonetheless initialized, whileaught
represents an intentional absence of an object.
Let's explore the divergence in some examples.
The variable number
is defined, however, is not assigned with an initial value:
javascript
allow number ;
number ; // => undefined
number
variable is undefined
, which indicates an uninitialized variable.
The same uninitialized concept happens when a not-existing object property is accessed:
javascript
const obj = { firstName: 'Dmitri' };
obj . lastName ; // => undefined
Because lastName
property does not be in obj
, JavaScript evaluates obj.lastName
to undefined
.
On the other side, you know that a variable expects an object. But for some reason, y'all tin't instantiate the object. In such case null
is a meaningful indicator of a missing object.
For example, clone()
is a office that clones a plain JavaScript object. The office is expected to return an object:
javascript
function clone ( obj ) {
if ( typeof obj === 'object' && obj !== null ) {
return Object . assign ({}, obj );
}
render null ;
}
clone ({ name: 'John' }); // => {name: 'John'}
clone ( 15 ); // => null
clone ( cipher ); // => null
However clone()
might be invoked with a non-object argument: 15
or null
. In such a example, the function cannot create a clone, so information technology returns null
— the indicator of a missing object.
typeof
operator makes the distinction between undefined
and null
:
javascript
typeof undefined ; // => 'undefined'
typeof cipher ; // => 'object'
As well the strict quality operator ===
correctly differentiates undefined
from naught
:
javascript
let nothing = undefined ;
permit missingObject = zippo ;
nothing === missingObject ; // => false
five. Conclusion
undefined
being is a consequence of JavaScript's permissive nature that allows the usage of:
- uninitialized variables
- non-existing object properties or methods
- out of bounds indexes to admission array elements
- the invocation effect of a function that returns nil
Comparing directly against undefined
is unsafe because you rely on a permitted but discouraged do mentioned higher up.
An efficient strategy is to reduce at minimum the appearance of undefined
keyword in your lawmaking past applying practiced habits such as:
- reduce the usage of uninitialized variables
- make the variables lifecycle short and close to the source of their usage
- whenever possible assign initial values to variables
- favor
const
, otherwise applypermit
- employ default values for insignificant office parameters
- verify the properties existence or fill up the unsafe objects with default properties
- avoid the usage of sparse arrays
Is it good that JavaScript has both undefined
and nada
to stand for empty values?
Source: https://dmitripavlutin.com/7-tips-to-handle-undefined-in-javascript/