in ECMAScript

ECMA-262-3 in detail. Chapter 7.2. OOP: ECMAScript implementation.

Read this article in: Russian, French.

Introduction

This is the second part of article about object-oriented programming in ECMAScript. In the first part we discussed the general theory and drew parallels with ECMAScript. Before reading of the current part, if it is necessary, I recommend reading the first part as in this article we will actively use the passed terminology. You can find the first part here: ECMA-262-3 in detail. Chapter 7.1. OOP: The general theory.

ECMAScript OOP implementation

Having passed the way of highlights of the general theory, we at last have reached the ECMAScript itself. Now, when we know its OOP approach, let’s make once again an accurate definition:

ECMAScript is an object-oriented programming language supporting delegating inheritance based on prototypes.

We begin the analysis from consideration of data types. And first it is necessary to notice that ECMAScript distinguishes entities on primitive values and objects. Therefore the phrase “everything in JavaScript is an object” sometimes arising in various articles, is not correct (is not full). Primitive values concern to a data of certain types which we should discuss in detail.

Data types

Though ECMAScript is a dynamic, weakly typed language with “duck” typing, and automatic type conversion, it nevertheless has certain data types. That is, at one moment, an object belongs to one concrete type.

Standard defines nine types, and only six are directly accessible in an ECMAScript program:

  • Undefined
  • Null
  • Boolean
  • String
  • Number
  • Object

Other three types are accessible only at implementation level (none of ECMAScript objects can have such type) and used by the specification for explaining behavior of some operations, for storing intermediate values and other. These are following types:

  • Reference
  • List
  • Completion

Thus (in short overview), Reference type is used for an explanation of such operators as delete, typeof, this and other, and consists of a base object and a property name. List type describes behavior of the arguments list (in the new expression and function calls). Completion type in turn is used for an explanation of behavior break, continue, return and throw statements.

Primitive value types

Coming back to the six types used by ECMAScript programs, first five of them: Undefined, Null, Boolean, String and Number are types of primitive values.

Examples of primitive values:

var a = undefined;
var b = null;
var c = true;
var d = 'test';
var e = 10;

These values are represented in implementations directly on a low level. They are not objects, they do not have neither prototypes, nor constructors.

The typeof operator can be unintuitive if not properly understood. And one such example of that is with the value null. When null is supplied to the typeof operator, the result is "object" regardless of the fact that the type of null is specified as Null.

console.log(typeof null); // "object"

And the reason is that the typeof operator returns the value taken from standard table which simply says: “for null value string "object" should be returned”.

Specification doesn’t clarify this, however Brendan Eich (JavaScript inventor) noticed that null in contrast with undefined, is used in mostly where objects appear, i.e. is an essence closely related to objects (meaning the “empty” reference to an object, probably reserved a place for the future purposes). But, in some drafts, there was provided the document where this “phenomenon” was described as a usual bug. Also, this bug appeared in one of bug-trackers where Brendan Eich also participated; as a result it has been decided to leave typeof null as is, i.e. "object" though ECMA-262-3 standard defines type of null as Null.

Object type

In turn, the Object type (do not confuse with the Object constructor, we’re talking now only about abstract types!) is the only type that represents ECMAScript objects.

Object is an unordered collection of key-value pairs.

The keys of objects are called properties. Properties are containers for primitive values and other objects. In case when properties contain functions as their values, they are called methods.

Example:

var x = { // object "x" with three properties: a, b, c
  a: 10, // primitive value
  b: {z: 100}, // object "b" with property z
  c: function () { // function (method)
    console.log('method x.c');
  }
};

console.log(x.a); // 10
console.log(x.b); // [object Object]
console.log(x.b.z); // 100
x.c(); // 'method x.c'
Dynamic nature

As we noted in chapter 7.1, objects in ES are fully dynamic. It means that we may add, modify or remove properties of objects at any time of program execution.

For example:

var foo = {x: 10};

// add new property
foo.y = 20;
console.log(foo); // {x: 10, y: 20}

// change property value to function
foo.x = function () {
  console.log('foo.x');
};

foo.x(); // 'foo.x'

// delete property
delete foo.x;
console.log(foo); // {y: 20}

Some properties cannot be modified — read-only properties or deleted — non-configurable properties. We’ll consider these cases shortly in the section of property attributes.

Note, ES5 standardized static objects which cannot be extended with new properties and none of the properties can be modified or deleted. These are so-called frozen objects, which can be gotten by applying Object.freeze(o) method.

var foo = {x: 10};

// freeze the object
Object.freeze(foo);
console.log(Object.isFrozen(foo)); // true

// can't modify
foo.x = 100;

// can't extend
foo.y = 200;

// can't delete
delete foo.x;

console.log(foo); // {x: 10}

Also it’s possible just to prevent extensions using Object.preventExtensions(o) method, and to control specific attributes with Object.defineProperty(o) method:

var foo = {x : 10};

Object.defineProperty(foo, "y", {
  value: 20,
  writable: false, // read-only
  configurable: false // non-configurable
});

// can't modify
foo.y = 200;

// can't delete
delete foo.y; // false

// prevent extensions
Object.preventExtensions(foo);
console.log(Object.isExtensible(foo)); // false

// can't add new properties
foo.z = 30;

console.log(foo); {x: 10, y: 20}

For details see this chapter.

Built-in, native and host objects

It is necessary to notice also that the specification distinguishes native objects, built-in objects and host objects.

Built-in and native objects are defined by the ECMAScript specification and the implementation, and a difference between them insignificant. Native objects are the all objects provided by ECMAScript implementation (some of them can be built-in, some can be created during the program execution, for example user-defined objects).

The built-in objects are a subtype of native objects which are built into the ECMAScript prior to the beginning of a program (for example, parseInt, Math etc.).

All host objects are objects provided by the host environment, typically a browser, and may include, for example, window, console.log, etc.

Notice, that host objects may be implemented using ES itself and completely correspond to the specification’s semantics. From this viewpoint, they can be named (unofficially) as “native-host” objects, though it’s mostly a theoretical aspect. The specification however does not define any “native-host” concept.

Boolean, String and Number objects

Also for some primitives the specification defines special wrapper objects. These are following objects:

  • Boolean-object
  • String-object
  • Number-object

Such objects are created with corresponding built in constructors and contain primitive value as one of internal properties. Object representation can be converted into primitive values and vice-versa.

Examples of the object values corresponding to primitive types:

var c = new Boolean(true);
var d = new String('test');
var e = new Number(10);

// converting to primitive
// conversion: ToPrimitive
// applying as a function, without "new" keyword
с = Boolean(c);
d = String(d);
e = Number(e);

