Objects: the basics Flashcards
What is an object datatype in JS ?
As we know from the chapter Data types, there are eight data types in JavaScript. Seven of them are called “primitive”, because their values contain only a single thing (be it a string or a number or whatever).
In contrast, objects are used to store keyed collections of various data and more complex entities. In JavaScript, objects penetrate almost every aspect of the language. So we must understand them first before going in-depth anywhere else.
An object can be created with figure brackets {…} with an optional list of properties. A property is a “key: value” pair, where key is a string (also called a “property name”), and value can be anything.
We can imagine an object as a cabinet with signed files. Every piece of data is stored in its file by the key. It’s easy to find a file by its name or add/remove a file.
How to declare an empty object ? Write two methods.
let user = new Object(); // "object constructor" syntax let user = {}; // "object literal" syntax
What is a property in an object ?
let user = { // an object
name: “John”, // by key “name” store value “John”
age: 30 // by key “age” store value 30
};
A property has a key (also known as “name” or “identifier”) before the colon “:” and a value to the right of it.
In the user object, there are two properties:
The first property has the name “name” and the value “John”.
The second one has the name “age” and the value 30.
How to access a property of an object ?
Property values are accessible using the dot notation:
// get property values of the object:
alert( user.name ); // John
alert( user.age ); // 30
The value can be of any type. Let’s add a boolean one:
user.isAdmin = true;
How to delete a property of an object ?
To remove a property, we can use delete operator:
delete user.age;
Can we use multi word property name for an object ?
We can also use multiword property names, but then they must be quoted:
let user = { name: "John", age: 30, "likes birds": true // multiword property name must be quoted };
Why the last property ends with a comma ?
The last property in the list may end with a comma:
let user = { name: "John", age: 30, } That is called a “trailing” or “hanging” comma. Makes it easier to add/remove/move around properties, because all lines become alike.
How to access multi word properties of an object ?
For multiword properties, the dot access doesn’t work:
// this would give a syntax error user.likes birds = true JavaScript doesn’t understand that. It thinks that we address user.likes, and then gives a syntax error when comes across unexpected birds.
The dot requires the key to be a valid variable identifier. That implies: contains no spaces, doesn’t start with a digit and doesn’t include special characters ($ and _ are allowed).
There’s an alternative “square bracket notation” that works with any string:
let user = {};
// set user["likes birds"] = true;
// get alert(user["likes birds"]); // true
// delete delete user["likes birds"]; Now everything is fine. Please note that the string inside the brackets is properly quoted (any type of quotes will do).
Can we access a property from another variable ?
yes
Square brackets also provide a way to obtain the property name as the result of any expression – as opposed to a literal string – like from a variable as follows:
let key = “likes birds”;
// same as user["likes birds"] = true; user[key] = true; Here, the variable key may be calculated at run-time or depend on the user input. And then we use it to access the property. That gives us a great deal of flexibility.
let user = { name: "John", age: 30 };
let key = "name"; alert( user.key ) // Will this work ?
let user = { name: "John", age: 30 };
let key = "name"; alert( user.key ) // undefined Because dot operator doesn't work like that
What are computed properties ?
We can use square brackets in an object literal, when creating an object. That’s called computed properties.
For instance:
let fruit = prompt(“Which fruit to buy?”, “apple”);
let bag = { [fruit]: 5, // the name of the property is taken from the variable fruit };
alert( bag.apple ); // 5 if fruit=”apple”
The meaning of a computed property is simple: [fruit] means that the property name should be taken from fruit.
So, if a visitor enters “apple”, bag will become {apple: 5}.
let fruit = 'apple'; let bag = { [fruit + 'Computers']: 5 // What does this line mean if we write it in dot operator form ? };
let fruit = 'apple'; let bag = { [fruit + 'Computers']: 5 // bag.appleComputers = 5 };
Are thier any name limitations for property names ?
As we already know, a variable cannot have a name equal to one of language-reserved words like “for”, “let”, “return” etc.
But for an object property, there’s no such restriction:
// these properties are all right let obj = { for: 1, let: 2, return: 3 };
alert( obj.for + obj.let + obj.return ); // 6
In short, there are no limitations on property names. They can be any strings or symbols (a special type for identifiers, to be covered later).
Other types are automatically converted to strings.
let obj = { 0: "test" }; alert( obj["0"] ); alert( obj[0] );
Will this work ?
let obj = { 0: "test" // same as "0": "test" };
// both alerts access the same property (the number 0 is converted to string “0”)
alert( obj[“0”] ); // test
alert( obj[0] ); // test (same property)
Is it possible to access any non existing property of an object. Will there be any error ?
No.
A notable feature of objects in JavaScript, compared to many other languages, is that it’s possible to access any property. There will be no error if the property doesn’t exist!
Reading a non-existing property just returns undefined. So we can easily test whether the property exists:
let user = {};
alert( user.noSuchProperty === undefined ); // true means “no such property”
What is ‘in’ operator ?
The syntax is:
“key” in object
For instance:
let user = { name: “John”, age: 30 };
alert( “age” in user ); // true, user.age exists
alert( “blabla” in user ); // false, user.blabla doesn’t exist
Do we have to use the ‘in’ operator for checking any property existence in a object. Can’t we directly use undefined comparison ?
Why does the in operator exist? Isn’t it enough to compare against undefined?
Well, most of the time the comparison with undefined works fine. But there’s a special case when it fails, but “in” works correctly.
It’s when an object property exists, but stores undefined:
let obj = { test: undefined };
alert( obj.test ); // it’s undefined, so - no such property?
alert( “test” in obj ); // true, the property does exist!
In the code above, the property obj.test technically exists. So the in operator works right.
Situations like this happen very rarely, because undefined should not be explicitly assigned. We mostly use null for “unknown” or “empty” values. So the in operator is an exotic guest in the code.
How for in loop works ?
To walk over all keys of an object, there exists a special form of the loop: for..in. This is a completely different thing from the for(;;) construct that we studied before.
The syntax:
for (key in object) { // executes the body for each key among object properties } For instance, let’s output all properties of user:
let user = { name: "John", age: 30, isAdmin: true };
for (let key in user) { // keys alert( key ); // name, age, isAdmin // values for the keys alert( user[key] ); // John, 30, true }
Are properties ordered inside the object ?
The short answer is: “ordered in a special fashion”: integer properties are sorted, others appear in creation order. The details follow.
As an example, let’s consider an object with the phone codes:
let codes = { "49": "Germany", "41": "Switzerland", "44": "Great Britain", // .., "1": "USA" };
for (let code in codes) {
alert(code); // 1, 41, 44, 49
}
let user = { name: "John", surname: "Smith" }; user.age = 25; // add one more
for (let prop in user) {
alert( prop );
}
What would be the output ?
let user = { name: "John", surname: "Smith" }; user.age = 25; // add one more
// non-integer properties are listed in the creation order for (let prop in user) { alert( prop ); // name, surname, age }
if the keys are non-integer, then they are listed in the creation order,
let codes = { "+49": "Germany", "+41": "Switzerland", "+44": "Great Britain", // .., "+1": "USA" };
for (let code in codes) {
alert( +code );
}
Output ?
let codes = { "+49": "Germany", "+41": "Switzerland", "+44": "Great Britain", // .., "+1": "USA" };
for (let code in codes) {
alert( +code ); // 49, 41, 44, 1
}
to fix the issue with the phone codes, we can “cheat” by making the codes non-integer. Adding a plus “+” sign before each code is enough.
A variable assigned to an object stores not the object itself, but its “address in memory” – in other words “a reference” to it.
Is it true ?
Yes
When an object variable is copied, the reference is copied, but the object itself is not duplicated. Is it true ?
Yes
let a = {}; // empty object let b = a;
alert( a == b );
alert( a === b );
Output ?
let a = {}; // empty object let b = a; // copy the reference
alert( a == b ); // true, both variables reference the same object
alert( a === b ); // true
let a = {}; let b = {}; // two independent objects
alert( a == b );
let a = {}; let b = {}; // two independent objects
alert( a == b ); // false
How to duplicate an object?or How to Create an independent copy, a clone? since we can not do that by simply assigning an object to another variable because it will copy the reference to the object not the object itself.
That’s also doable, but a little bit more difficult, because there’s no built-in method for that in JavaScript. But there is rarely a need – copying by reference is good most of the time.
But if we really want that, then we need to create a new object and replicate the structure of the existing one by iterating over its properties and copying them on the primitive level.
Like this:
let user = { name: "John", age: 30 };
let clone = {}; // the new empty object
// let's copy all user properties into it for (let key in user) { clone[key] = user[key]; }
// now clone is a fully independent object with the same content clone.name = "Pete"; // changed the data in it
alert( user.name ); // still John in the original object
Also we can use the method Object.assign for that.
How to use object.assign to clone a object ?
The syntax is:
Object.assign(dest, [src1, src2, src3…])
The first argument dest is a target object.
Further arguments src1, …, srcN (can be as many as needed) are source objects.
It copies the properties of all source objects src1, …, srcN into the target dest. In other words, properties of all arguments starting from the second are copied into the first object.
The call returns dest.
What is deep cloning or deep copy ?
When an object have a nested object and we try to copy it using object assign then The nested object will be saved by reference. To prove that, if we make changes in original’s nested object, then the value would also get changed in the copy object.
for example: let user = { name: "John", sizes: { height: 182, width: 50 } };
let clone = Object.assign({}, user);
alert( user.sizes === clone.sizes ); // true, same object
// user and clone share sizes user.sizes.width++; // change a property from one place alert(clone.sizes.width); // 51, see the result from the other one
To fix that, we should use a cloning loop that examines each value of user[key] and, if it’s an object, then replicate its structure as well. That is called a “deep cloning”.
We can use recursion to implement it. Or, to not reinvent the wheel, take an existing implementation, for instance _.cloneDeep(obj) from the JavaScript library lodash.
What is shallow copy ?
When we copy an object, when nested objects are copied by reference then, it is called a shallow copy. because it is not a complete clone. If we make changes in the original’s nested object, then the values will also get changed in the clone’s nested object.
Can const objects be modified ?
An important side effect of storing objects as references is that an object declared as const can be modified.
For instance:
const user = { name: "John" };
user.name = “Pete”; // (*)
alert(user.name); // Pete
It might seem that the line (*) would cause an error, but it does not. The value of user is constant, it must always reference the same object, but properties of that object are free to change.
In other words, the const user gives an error only if we try to set user=… as a whole.
That said, if we really need to make constant object properties, it’s also possible, but using totally different methods. We’ll mention that in the chapter Property flags and descriptors.
Does automatic garbage collection happens in JS ?
Yes
What is the concept of reachibility in JS ?
The main concept of memory management in JavaScript is reachability.
Simply put, “reachable” values are those that are accessible or usable somehow. They are guaranteed to be stored in memory.