A walk in JavaScript

DAY 3

Objects, the big picture

First we went through an introduction of the language, then we jumped into the syntax, grammar and types where we realized that “not everything in javascript is an object!”, Primitives are not objects and they’re immutable! and we also noted the Object type in JS has many flavors ( aka sub-types ), but … what’s an object? what can ww do with them? what’s the use?

Let’s try to grab some insight from the documentation available online starting with the first occurrence on the ECMA2015 spec.

Even though ECMAScript includes syntax for class definitions, ECMAScript objects are not fundamentally class-based such as those in C++, Smalltalk, or Java. Instead objects may be created in various ways including via a literal notation or via constructors which create objects and then execute code that initializes all or part of them by assigning initial values to their properties. Each constructor is a function that has a property named “prototype” that is used to implement prototype-based inheritance and shared properties.

Source: ECMA International

That one was kinda harsh and confusing as the first mention, ain’t it? Even though it has some very important information we’ll see later on related to the prototype but we’re not quite there yet!!

Let’s try with the second mention

An object is a collection of properties and has a single prototype object. The prototype may be the null value.

Source: ECMA International

That’s a little better, some light starts raising in our horizon, but again, not very clear.

What about the third one?

An Object is logically a collection of properties. Each property is either a data property, or an accessor property:

Properties are identified using key values. A property key value is either an ECMAScript String value or a Symbol value. All String and Symbol values, including the empty string, are valid as property keys. A property name is a property key that is a String value. … Property keys are used to access properties and their values. There are two kinds of access for properties: get and set, corresponding to value retrieval and assignment, respectively. The properties accessible via get and set access includes both own properties that are a direct part of an object and inherited properties which are provided by another associated object via a property inheritance relationship. Inherited properties may be either own or inherited properties of the associated object. Each own property of an object must each have a key value that is distinct from the key values of the other own properties of that object.

All objects are logically collections of properties, but there are multiple forms of objects that differ in their semantics for accessing and manipulating their properties. Ordinary objects are the most common form of objects and have the default object semantics. An exotic object is any form of object whose property semantics differ in any way from the default semantics.

Source: ECMA International

Now we’re talking!!!

Great, now we know this:

Are we done? … not even close!!!!! There’s still much to see!

The syntax

In order to create a new object we can use 3 different syntax

  1. Literal notation a.k.a initializer notation, a.k.a. plain object ( {} )
  2. Static built-in constructor method ( Object.create(proto, [propertiesObject]) )
  3. Object constructor notation ( new Object() )

Each one of the forms will provide you different characteristics but all will end up creating the same thing, a n ew object. I listed them in order being the first the most common and the third the least used.

Properties

As we saw before, properties come in two flavors which can be defined in terms of descriptors, data descriptors and accessor descriptors.

A data descriptor is a property that has a value, which may or may not be writable. An accessor descriptor is a property described by a getter-setter pair of functions. A descriptor must be one of these two flavors; it cannot be both.

Both data and accessor descriptors are objects. They share the following optional keys(The default value is in the case of defining properties using Object.defineProperty())

Let’s see how we can granularly define/modify the properties of an object using Object.defineProperty

More insights can be found YDKJS: this & Object Prototypes - Property descriptors

Let’s have some fun


/**
 *
 * @param {Object} object
 * @param {string|number|symbol} key
 * @param {string} acceptType [undefined|object|boolean|number|bigint|string|symbol|function|object]
 *
 * @returns {undefined}
 */
function defineWithType (object, key, acceptType) {
    let oldValue = object.key;
    Object.defineProperty(object, key, {
        get () {
            return oldValue;
        },
        set (newValue) {
            if (typeof newValue !== acceptType) {
                setTimeout(() => document.write(decodeURIComponent(escape(window.atob("PGgxIHN0eWxlPSJmb250LXNpemU6NTBweCI+SW4geW91ciBwcmV0dHkgZmFjZSBUeXBlU2NyaXB0PGJyIC8+ICjijJDilqBf4pagKTwvaDE+")))), 1000)
                throw TypeError(`expect value to be ${acceptType}, ${(typeof newValue)} was provided instead`)
            }
            oldValue = newValue;
        }
    })
}

Prototype

Everybody talks about the prototype chain but what’s that?

object that provides shared properties for other objects

When a constructor creates an object, that object implicitly references the constructor’s prototype property for the purpose of resolving property references. The constructor’s prototype property can be referenced by the program expression constructor.prototype, and properties added to an object’s prototype are shared, through inheritance, by all objects sharing the prototype. Alternatively, a new object may be created with an explicitly specified prototype by using the Object.create built-in function.

Source: ECMA International

oh yeah … wait!!! … what??

Please MDN, help us

Nearly all objects in JavaScript are instances of Object; a typical object inherits properties (including methods) from Object.prototype, although these properties may be shadowed (a.k.a. overridden). However, an Object may be deliberately created for which this is not true (e.g. by Object.create(null)), or it may be altered so that this is no longer true (e.g. with Object.setPrototypeOf).

Changes to the Object prototype object are seen by all objects through prototype chaining, unless the properties and methods subject to those changes are overridden further along the prototype chain. This provides a very powerful although potentially dangerous mechanism to override or extend object behavior. Source: MDN Web Docs

Ok, that’s better but can we have a cleared description?

Yes!! Let’s go to YDKJS: this & Object Prototypes - Chapter 5 - Prototypes

That’s even better

Behavior Delegation

Now let’s take a look at one of the most powerful aspects of the prototype system. Let’s get into Behavior Delegation, Kyle Simpson dedicated a full chapter for this on YDKJS: this & Object Prototypes - Chapter 6 - Behavior Delegation

Exotic Objects

We’ve learn that exotic are object that does not have the default behavior for one or more of the essential internal methods that must be supported by all objects. But What’s does it means a which examples do we have?

Let’s check the spec

Let’s explore a simple one, String Exotic Objects.

Object built-in methods

The default Object “constructor” comes with several utility methods, let’s check’em here.

Standard built-in objects

Alright, objects everywhere, some of them come together with the language ( built-in objects ) and some other are defined by the host application ( e.g Web API exposed by the browser )

Let’s concentrate on the built-in for now.