// back to Object
// conversion: ToObject
с = Object(c);
d = Object(d);
e = Object(e);

Besides, there are also objects created by special built in constructors: Function (function objects constructor) Array (arrays constructor), RegExp (regular expressions constructor), Math (the mathematical module), Date (the constructor of dates), etc. Such objects are also values of type Object and their distinction from each other is managed by internal properties which we will discuss below.

Literal notations

For three object values: object, array and regular expression there are short notations which called accordingly an object initialiser, an array initialiser and a regular expression literal:

// equivalent to new Array(1, 2, 3);
// or array = new Array();
// array[0] = 1;
// array[1] = 2;
// array[2] = 3;
var array = [1, 2, 3];

// equivalent to
// var object = new Object();
// object.a = 1;
// object.b = 2;
// object.c = 3;
var object = {a: 1, b: 2, c: 3};

// equivalent to new RegExp("^\\d+$", "g")
var re = /^\d+$/g;

Notice, that in case of reassigning the name bindings — Object, Array or RegExp to some new objects, the semantics of subsequent using of the literal notations may vary in implementations. For example in the current Rhino implementation or in the old SpiderMonkey 1.7 appropriate literal notation will create an object corresponding to the new value of constructor name. In other implementations (including current Spider/TraceMonkey) semantics of the literal notations is not being changed even if constructor name is rebound to the new object:

var getClass = Object.prototype.toString;

Object = Number;

var foo = new Object;
console.log([foo, getClass.call(foo)]); // 0, "[object Number]"

var bar = {};

// in Rhino, SpiderMonkey 1.7 - 0, "[object Number]"
// in other: still "[object Object]", "[object Object]"
console.log([bar, getClass.call(bar)]);

// the same with Array name
Array = Number;

foo = new Array;
console.log([foo, getClass.call(foo)]); // 0, "[object Number]"

bar = [];

// in Rhino, SpiderMonkey 1.7 - 0, "[object Number]"
// in other: still "", "[object Object]"
console.log([bar, getClass.call(bar)]);

// but for RegExp, semantics of the literal
// isn't being changed in all tested implementations

RegExp = Number;

foo = new RegExp;
console.log([foo, getClass.call(foo)]); // 0, "[object Number]"

bar = /(?!)/g;
console.log([bar, getClass.call(bar)]); // /(?!)/g, "[object RegExp]"
Regular Expression Literal and RegExp Objects

Notice although, that in ES3 the two last cases with regular expressions being equivalent semantically, nevertheless differ. The regexp literal exists only in one instance and is created on parsing stage, while RegExp constructor creates always a new object. This can cause some issues with e.g. lastIndex property of regexp objects when regexp test is fail:

for (var k = 0; k < 4; k++) {
  var re = /ecma/g;
  console.log(re.lastIndex); // 0, 4, 0, 4
  console.log(re.test("ecmascript")); // true, false, true, false
}

// in contrast with

for (var k = 0; k < 4; k++) {
  var re = new RegExp("ecma", "g");
  console.log(re.lastIndex); // 0, 0, 0, 0
  console.log(re.test("ecmascript")); // true, true, true, true
}

Note, in ES5 this issue has been fixed and regexp literal also always creates a new object.

Associative arrays?

Often in various articles or discussions, JavaScript objects (and usually exactly those which created in declarative form — via the object initialiser — {}) are called hash-tables or simply — hashes (terms from Ruby or Perl), associative arrays (term from PHP), dictionaries (term from Python) etc.

Using of this terminology is a habit to concrete technology. Really, they are similar enough, and in respect of “key-value” pairs storage completely correspond to the theoretical “associative array” or “hash tables” data structures. Moreover, a hash table abstract data type may be and usually is used at implementation level.

However, although terminology is used to describe a conceptual way of thinking, it is not actually technically correct, regarding ECMAScript. As it has been noted, ECMAScript has only one object type and its “subtypes” in respect of a “key-value” pairs storage do not differ from each other. Therefore, there is no separated special term (hash or other) for that. Because any object regardless its internal properties can store these pairs:

var a = {x: 10};
a['y'] = 20;
a.z = 30;

var b = new Number(1);
b.x = 10;
b.y = 20;
b['z'] = 30;

var c = new Function('');
c.x = 10;
c.y = 20;
c['z'] = 30;

// etc. – with any object "subtype"

Moreover, objects in ECMAScript because of delegation can be nonempty, therefore the term “hash” also can be improper:

Object.prototype.x = 10;

var a = {}; // create "empty" "hash"

console.log(a["x"]); // 10, but it's not empty
console.log(a.toString); // function

a["y"] = 20; // add new pair to "hash"
console.log(a["y"]); // 20

Object.prototype.y = 20; // and property into the prototype

delete a["y"]; // remove
console.log(a["y"]); // but key and value are still here – 20
Notice, that ES5 standardized the ability to create objects without prototypes — that is, their prototype is set to null. It’s achieved with using the Object.create(null) method. From this viewpoint such objects are simple hash-tables:

var aHashTable = Object.create(null);
console.log(aHashTable.toString); // undefined

Also, some properties can have specific getters/setters, so it can also confuse:

var a = new String("foo");
a['length'] = 10;
console.log(a['length']); // 3

However, even if to consider that “hash” could have a “prototype” (as for example, in Ruby or Python — a class to which delegate hash-objects), in ECMAScript this terminology can also be improper because there is no semantic differentiation between kinds of property accessors (i.e. dot and bracket notations).

Also in ECMAScript concept of a “property” semantically is not separated into a “key”, “array index”, “method” or “property”. Here all of them are properties which obey to the common law of reading/writing algorithm with examination of the prototype chain.

In the following example on Ruby we see this distinction in semantics and consequently there such terminology can differ:

a = {}
a.class # Hash

a.length # 0

# new "key-value" pair
a['length'] = 10;

# but semantics for the dot notation
# remains other and means access
# to the "property/method", but not to the "key"

a.length # 1

# and the bracket notation
# provides access to "keys" of a hash

a['length'] # 10

# we can augment dynamically Hash class
# with new properties/methods and they via
# delegation will be available for already created objects

class Hash
  def z
    100
  end
end

# a new "property" is available

a.z # 100

# but not a "key"

a['z'] # nil

ECMA-262-3 standard does not define concept of “hash” (and similar). However, if theoretical data structure is meant, it is possible to name objects so.

Type conversion

To convert an object into a primitive value the method valueOf can be used. As we noted, the call of the constructor (for certain types) as a function, i.e. without new operator performs conversion of object type to a primitive value. For this conversion exactly implicit call of the valueOf method is used:

