Remember backticks support new lines and inline variables..
const myVar = "foo";
const backTicks =
`Backticks support new lines.
And inline variables: ${myVar}`;
null
and undefined
null
represents that some value is missing intentionallyundefined
represents that a value is missing unintentionallynull
is not a reference to a non-existing object or a null pointer. The code below represents that name is unknown for whatever reason:
let myName = null;
undefined
means a value is not assigned. If a variable is declared but not assigned a value, it is undefined
.
let myName; // undefined
You should never explicitly set a variable to be undefined
. The literal undefined
value is provided mainly for comparison, to help formalize the difference between an empty object pointer, null
and an uninitialized variable.
let typeOfVar;
// both return strings
typeOfVar = typeof var // using as an operator
typeOfVar = typeof(var) // as a function
typeof null
is "object"
. This is wrong, null
is not an object, it is a special value with its special type. The error is kept in the language due to compatibility and was never fixed.typeof alert
returns "function"
however this is not strictly true. Although alert
is a function, it is still of type "object"
. typeof
treats functions differently for convenience.An object can be created using one of the two syntaxes:
let foo = {};
let bar = new Object();
Object are useful when they store properties:
let employee = {
firstname: "Koray",
lastname: "Tugay"
};
We can also delete properties from objects:
delete employee.firstname; // Removes the property from the object
Many times there will be functions that create objects to avoid code repetition.
function newUser(name, age) {
return {
name: name,
age: age
};
}
And there is a shorthand for this, in case the variables have same names with function properties:
function newUser(name, age) {
return {
name, // same with name: name
age // same with age: age
};
}
Objects can have flashy property names within quotes:
let foo = {
"flashy property name": "flash property value"
};
Flashy property names cannot be accessed using the dot notation, and must use square brackets:
let val = foo["flashy property name"];
Square brackets also lets referencing property names that are not literals:
let preferedName = "firstname";
let name = employee[preferedName]; // not possible with name.preferedName
With square brackets, you can even have dynamic property names:
let name = "firstname";
let employee = {[name]: "Koray"}; // {firstname: "Koray"} - This is crazy..
Objects can have functions as properties too:
let user = {
greet: function() {
return "Greetings!";
}
};
The method above can be called via:
user.greet();
There is a shorthand form for functions in objects:
let user = {
greet() {
return "Greetings!";
}
};
JavaScript is very liberal in terms of calling functions. If you pass too many arguments, extra ones will be ignored. If you pass too few, missing parameters get assigned undefined
. This allow functions to be called with different number of arguments.
function minus(a, b) {
if (b === undefined)
return -a;
else
return a - b;
}
function power(base, exponent = 2) {
// You already understand..
}
Functions are values in JavaScript, which makes them very powerful and in the same time somewhat confusing..
// This is a function expression, semicolon at the end.
let msgFormatter = function(from, msg) {
return `Message from ${from} : ${msg}`;
};
// This is a function declaration. No semicolon at the end.
function fetchMessageFormatted(url, formatter) {
// fetch message from some remote service
let msg = fromRemoteService(url);
return formatter(msg, url);
}
// I can pass function itself to another function:
fetchMessageFormatted('remote-service-url', msgFormatter);
Such functions are called callback functions. The idea is that we pass a function and expect it to be “called back” later. We can pass anonymous functions as well, which is another powerful aspect of functions as values:
fetchMessageFormatted(
'remote-service-url',
function(from, msg) {
return `${msg} from: ${from}`;
}
);
To make things even more confusing, there is yet another syntax for declaring functions.
let myArrowFunct = (arg1, arg2, arg3) => functionBody;
let numberMultiplier = (num, multiplier) => num * multiplier;
JavaScript is full of situations where we need to write a small function that’s executed somewhere else.
myArr.forEach(myFunct); // myFunct is executed for every item of myArr
The global object is provided by the runtime environment and it is the object accessed when you do not specify any specific objects. In browsers, global object is window
whereas in node it is global
.
When you access the Math
object directly in a browser environment, as in Math.E
, you are actually accessing window.Math
.
There are many other properties that are very useful that comes with the global object, simply type window
or globalThis
in the console and see for yourself.
To gather all passed arguments in an array, use the rest (...
) operator. The dots literally mean gather the remaining parameters into an array.
function authorTitles(firstname, lastname, ...titles) {
return {
firstname,
lastname,
titles
}
}
let king = authorTitles("Stephen", "King", "christine", "it", "shining");
console.log(king);
// Prints the following, note how titles are in an array:
// {
// firstname: 'Stephen',
// lastname: 'King',
// titles: [ 'christine', 'it', 'shining' ]
// }
The rest parameters must always be at the very end, as the last function parameter.
Spread syntax looks very similar to the rest parameters, also using ...
, but does quite the opposite. It spreads the the values of an iterable to individual values:
function greet(firstname, lastname) {
console.log(`Hello ${lastname}. Can I call you ${firstname}?`);
}
greet(...["Koray", "Tugay"]);
// Hello Mr.Tugay. Can I call you Koray?
Note how values in the array has been expanded.
Destructuring assignment is a special syntax that allows us to “unpack” arrays or objects into a bunch of variables.
let [firstname, lastname] = ["Koray", "Tugay"];
// firstname is set to "Koray"
// lastname is set to "Tugay"
Remember the example from spread syntax? Here is something similar to that:
function greet([firstname, lastname]) {
console.log(`Hello ${lastname}. Can I call you ${firstname}?`);
}
greet(["Koray", "Tugay"]);
// Hello Mr.Tugay. Can I call you Koray?
We can also destructure objects..
let kt = {
firstname: "Koray",
lastname: "Tugay"
};
let { firstname, lastname } = kt;
// firstname is set to "Koray"
// lastname is set to "Tugay"
You can even destructure nested objects:
let foo = {
bar: "immediate value",
nested: {
baz: "nested value"
}
};
let {
bar,
nested: {
baz
}
} = foo;
console.log(bar); // immediate value
console.log(baz); // nested value