Objects
What is an array?
The array is one of the most fundamental data structures. It's an ordered collection of elements. Here's a foo
variable, which is assigned to an empty array:
const foo = [];
Each element in an array is referenced by a numeric key called an index, which starts from zero and increments by one for each additional element in the array.
const fruits = ['apple', 'orange', 'kiwi'];
To retrieve the first element in fruits
, we access it by its index:
fruits[0]; // 'apple'
To access the last element in fruits
if we know the size of the array, we can access it like:
fruits[2]; // 'kiwi'
To access the last element in fruits
if don't know the size of the array, we can access it like:
fruits[fruits.length - 1]; // 'kiwi'
Arrays can store elements of any type (from left to right: string, boolean, number, function, object, array)
const mixedArray = ['Marios', true, 27, function() { alert('hello'); }, { name: 'Marios' }, [1, 2]];
What is an object?
Introduction
Objects are unordered collection of associated key/value pairs. Here's a foo
variable, which is assigned to an empty object:
const foo = {};
Here's a car
variable, which is assigned to an object. Each distinct key-value pair, is known as a property.
const recipe = {
name: 'Sweet chilli jam',
difficulty: 'easy',
vegetarian: true,
prep: 20,
cook: 60,
ingredients: ['red peppers', 'red chillies', 'fresh root ginger', 'garlic cloves', 'cherry tomatoes', 'sugar', 'vinegar']
};
Object creation
To create a new empty object, you can use the literal notation or the constructor function:
const myObject = {}; // Literal notation
const myObject = new Object(); // Ctor function
Object properties
Object property syntax
Object keys are strings and quotation marks surrounding these strings are optional. As a result the following three objects are equivalent.
const person = { age: 12 };
const person = { 'age': 12 };
const person = { 'age': 12 };
Certain situations require the use of quotation marks. Especially if the property name is a reserved word, contains spaces or special characters.
Accessing object properties
To access object properties we use either the dot notation or the bracket notation:
const car = {
owner: 'Marios',
color: 'red',
year: 1990,
paint: {
type: 'metallic',
code: '23fa4567h'
}
};
Using dot notation we can access car
's color
property as follows:
car.color; // 'red'
Using bracket notation we can access car
's color
property as follows:
car['color']; // 'red'
Using dot notation we can access the code
property as follows:
car.paint.code; // '23fa4567h'
Using bracket notation we can access the code
property as follows:
car['paint']['code']; // '23fa4567h'
The dot notation has its limitations. Consider the following:
const car = {
owner: 'Marios',
color: 'red',
1: 'blah blah blah'
};
const foo = 'color';
car[foo]; // Returns 'red'
car.foo; // Returns undefined
car[1]; // Returns 'blah blah blah'
car.1; // Returns SyntaxError
Considering the following object, write an expression that outputs how to say hello in Portuguese:
const greetings = {
hello: [{
english: 'hi',
french: 'bonjour',
portuguese: 'oi'
}],
goodbye: [{
english: 'bye',
french: 'au revoir',
portuguese: 'tchau'
}]
};
Solution:
greetings.hello[0].portuguese; // Dot notation
greetings['hello'][0]['portuguese']; // Bracket notation
Modifying object properties
Considering the following object:
const person = {
name: 'Mario',
age: 26
}
We can modify the age
and name
properties as follows:
person.age += 1;
person.name = 'Luigi';
Adding object properties
To add a new property to an object, we simply specify the property name and then giving it a value. We can use both the dot and bracket notation to add properties.
const course = {};
course.IsFree = true; // Dot notation
course['name'] = 'Object-Oriented JavaScript'; // Bracket notation
course.message = function () { // Bracket notation
alert('Welcome to OO JavaScript. Have fun!');
};
The complete course
object now looks like:
const course = {
IsFree: true,
name: 'Object-Oriented JavaScript',
message: function () {
alert('Welcome to OO JavaScript. Have fun!');
}
};
Removing object properties
We can go ahead and remove the IsFree
property from course
using the delete
operator. Removing properties with the delete
operator returns true
upon successful deletion.
delete course.IsFree;
Passing arguments
Passing primitives
In JavaScript primitives (e.g. string, number, boolean) are immutable (meaning they can't be changed).
function foo(n) {
n = 8;
}
let n = 6;
foo(n);
console.log(n); // n = 6
Passing objects
In JavaScript objects are mutable (meaning they can be changed). Objects are passed by reference.
const foo = {
color: 'red'
};
function setColor(obj) {
obj.color = 'blue';
};
setColor(foo);
console.log(foo.color); // blue
When re-assigning an object to a new variable, and then change the copy, changes are also reflected back to the original object since objects are passed by reference.
const original = { color: 'red' };
const copy = original;
copy.color = 'blue';
console.log(original.color); // 'blue'
Comparing objects
The following objects look the same:
const lion = {
group: 'mammal',
type: 'carnivor'
}
const tiger = {
group: 'mammal',
type: 'carnivor'
}
You might expect the lion
and tiger
object to be equal but this is not true.
parrot === tiger // false
The expression only returns true when comparing two references to the same object:
const myMammal = lion;
myMammal === lion; // true
myMammal === tiger // false
Object methods
A method is a property of an object whose value is a function.
Consider the following object:
const person = {
name: 'marios'
}
Consider the following function:
function sayHello () {
alert('Hello World');
}
If we want to add the sayHello()
function into the person
object, we can add it with the same way as we add other new properties.
person.sayHello = function () {
alert('Hello World');
};
The updated person
object now looks like:
const person = {
name: 'marios',
sayHello: function () {
alert('Hello World');
}
};
We can access a method the same way that we do with other properties: by using dot notation
or bracket
notation.
person.sayHello(); // Dot notation
person['sayHello'](); // Bracket notation
Consider the following object:
const person = {
name: 'marios',
favoriteCar: function (model) {
alert('My favorite car is a ${model}');
}
}
To pass an argument to the method:
person.favoriteCar('1968 Ford Mustang');
Consider the following array:
const foo = [function sayHello() { alert('Hello');}];
To invoke the sayHello()
function:
foo[0]();
So far we've been using anonymous functions for object methods. However, naming those functions is still valid JavaScript syntax:
const person = {
name: 'marios',
welcomeMsg: function sayHello() {
alert('Hello');
}
};
Whether a method is named or not, it is invoked the same way:
person.welcomeMsg();
'this' keyword
A method can access the object it was called on using this
. Using this
, methods can access and manipulate an object's properties. this
is a reserved word in JavaScript. The value of this
can have different meanings outside an object.
Consider the following object:
const car = {
type: 'RWD',
identify: function () {
alert('This car is a ${this.type} car.');
}
};
When you say this
, what you're really saying is 'this object' or 'the object at hand'.
Consider the following object:
const person = {
name: 'marios',
age: 26,
booksRead: ['The Silmarillion', 'The Count of Monte Cristo'],
ageOneYear: function () {
this.age += 1;
},
addBook: function (book) {
this.booksRead.push(book);
}
};
person.ageOneYear();
alert(person.age); // 27
person.addBook('Thinking, Fast and Slow');
alert(person.booksRead[2]); // 'Thinking, Fast and Slow'
Create an object called chameleon
with two properties:
1. color
, whose value is initially set to 'green' or 'pink'
2. changeColor
, a function which changes chameleon
's color
to 'pink' if it is 'green', or to 'green' if it is 'pink'.
const chameleom = {
color: 'green',
changeColor: function () {
if(this.color === 'pink') {
this.color = 'green';
}
else {
this.color = 'pink';
}
}
};
Globals
const lion = {
eyes: 2,
lookAround: fuction () {
console.log('I see you with my ${this.eyes} eyes!');
}
};
function whoThis () {
this.trickyish = true;
}
lion.lookAround(); // 'I see you with my 2 eyes!'
whoThis();
The this
keyword inside a method refers to the object the method was called on. In our case this
refers to lion
.
The value of this
inside the regular function is the global window
object.
The 'window' object
Introduction
The window
object is provided by the browser. This object is not part of the JavaScript specification (i.e. ECMAScript), instead, it is developed by the W3C. This window
object has access to a ton of information about the page itself, including:
- The page's URL (window.location;)
- The vertical scroll position of the page (window.scrollY')
- Opening a new web page (window.open('https://www.udacity.com/');)
const car = {
numberOfDoors: 4,
drive: function () {
console.log(`Get in one of the ${this.numberOfDoors} doors, and let's go!`);
}
};
const letsRoll = car.drive;
letsRoll();
What does you think this
refers to in the code above?
Even though car.drive
is a method, we're storing the function itself in the a variable letsRoll
. Because letsRoll()
is invoked as a regular function, this
will refer to the window
object inside of it.
Properties
Every variable declaration that is made at the global level (outside of a function) automatically becomes a property on the window object. Only declaring variables with the var
keyword will add them to the window
object. If you declare a variable outside of a function with either let
or const
, it will not be added as a property to the window
object. Similarly to global variables, any global function declaration is accessible on the window
object as a method:
var str1 = 'john';
let str2 = 'marios';
const str3 = 'emily';
window.str1 === str1 // true
window.str2 === str2 // false
window.str3 === str3 // false
function learnSomethingNew() {
window.open('https://www.google.com/');
}
window.learnSomethingNew === learnSomethingNew // true
Considerations
Global variables and functions should be used sparingly. There are actually a number of reasons why, but the two we'll look at are:
- Tight Coupling: In tight coupling, pieces of code are joined together in a way where changing one unintentionally alters the functioning of some other code.
- Name Collisions: A name collision occurs when two (or more) functions depend on a variable with the same name. A major problem with this is that both functions will try to update the variable and or set the variable, but these changes are overridden by each other.
You should write as few global variables as possible. Write your variables inside of the functions that need them, keeping them as close to where they are needed as possible.
The 'Object()' constructor
const dictionary = {
mario: 'nfjdfjhdfkdfd',
john: 'paphos2017',
mary: 'mary1990',
ian: 'password'
};
- Create object:
const myObject = new Object();
- Return object keys:
const myArray = Object.keys(dictionary);
- Return object values:
const myArray = Object.values(dictionary);
The resulting array's elements for Object.keys()
are strings.
We could also aquire the object's keys and values using a for...in
loop like:
const keys = [];
for(const key in dictionary) {
keys.push(key);
}