var a = new Number(1);
var primitiveA = Number(a); // implicit "valueOf" call
var alsoPrimitiveA = a.valueOf(); // explicit

console.log([
  typeof a, // "object"
  typeof primitiveA, // "number"
  typeof alsoPrimitiveA // "number"
]);

This method allows objects to participate in various operations, for example, in addition:

var a = new Number(1);
var b = new Number(2);

console.log(a + b); // 3

// or even so

var c = {
  x: 10,
  y: 20,
  valueOf: function () {
    return this.x + this.y;
  }
};

var d = {
  x: 30,
  y: 40,
  // the same .valueOf
  // functionality as "с" object has,
  // borrow it:
  valueOf: c.valueOf
};

console.log(c + d); // 100

The value of the valueOf method by default (if it is not overridden) can vary depending on object type. For some objects it returns the this value — for example, Object.prototype.valueOf(), for others — any calculated value, as e.g. Date.prototype.valueOf(), which returns the time of a date:

var a = {};
console.log(a.valueOf() === a); // true, "valueOf" returned this value

var d = new Date();
console.log(d.valueOf()); // time
console.log(d.valueOf() === d.getTime()); // true

Also there is one more primitive representation of an object — a string representation. For this toString method is responsible, which in some operations is also applied automatically:

var a = {
  valueOf: function () {
    return 100;
  },
  toString: function () {
    return '__test';
  }
};

// in this operation
// toString method is
// called automatically
console.log(a); // "__test"

// but here - the .valueOf() method
console.log(a + 10); // 110

// but if there is no
// valueOf method, it
// will be replaced with the
//toString method
delete a.valueOf;
console.log(a + 10); // "_test10"

The toString method defined on Object.prototype has special meaning. It returns the value of the internal [[Class]] property, which we’ll discuss below.

Along with ToPrimitive conversion, there is also ToObject conversion which vice-versa converts the value to the object type.

One of explicit ways to call ToObject is to use built in Object constructor as a function (though for some types using of Object with the new operator is also possible):

var n = Object(1); // [object Number]
var s = Object('test'); // [object String]

// also for some types it is
// possible to call Object with new operator
var b = new Object(true); // [object Boolean]

// but applied without arguments,
// new Object creates a simple object
var o = new Object(); // [object Object]

// in case if argument for Object function
// is already object value,
// it simply returns
var a = [];
console.log(a === new Object(a)); // true
console.log(a === Object(a)); // true

Regarding calls of the built in constructors with the new and without new operator, there is no the general rule and it depends on the constructor. For example Array or Function constructors produce the same results when are called as a constructor (with new) and as a simple function (without new):

var a = Array(1, 2, 3); // [object Array]
var b = new Array(1, 2, 3); // [object Array]
var c = [1, 2, 3]; // [object Array]

var d = Function(''); // [object Function]
var e = new Function(''); // [object Function]

There are also explicit and implicit type casting when some operators are applied:

var a = 1;
var b = 2;

// implicit
var c = a + b; // 3, number
var d = a + b + '5' // "35", string

// explicit
var e = '10'; // "10", string
var f = +e; // 10, number
var g = parseInt(e, 10); // 10, number

// etc.
Property attributes

All properties can have a number of attributes:

  • {ReadOnly} — attempt to write value to the property is ignored; however, ReadOnly-properties can be changed by host-environment actions, therefore ReadOnly — does not mean “constant value”;
  • {DontEnum} — the property is not enumerable by a for..in loop;
  • {DontDelete} — action of the delete operator applied to the property is ignored;
  • {Internal} — the property is internal, it has no name and is used only on implementation level; such properties are not accessible to the ECMAScript program.
Note, in ES5 {ReadOnly}, {DontEnum} and {DontDelete} are renamed accordingly into the [[Writable]], [[Enumerable]] and [[Configurable]] and can be manually managed via the Object.defineProperty and similar methods.

var foo = {};

Object.defineProperty(foo, "x", {
  value: 10,
  writable: true, // aka {ReadOnly} = false
  enumerable: false, // aka {DontEnum} = true
  configurable: true // {DontDelete} = false
});

console.log(foo.x); // 10

// attributes set is called a descriptor
var desc = Object.getOwnPropertyDescriptor(foo, "x");

console.log(desc.enumerable); // false
console.log(desc.writable); // true
// etc.
Internal properties and methods

Objects also can have a number of internal properties which are a part of implementation and inaccessible for ECMAScript programs directly (however as we will see below, some implementations allow the access to some such properties). These properties by the convention are enclosed with double square brackets — [[ ]].

We will touch some of them (obligatory for all objects); description of other properties can be found in the specification.

Each object should implement the following internal properties and methods:

  • [[Prototype]] — the prototype of this object (it will be considered below in detail);
  • [[Class]] — a string representation of object’s kind (for example, Object, Array, Function, etc.); it is used to distinguish the objects;
  • [[Get]] — a method of getting the property’s value;
  • [[Put]] — a method of setting the property’s value;
  • [[CanPut]] — checks whether writing to the property is possible;
  • [[HasProperty]] — checks whether the object has already this property;
  • [[Delete]] — removes the property from the object;
  • [[DefaultValue]] — returns a primitive value corresponding with the object (for getting this value the valueOf method is called; for some objects, TypeError exception can be thrown).
  • To get the [[Class]] property from ECMAScript programs is possible indirectly via the Object.prototype.toString() method. This method should return the following string: "[object " + [[Class]] + "]". For example:

    var getClass = Object.prototype.toString;
    
    getClass.call({}); // [object Object]
    getClass.call([]); // [object Array]
    getClass.call(new Number(1)); // [object Number]
    // etc.

    This feature is often used to check the kind of an object, however, it is necessary to note that by the specification internal [[Class]] property of hosts-objects can be any, including values of the [[Class]] property of the built in objects, that in theory does not make such checks 100% proved. For example, [[Class]] property of the document.childNodes.item(...) method in older IE returns "String" (in other implementations, "Function" is returned):

    // in older IE - "String", in other - "Function"
    console.log(getClass.call(document.childNodes.item));

    Constructor

    So, as we mentioned above, objects in ECMAScript are created via, so-called, constructors.

    Constructor is a function that creates and initializes the newly created object.

    For creation (memory allocation) the [[Construct]] internal method of a constructor function is responsible. The behavior of this internal method is specified and all constructor functions uses this method to allocate memory for new object.

    And initialization is managed by calling the function in context of newly created object. For this already internal [[Call]] method of the constructor function is responsible.

    Note, that from user-code only the initialization phase is accessible. Though, even from initialization we can return different object ignoring this object which was created at the first stage:

    function A() {
      // update newly created object
      this.x = 10;
      // but return different object
      return [1, 2, 3];
    }
    
    var a = new A();
    console.log(a.x, a); undefined, [1, 2, 3] 
    

    Referencing to algorithm of creation of Function objects discussed in the Chapter 5. Functions, we see that function is a native object which among other properties has this internal [[Construct]] and [[Call]] properties and also explicit prototype property — the reference to a prototype of the future objects (notice, NativeObject here and below is my pseudo-code naming convention for “native object” concept from ECMA-262-3, but not the built-in constructor).

    F = new NativeObject();
    
    F.[[Class]] = "Function"
    
    .... // other properties
    
    F.[[Call]] = <reference to function> // function itself
    
    F.[[Construct]] = internalConstructor // general internal constructor
    
    .... // other properties
    
    // prototype of objects created by the F constructor
    __objectPrototype = {};
    __objectPrototype.constructor = F // {DontEnum}
    F.prototype = __objectPrototype

    Thus [[Call]] besides the [[Class]] property (which equals to "Function") is the main in respect of objects distinguishing. Therefore the objects having internal [[Call]] property are called as functions. The typeof operator for such objects returns "function" value. However, it mostly relates to native objects, in case of host callable objects, the typeof operator (no less than [[Class]] property) of some implementations can return other value: for example, window.console.log(...) in IE:

    // in IE - "Object", "object", in other - "Function", "function"
    console.log(Object.prototype.toString.call(window.console.log));
    console.log(typeof window.console.log); // "Object"

    The internal [[Construct]] method is activated by the new operator applied to the constructor function. As we said this method is responsible for memory allocation and creation of the object. If there are no arguments, call parenthesis of constructor function can be omitted:

    function A(x) { // constructor А
      this.x = x || 10;
    }
    
    // without arguments, call
    // brackets can be omitted
    var a = new A; // or new A();
    console.log(a.x); // 10
    
    // explicit passing of
    // x argument value
    var b = new A(20);
    console.log(b.x); // 20

    And as also we know, this value inside the constructor (at initialization phase) is set to the newly created object.

    Let’s consider the algorithm of objects creation.

    Algorithm of objects creation

    The behavior of the internal [[Construct]] method can be described as follows:

    F.[[Construct]](initialParameters):
    
    O = new NativeObject();
    
    // property [[Class]] is set to "Object", i.e. simple object
    O.[[Class]] = "Object"
    
    // get the object on which
    // at the moment references F.prototype
    var __objectPrototype = F.prototype;
    
    // if __objectPrototype is an object, then:
    O.[[Prototype]] = __objectPrototype
    // else:
    O.[[Prototype]] = Object.prototype;
    // where O.[[Prototype]] is the prototype of the object
    
    // initialization of the newly created object
    // applying the F.[[Call]]; pass:
    // as this value – newly created object - O,
    // arguments are the same as initialParameters for F
    R = F.[[Call]](initialParameters); this === O;
    // where R is the returned value of the [[Call]]
    // in JS view it looks like:
    // R = F.apply(O, initialParameters);
    
    // if R is an object
    return R
    // else
    return O

    Note two major features:

    First, the prototype of the created object is taken from the prototype property of a function on the current moment (it means that the prototype of two created objects from one constructor can vary since the prototype property of a function can also vary).

    Secondly, as we have mentioned above, if at object initialization the [[Call]] has returned an object, exactly it is used as the result of the whole new expression:

    function A() {}
    A.prototype.x = 10;
    
    var a = new A();
    console.log(a.x); // 10 – by delegation, from the prototype
    
    // set .prototype property of the
    // function to new object; why explicitly
    // to define the .constructor property,
    // will be described below
    A.prototype = {
      constructor: A,
      y: 100
    };
    
    var b = new A();
    // object "b" has new prototype
    console.log(b.x); // undefined
    console.log(b.y); // 100 – by delegation, from the prototype
    
    // however, prototype of the "a" object
    // is still old (why - we will see below)
    console.log(a.x); // 10 - by delegation, from the prototype
    
    function B() {
      this.x = 10;
      return new Array();
    }
    
    // if "B" constructor had not return
    // (or was return this), then this-object
    // would be used, but in this case – an array
    var b = new B();
    console.log(b.x); // undefined
    console.log(Object.prototype.toString.call(b)); // [object Array]

    Let’s consider a prototype deeply in detail.

    Prototype

    Every object has a prototype (exceptions can be with some system objects). Communication with a prototype is organized via the internal, implicit and inaccessible directly [[Prototype]] property. A prototype can be either an object, or the null value.

    Property constructor

    In the above example there are two important points. The first relates to constructor property of the function’s prototype property.

    As we can see in algorithm of function objects creation, constructor property is set to function’s prototype property at function creation. The value of this property is the circular reference to the function itself:

    function A() {}
    var a = new A();
    console.log(a.constructor); // function A() {}, by delegation
    console.log(a.constructor === A); // true

    Often in this case there is a misunderstanding — constructor property is incorrectly treated as own property of the created object. However as we have seen, this property belongs to a prototype and is accessible to object via inheritance.

    Via the inherited constructor property instances can indirectly get the reference to the prototype object:

    function A() {}
    A.prototype.x = new Number(10);
    
    var a = new A();
    console.log(a.constructor.prototype); // [object Object]
    
    console.log(a.x); // 10, via delegation
    // the same as a.[[Prototype]].x
    console.log(a.constructor.prototype.x); // 10
    
    console.log(a.constructor.prototype.x === a.x); // true

    Notice though, that both constructor and prototype properties of the function can be redefined after the object is created. In this case the object looses the reference via the mechanism above.

    If we add new or modifiy existing property in the original prototype via the function’s prototype property, instances will see the newly added properties.

    However, if we change function’s prototype property completely (via assigning a new object), the reference to the original constructor (as well as to the original prototype) is lost. This is because we create the new object which does not have constructor property:

    function A() {}
    A.prototype = {
      x: 10
    };
    
    var a = new A();
    console.log(a.x); // 10
    console.log(a.constructor === A); // false!

    Therefore, this reference should be restored manually:

    function A() {}
    A.prototype = {
      constructor: A,
      x: 10
    };
    
    var a = new A();
    console.log(a.x); // 10
    console.log(a.constructor === A); // true

    Notice though that the restored manually constructor property, in contrast with the lost original, has no attribute {DontEnum} and, as consequence, is enumerable in the for..in loop over the A.prototype.

    In ES5 was introduced the ability of controlling enumerable state of properties via the [[Enumerable]] attribute.

    var foo = {x: 10};
    
    Object.defineProperty(foo, "y", {
      value: 20,
      enumerable: false // aka {DontEnum} = true
    });
     
    console.log(foo.x, foo.y); // 10, 20
    
    for (var k in foo) {
      console.log(k); // only "x"
    }
    
    var xDesc = Object.getOwnPropertyDescriptor(foo, "x");
    var yDesc = Object.getOwnPropertyDescriptor(foo, "y");
    
    console.log(
      xDesc.enumerable, // true
      yDesc.enumerable  // false
    );

    Explicit prototype and implicit [[Prototype]] properties

    Often prototype of an object is incorrectly confused with explicit reference to the prototype via the function’s prototype property. Yes, really, it references to the same object, as object’s [[Prototype]] property:

    a.[[Prototype]] ----> Prototype <---- A.prototype

    Moreover, [[Prototype]] of an instance gets its value from exactly the prototype property of the constructor — at object’s creation.

    However, replacing prototype property of the constructor does not affect the prototype of already created objects. It’s only the prototype property of the constructor that is changed! It means that new objects will have a new prototype. But already created objects (before the prototype property was changed), have reference to the old prototype and this reference cannot be changed already:

    // was before changing of A.prototype
    a.[[Prototype]] ----> Prototype <---- A.prototype
    
    // became after
    A.prototype ----> New prototype // new objects will have this prototype
    a.[[Prototype]] ----> Prototype // reference to old prototype

    Example:

    function A() {}
    A.prototype.x = 10;
    
    var a = new A();
    console.log(a.x); // 10
    
    A.prototype = {
      constructor: A,
      x: 20
      y: 30
    };
    
    // object "а" delegates to
    // the old prototype via
    // implicit [[Prototype]] reference
    console.log(a.x); // 10
    console.log(a.y) // undefined
    
    var b = new A();
    
    // but new objects at creation
    // get reference to new prototype
    console.log(b.x); // 20
    console.log(b.y) // 30

    Therefore, sometimes arising statements in articles on JavaScript claiming that “dynamic changing of the prototype will affect all objects and they will have that new prototype” is incorrect. New prototype will have only new objects which will be created after this changing.

    The main rule here is: the object’s prototype is set at the moment of object’s creation and after that cannot be changed to new object. Using the explicit prototype reference from the constructor if it still refers to the same object, it is possible only to add new or modify existing properties of the object’s prototype.

    Non-standard __proto__ property

    However, some implementations, for example, SpiderMonkey, provide explicit reference to object’s prototype via the non-standard __proto__ property:

    function A() {}
    A.prototype.x = 10;
    
    var a = new A();
    console.log(a.x); // 10
    
    var __newPrototype = {
      constructor: A,
      x: 20,
      y: 30
    };
    
    // reference to new object
    A.prototype = __newPrototype;
    
    var b = new A();
    console.log(b.x); // 20
    console.log(b.y); // 30
    
    // "a" object still delegates
    // to the old prototype
    console.log(a.x); // 10
    console.log(a.y); // undefined
    
    // change prototype explicitly
    a.__proto__ = __newPrototype;
    
    // now "а" object references
    // to new object also
    console.log(a.x); // 20
    console.log(a.y); // 30
    Note, ES5 introduced Object.getPrototypeOf(O) method, which directly returns the [[Prototype]] property of an object — the original prototype of the instance. However, in contrast with __proto__, being only a getter, it does not allow to set the prototype.

    var foo = {};
    Object.getPrototypeOf(foo) == Object.prototype; // true
    

    Object is independent from its constructor

    Since the prototype of an instance is independent from the constructor and the prototype property of the constructor, the constructor after its main purpose — creation of the object — can be removed. The prototype object will continue to exist, being referenced via the [[Prototype]] property:

    function A() {}
    A.prototype.x = 10;
    
    var a = new A();
    console.log(a.x); // 10
    
    // set "А" to null - explicit
    // reference on constructor
    A = null;
    
    // but, still possible to create
    // objects via indirect reference
    // from other object if
    // .constructor property has not been changed
    var b = new a.constructor();
    console.log(b.x); // 10
    
    // remove implicit reference
    // after it `a.constructor`, and `b.constructor`
    // will point to the default Object function, but not `A`
    delete a.constructor.prototype.constructor;
    
    // it is not possible to create objects
    // of "А" constructor anymore, but still
    // there are two such objects which
    // still have reference to their prototype
    console.log(a.x); // 10
    console.log(b.x); // 10

    Feature of instanceof operator

    With the explicit reference to a prototype — via the prototype property of the constructor, the work of the instanceof operator is related.

    This operator works exactly with the prototype chain of an object but not with the constructor itself. Take this into account, since there is often misunderstanding at this place. That is, when there is a check:

    if (foo instanceof Foo) {
      ...
    }

    it does not mean the check whether the object foo is created by the Foo constructor!

    All the instanceof operator does is only takes the value of the Foo.prototype property and checks its presence in the prototype chain of foo, starting from the foo.[[Prototype]]. The instanceof operator is activated by the internal [[HasInstance]] method of the constructor.

    Let’s see it on the example:

    function A() {}
    A.prototype.x = 10;
    
    var a = new A();
    console.log(a.x); // 10
    
    console.log(a instanceof A); // true
    
    // if set A.prototype
    // to null...
    A.prototype = null;
    
    // ...then "a" object still
    // has access to its
    // prototype - via a.[[Prototype]]
    console.log(a.x); // 10
    
    // however, instanceof operator
    // can't work anymore, because
    // starts its examination from the
    //prototype property of the constructor
    console.log(a instanceof A); // error, A.prototype is not an object

    On the other hand, it is possible to create object by one constructor, but instanceof will return true on check with another constructor. All that is necessary is to set object’s [[Prototype]] property and prototype property of the constructor to the same object:

    function B() {}
    var b = new B();
    
    console.log(b instanceof B); // true
    
    function C() {}
    
    var __proto = {
      constructor: C
    };
    
    C.prototype = __proto;
    b.__proto__ = __proto;
    
    console.log(b instanceof C); // true
    console.log(b instanceof B); // false

    Prototype as a storage for methods and shared properties

    The most useful application of the prototype in ECMAScript is the storage of methods, default state and shared properties of objects.

    Indeed, objects can have their own states, but methods are usually the same. Therefore, methods, for optimization of a memory usage, are usually defined in the prototype. It means that all instances created by this constructor, always share the same method.

    function A(x) {
      this.x = x || 100;
    }
    
    A.prototype = (function () {
    
      // initializing context,
      // use additional object
    
      var _someSharedVar = 500;
    
      function _someHelper() {
        console.log('internal helper: ' + _someSharedVar);
      }
    
      function method1() {
        console.log('method1: ' + this.x);
      }
    
      function method2() {
        console.log('method2: ' + this.x);
        _someHelper();
      }
    
      // the prototype itself
      return {
        constructor: A,
        method1: method1,
        method2: method2
      };
    
    })();
    
    var a = new A(10);
    var b = new A(20);
    
    a.method1(); // method1: 10
    a.method2(); // method2: 10, internal helper: 500
    
    b.method1(); // method1: 20
    b.method2(); // method2: 20, internal helper: 500
    
    // both objects are use
    // the same methods from
    // the same prototype
    console.log(a.method1 === b.method1); // true
    console.log(a.method2 === b.method2); // true

    Reading and writing properties

    As we mentioned, reading and writing of properties are managed by the internal methods [[Get]] and [[Put]]. The methods are activated by property accessors — dot notation or brackets notation:

    // write
    foo.bar = 10; // [[Put]] is called
    
    console.log(foo.bar); // 10, [[Get]] is called
    console.log(foo['bar']); // the same

    Let’s show the work of these methods as a pseudo-code.

    [[Get]] method

    The [[Get]] method considers the properties from the prototype chain of object as well. Therefore properties of a prototype are accessible to object as own.

    O.[[Get]](P):
    
    // if there is own
    // property, return it
    if (O.hasOwnProperty(P)) {
      return O.P;
    }
    
    // else, analyzing prototype
    var __proto = O.[[Prototype]];
    
    // if there is no prototype (it is,
    // possible e.g. in the last link of the
    // chain - Object.prototype.[[Prototype]],
    // which is equal to null),
    // then return undefined;
    if (__proto === null) {
      return undefined;
    }
    
    // else, call [[Get]] method recursively -
    // now for prototype; i.e. go through prototype
    // chain: try to find property in the
    // prototype, after that – in a prototype of
    // the prototype and so on, until
    // [[Prorotype]] will be equal to null
    return __proto.[[Get]](P)

    Note, since the [[Get]] method in one of cases can return undefined, checks on variable presence, like the following are possible:

    if (window.someObject) {
      ...
    }

    Here, property someObject is not found in window, then in its prototype, in the prototype of the prototype etc., and in this case, by the algorithm, undefined value is returned.

    Notice, that for exactly presence the in operator is responsible. It also considers the prototype chain:

    if ('someObject' in window) {
      ...
    }

    It helps to avoid cases when, for example, someObject can be equal to false and the first check does not pass even if someObject exists.

    [[Put]] method

    The [[Put]] method in contrast creates or updates an own property of the object and shadows the property with the same name from the prototype.

    O.[[Put]](P, V):
    
    // if we can't write to
    // this property then exit
    if (!O.[[CanPut]](P)) {
      return;
    }
    
    // if object doesn't have such own,
    // property, then create it; all attributes
    // are empty (set to false)
    if (!O.hasOwnProperty(P)) {
      createNewProperty(O, P, attributes: {
        ReadOnly: false,
        DontEnum: false,
        DontDelete: false,
        Internal: false
      });
    }
    
    // set the value;
    // if property existed, its
    // attributes are not changed
    O.P = V
    
    return;

    For example:

    Object.prototype.x = 100;
    
    var foo = {};
    console.log(foo.x); // 100, inherited
    
    foo.x = 10; // [[Put]]
    console.log(foo.x); // 10, own
    
    delete foo.x;
    console.log(foo.x); // again 100, inherited
    Notice, it’s not possible to shadow inherited read-only property. Result of an assignment is just ignored. This is controlled by the [[CanPut]] internal method; see 8.6.2.3 of ES3.

    // For example, property "length" of
    // string objects is read-only; let's make a
    // string as a prototype of our object and try
    // to shadow the "length" property
    
    function SuperString() {
      /* nothing */
    }
    
    SuperString.prototype = new String("abc");
    
    var foo = new SuperString();
    
    console.log(foo.length); // 3, the length of "abc"
    
    // try to shadow
    foo.length = 5;
    console.log(foo.length); // still 3

    In strict mode of ES5 an attempt to shadow a non-writable property results a TypeError.

    Property accessors

    That’s said, internal methods [[Get]] and [[Put]] are activated by property accessors which in ECMAScript are available via the dot notation, or via the bracket notation. The dot notation is used when the property name is a valid identifier name and in advance known, bracket notation allows forming names of properties dynamically.

    var a = {testProperty: 10};
    
    console.log(a.testProperty); // 10, dot notation
    console.log(a['testProperty']); // 10, bracket notation
    
    var propertyName = 'Property';
    console.log(a['test' + propertyName]); // 10, bracket notation with dynamic property

    There is one important feature — property accessor always calls ToObject conversion for the object standing on left hand side from the property accessor. And because of this implicit conversion it is possible roughly speaking to say that “everything in JavaScript is an object” (however as we already know — of course not everything since there are also primitive things).

    If we use property accessor with a primitive value, we just create intermediate wrapper object with corresponding value. After the work is finished, this wrapper is removed.

    Example:

    var a = 10; // primitive value
    
    // but, it has access to methods,
    // just like it would be an object
    console.log(a.toString()); // "10"
    
    // moreover, we can even
    // (try) to create a new
    // property in the "а" primitive calling [[Put]]
    a.test = 100; // seems, it even works
    
    // but, [[Get]] doesn't return
    // value for this property, it returns
    // by algorithm - undefined
    console.log(a.test); // undefined

    So, why in this example “primitive” value a has access to the toString method, but has no to the newly created test property?

    The answer is simple:

    First, as we said, after the property accessor is applied, it is already not a primitive, but the intermediate object. In this case new Number(a) is used, which via delegation finds the toString method in the prototype chain:

    // Algorithm of evaluating a.toString():
    
    1. wrapper = new Number(a);
    2. wrapper.toString(); // "10"
    3. delete wrapper;

    Next, [[Put]] method also creates its own wrapper object when evaluating the test property:

    // Algorithm of evaluating a.test = 100:
    
    1. wrapper = new Number(a);
    2. wrapper.test = 100;
    3. delete wrapper;

    We see that in step 3 the wrapper is removed and its newly created test property is of course also — with removing the object itself.

    Then again [[Get]] is called where the property accessor creates again new wrapper which of course does not known anything about any test property:

    // Algorithm of evaluating a.test:
    
    1. wrapper = new Number(a);
    2. wrapper.test; // undefined

    That is the reference to properties/methods from a primitive value makes sense only for reading the properties. Also if any of primitive values often uses the access to properties, for economy of time resources, there is a sense directly to replace it with an object representation. And on the contrary — if values participate only in some small calculations which are not demanding the access to properties then more efficiently primitive values can be used.

    Inheritance

    As we know, ECMAScript uses delegating inheritance based on prototypes.

    Chaining, prototypes generate already mentioned prototype chain.

    Actually, all work for implementing delegation and the analysis of a prototype chain is reduced to the work of the mentioned above [[Get]] method.

    If you completely understand the simple algorithm of the [[Get]] method, the question on inheritance in JavaScript will disappear by itself and the answer to it will become clear.

    Often on forums when the talk comes about inheritance in JavaScript, I show as an example only one line of ECMAScript code which very exactly and accurate describes object structure of the language and shows delegation based inheritance. Indeed, we can do not create any constructors or objects but the whole language is already full of inheritance. The line of code is very simple:

    console.log(1..toString()); // "1"

    Now, when we know the algorithm of the [[Get]] method and property accessors, we can see what happens here:

    1. First, from a primitive value 1 the wrapper object as new Number(1) is created;

    2. Then the inherited method toString is called from this wrapper.

    Why the inherited? Because objects in ECMAScript can have own properties, and the created wrapper object, in this case, has no own toString method. Therefore, it inherits it from a prototype, i.e. Number.prototype.

    Notice the subtle case of the syntax. Two dots in the example above is not an error. The first dot is used for fractional part of a number, and the second one is already a property accessor:

    1.toString(); // SyntaxError!
    
    (1).toString(); // OK
    
    1 .toString(); // OK (space after 1)
    
    1..toString(); // OK
    
    1['toString'](); // OK

    Prototype chain

    Let’s show how to create these prototype chains for the user-defined objects. It is quite simple:

    function A() {
      console.log('A.[[Call]] activated');
      this.x = 10;
    }
    A.prototype.y = 20;
    
    var a = new A();
    console.log([a.x, a.y]); // 10 (own), 20 (inherited)
    
    function B() {}
    
    // the easiest variant of prototypes
    // chaining is setting child
    // prototype to new object created,
    // by the parent constructor
    B.prototype = new A();
    
    // fix .constructor property, else it would be А
    B.prototype.constructor = B;
    
    var b = new B();
    console.log([b.x, b.y]); // 10, 20, both are inherited
    
    // [[Get]] b.x:
    // b.x (no) -->
    // b.[[Prototype]].x (yes) - 10
    
    // [[Get]] b.y
    // b.y (no) -->
    // b.[[Prototype]].y (no) -->
    // b.[[Prototype]].[[Prototype]].y (yes) - 20
    
    // where b.[[Prototype]] === B.prototype,
    // and b.[[Prototype]].[[Prototype]] === A.prototype

    This approach has two features.

    First, B.prototype will contain x property. At first glance, seems that it is not correct, since x property is defined in A as own and is expected to be own as well in objects of the B constructor.

    In a case of prototypal inheritance though it is normal situation, since the descendant object, if has no such own property delegates to a prototype. The idea behind this is that probably, objects created by the B constructor do not need x property. In contrast, in the class based model, all properties are copied to the class-descendant.

    However, if nevertheless it is needed (emulating class-based approach) that x property be own for the objects created by B constructor, there are some techniques for this, one of which we will show below.

    Secondly, that is already not a feature but the disadvantage — the code of the constructor is also executed when the descendant prototype is created. We can see that the message "A.[[Call]] activated" is shown twice — when the object created by the A constructor is used for B.prototype and also at creation of object a object itself!

    A more critical example is a thrown exception in the parent constructor: perhaps, for the real objects created by this constructor such checks are needed, but obviously, the same case is completely unacceptable with using these parent objects as prototypes:

    function A(param) {
      if (!param) {
        throw 'Param required';
      }
      this.param = param;
    }
    A.prototype.x = 10;
    
    var a = new A(20);
    console.log([a.x, a.param]); // 10, 20
    
    function B() {}
    B.prototype = new A(); // Error

    Besides, heavy calculations in the parent constructor can also be considered as disadvantage of this approach.

    To solve these “features” and issues, today programmers use standard pattern for chaining the prototypes, which we show below. The main goal of this trick consists in creation of the intermediate wrapper constructor which chains the needed prototypes.

    function A() {
      console.log('A.[[Call]] activated');
      this.x = 10;
    }
    A.prototype.y = 20;
    
    var a = new A();
    console.log([a.x, a.y]); // 10 (own), 20 (inherited)
    
    function B() {
      // or simply A.apply(this, arguments)
      B.superproto.constructor.apply(this, arguments);
    }
    
    // inheritance: chaining prototypes
    // via creating empty intermediate constructor
    var F = function () {};
    F.prototype = A.prototype; // reference
    B.prototype = new F();
    B.superproto = A.prototype; // explicit reference to ancestor prototype, "sugar"
    
    // fix .constructor property, else it would be A
    B.prototype.constructor = B;
    
    var b = new B();
    console.log([b.x, b.y]); // 10 (own), 20 (inherited)

    Notice how we create own property x on b instance: we call parent constructor via the B.superproto.constructor reference in context of newly created object.

    We have fixed also the issue with non-needed call of the parent constructor for creating the descendant prototype. Now the message "A.[[Call]] activated" is shown when is needed.

    And for not to repeat every time the same actions of prototypes chaining (creation of the intermediate constructor, setting this superproto sugar, restoring the original constructor etc.), this template can be encapsulated in the convenient util function, which purpose is to chain prototypes regardless the concrete names of constructors:

    function inherit(child, parent) {
      var F = function () {};
      F.prototype = parent.prototype
      child.prototype = new F();
      child.prototype.constructor = child;
      child.superproto = parent.prototype;
      return child;
    }

    Accordingly, inheritance:

    function A() {}
    A.prototype.x = 10;
    
    function B() {}
    inherit(B, A); // chaining prototypes
    
    var b = new B();
    console.log(b.x); // 10, found in the A.prototype

    There are many variations of such wrappers (in respect of syntax); however, all of them are reduced to the actions described above.

    For example, we can optimize the previous wrapper if we will put intermediate constructor outside (thus, only one function will be created), thereby, reusing it:

    var inherit = (function(){
      function F() {}
      return function (child, parent) {
        F.prototype = parent.prototype;
        child.prototype = new F;
        child.prototype.constructor = child;
        child.superproto = parent.prototype;
        return child;
      };
    })();

    Since the real prototype of an object is the [[Prototype]] property, it means that the F.prototype can be easily changed and reused, because child.prototype, being created via new F, will get its [[Prototype]] from the the current value of child.prototype:

    function A() {}
    A.prototype.x = 10;
    
    function B() {}
    inherit(B, A);
    
    B.prototype.y = 20;
    
    B.prototype.foo = function () {
      console.log("B#foo");
    };
    
    var b = new B();
    console.log(b.x); // 10, is found in A.prototype
    
    function C() {}
    inherit(C, B);
    
    // and using our "superproto" sugar
    // we can call parent method with the same name
    
    C.prototype.foo = function () {
      C.superproto.foo.call(this);
      console.log("C#foo");
    };
    
    var c = new C();
    console.log([c.x, c.y]); // 10, 20
    
    c.foo(); // B#foo, C#foo
    Note, that ES5 has standardized this util function for better prototypes chaining. It is the Object.create method.

    Simplified version in ES3 can nearly be implemented in the following way:

    Object.create ||
    Object.create = function (parent, properties) {
      function F() {}
      F.prototype = parent;
      var child = new F;
      for (var k in properties) {
        child[k] = properties[k].value;
      }
      return child;
    }

    Usage:

    var foo = {x: 10};
    var bar = Object.create(foo, {y: {value: 20}});
    console.log(bar.x, bar.y); // 10, 20
    

    For details see this chapter.

    Also, all existing variations of imitations of “classical inheritance in JS” are based on this principle. Now we see, that in fact it is even not an “imitation of class based inheritance”, but simply a convenient code reuse for chaining prototypes.

    Notice: in ES6 the concept of a “class” is standardized, and is implemented as exactly a syntactic sugar over the constructor functions as described above. From this viewpoint prototype chains become as an implementation detail of the class-based inheritance:

    // ES6
    class Foo {
      constructor(name) {
        this._name = name;
      }
    
      getName() {
        return this._name;
      }
    }
    
    class Bar extends Foo {
      getName() {
        return super.getName() + ' Doe';
      }
    }
    
    var bar = new Bar('John');
    console.log(bar.getName()); // John Doe
    

    Conclusion

    This article has turned out big enough and detailed. I hope that its material is useful and has dispelled some doubts regarding ECMAScript. If you have any questions or additions, they as always can be discussed in comments.

    Additional literature


    Translated by: Dmitry Soshnikov with additions by Garrett Smith.
    Published on: 2010-03-04

    Originally written by: Dmitry Soshnikov [ru, read »]
    Originally published on: 2009-09-12 [ru]

Write a Comment

Comment

60 Comments

  1. “console.log(a.constructor.prototype); // [object Object]”
    Really is
    console.log(a.constructor.prototype); // A { x: [Number: 10] }

  2. In the example for the section “Object is independent from its constructor” there are two delete statements:

    // remove both implicit references
    delete a.constructor.prototype.constructor;
    delete b.constructor.prototype.constructor;
    

    I believe the second statement
    a) is unnecessary (for the purpose of this specific example)
    b) does not do what was probably expected (according to the comment to the code)

    Reason:

    Since both a.[[Prototype]] and b.[[Prototype]] initially point to the same A.prototype object then the first delete statement already breaks the link that object b could use to point to its initial constructor A via b.[[Prototype]].constructor since their common [[Prototype]].constructor has gone.

    What is not obvious is that after a.prototype.constructor property is deleted, both a.prototype.constructor and b.prototype.constructor accessors return not null but “default constructor” instead. That is Object constructor function.

    So the second delete statement actually deletes Object.prototype.constructor property.

    One can see the actual results with the slightly modified code (shown as the comments):

    delete a.constructor.prototype.constructor;
    
    console.log("b's constructor", b.constructor); // b's constructor function Object() { [native code] }
    console.log("a's constructor", a.constructor); // a's constructor function Object() { [native code] }
    
    delete a.constructor.prototype.constructor;
    
    console.log("b's constructor", b.constructor); // b's constructor undefined
    console.log("a's constructor", a.constructor); // a's constructor undefined
    
  3. // fix .constructor property, else it would be А
    B.prototype.constructor = B;

    Could you please elaborate on..
    What do you mean by above and how that make a difference in first most example ?

  4. @KRISHNA CHANDU AKULA, the constructor property by inheritance chain would still find A:

    function A() {}
    
    function B() {}
    B.prototype = new A();
    
    let b = new B();
    
    console.log(b.constructor); // A
    

    This happens because B.prototype is assigned an instance of A. This instance of A inherits from A.prototype, where eventually the constructor property is found:

    console.log(
      b.hasOwnProperty('constructor'), // false
    
      b.__proto__ === B.prototype, // true
      b.__proto__.hasOwnProperty('constructor'), // false
    
      b.__proto__.__proto__ === A.prototype, // true
      b.__proto__.__proto__.hasOwnProperty('constructor'), // true
      A.prototype.constructor === A, // true
    
      b.__proto__.__proto__.constructor === b.constructor, // true
      b.constructor === A // true
    );
    
  5. Very good article, thank you very much!
    I am about to write one myself, although it will be much shorter 🙂

  6. I read some articles in chinese, some of them say that user-defined object is another object type, the others say that user-defined object belongs to host object. But, you say user-defined object belongs to native object; it’s hard for me to distinguih them.

  7. @rookieLink

    A native object is the one which semantics is fully defined by the ECMAScript spec.

    const point = {x: 10, y: 20}; // A native object
    

    A host object is the one provided by the host, i.e. the environment where ECMAScript engine is used in. Examples: alert function in Browser is a host object, since it’s not defined in the spec.

    A built-in object is a native object, which is defined prior program execution by the engine itself.

  8. Hello. Thanks for great articles 🙂
    I have a question about make intermediate function. We can do same thing without intermediate function for example like this. What is difference between intermediate wrapper and my example?

    function A() {
        console.log("A class's constructer call");
        this.x = 10;
    }
    
    A.prototype.y = 20;
    
    function B() {
        this.super.apply(this, arguments);
    }
    
    B.prototype.__proto__ = A.prototype;
    B.prototype.super = A;
    B.prototype.constructor = B;
    
    var c = new B();
    console.log(c);
  9. @Murad Sofiyev, thanks for the feedback. Yes, this would work too, as long as you have access to the __proto__ directly. It’s just recently standardized (even though existed for years in many implementations), but direct usage of it is not recommended.