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

Read this article in: Russian.

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. Interested persons can find the first part here: ECMA-262-3 in detail. Chapter 7.1. OOP: The general theory.

So, having passed (and maybe, considerable) the way of highlights of the general theory, we at last have reached the ECMAScript itself. Now, when we know its ideology, let’s make once again accurate definition regarding OOP which it is possible to use in discussions on forums or in articles:

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.

Though ECMAScript is the 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.

Totally 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, other and consists of a base object and a property name. List type describes behavior of the arguments list (in a new expression and a functions call). Completion type in turn is used for an explanation of behavior break, continue, return and throw statements.

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 prototypes, no less than constructor objects (it will be considered below).

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.

alert(typeof null); // "object"

And the reason is that the typeof operator returns the value taken from standard table which statements: “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 (which means, “undefined or initial value”), is used in mostly where objects appear, i.e. is an essence closely related to objects (meaning the null reference to object, probably reserved a place for the future purposes). But, in some drafts (for example, in not released ECMAScript4 aka JavaScript 2.0), 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.

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.

Keys of objects are called as properties. Properties are containers for primitive values and other objects. In the case when the Type of object is function (as we will see in more detailed below), such properties are called as 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)
    alert('method x.c');
  }
};

alert(x.a); // 10
alert(x.b); // [object Object]
alert(x.b.z); // 100
x.c(); // 'method x.c'

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, alert, etc.

Also the specification defines a number of objects of type Object corresponding to some primitive types (i.e., being object representation of a primitive value; roughly speaking it is possible to name these objects as “subtypes” of Object type). These are following objects:

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

Such objects are created with corresponding built in constructors (about constructors — more below) and contain primitive value as one of internal properties. Object representation can be converted in primitive values (as a rule applying corresponding constructors as functions, without the new operator) and back.

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
с = Boolean(c);
d = String(d);
e = Number(e);

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

Besides objects corresponded with primitive values, 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; their distinction from each other is implemented by presence and values of certain internal properties which we will discuss below.

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;
alert([foo, getClass.call(foo)]); // 0, "[object Number]"

var bar = {};

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

// the same with Array name
Array = Number;

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

bar = [];

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

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

RegExp = Number;

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

bar = /(?!)/g;
alert([bar, getClass.call(bar)]); // /(?!)/g, "[object RegExp]"

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 = /ec/g;
  alert(re.lastIndex); // 0, 2, 0, 2
  alert(re.test("ecmascript")); // true, false, true, false
}

// in contrast with

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

In ES5 this issue has been solved and regexp literal also always creates a new object.

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 may be used on an 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"

alert(a['x']); // 10, but it's not empty

a['y'] = 20; // add new pair to "hash"
alert(a['y']); // 20

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

delete a['y']; // remove
alert(a['y']); // but key and value are still here – 20

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

var a = new String("foo");
a['length'] = 10;
alert(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 also is 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 submit 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. Though, repeat, in ECMAScript terminology and ideology, it is incorrect.

For converting into a primitive value the method valueOf is 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

alert([
  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);

alert(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
};

alert(c + d); // 100

Value of a valueOf method by default (if it is not redefined) can vary depending on object type. For some objects it returns this value (for example, Object.prototype.valueOf() and all who inherit this method from it), for others — any calculated value (for example, Date.prototype.valueOf(), returning the time of a date):

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

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

Also there is one more primitive representation of an object – a string representation. For this method toString is responsible which the same as valueOf in some operations is called automatically:

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

// in this operation
// toString method is
// called automatically
alert(a); // "__test"

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

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

It is necessary to note the toString method defined in Object.prototype: this method is especial and returns the value containing one of internal properties, exactly [[Class]]; but more detailed about this is below.

Along with ToPrimitive conversion which actions we saw above, there is also ToObject conversion which is contrast ToPrimitive, i.e. converts the value to the object type.

One of explicit ways to call ToObject is to use built in Object constructor as a function (however, 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 with 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 = [];
alert(a === new Object(a)); // true
alert(a === Object(a)); // true

Regarding calls of the built in constructors with new and without new operator, there is no the general rule and it depends on the constructor. So, for example Array or Function constructors produce identical results being called as a constructor (with new) and as a 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]

Besides conversions from object type into primitive and back, there are explicit and implicit conversions within the primitive types, for example from number to string:

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.

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 cycle;
  • {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.

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 the theory does not make such checks 100% proved. For example, [[Class]] property of the document.childNodes.item(…) method in IE returns “String” (in other implementations, “Function” is returned):

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

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

    Constructor is a Function object that creates objects applying its internal [[Construct]] method (the general constructor of all objects) and initializes the newly created object applying its [[Call]] internal method.

    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 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.alert(…) in IE:

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

    The internal [[Construct]] method is activated by the new operator applied to the constructor function. This method is responsible for memory allocation and creation of the object. If there are no arguments, call brackets 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();
    alert(a.x); // 10
    
    // explicit passing of
    // x argument value
    var b = new A(20);
    alert(b.x); // 20

    As it was mentioned in the article about this value, the given keyword inside the constructor (at initialization phase) is set to newly created object.

    Let’s see the behavior of the internal [[Construct]] method of function “F”:

    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

    Please note two major features: first, the prototype of the created object (more detailed about the prototype is below) 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, if at object initialization the [[Call]] has returned object (any object) it will be used as the result of new expression:

    function A() {}
    A.prototype.x = 10;
    
    var a = new A();
    alert(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
    alert(b.x); // undefined
    alert(b.y); // 100 – by delegation, from the prototype
    
    // however, prototype of the "a" object
    // is still old (why - we will see below)
    alert(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();
    alert(b.x); // undefined
    alert(Object.prototype.toString.call(b)); // [object Array]

    Let’s consider a prototype deeply in detail.

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

    In the above example there are two important points. The first relates to constructor property of function’s prototype property. As we can see in algorithm of function objects creation mentioned above, constructor property is set to function’s prototype property at creation; value of this property is the reference to function itself:

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

    Often in this case there is a mess — constructor property is incorrectly treated as own property of the created object, but as we saw (in algorithm of creation of functions) this property belongs to a prototype and is accessible to object via delegation.

    Through the constructor property (if it still references to the constructor and prototype property of the constructor, in turn, still references to an initial prototype) it is indirectly possible to receive the reference to an object prototype:

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

    If we add new or modifiy existing property in the prototype via the function’s prototype property, this is completely ok; in the example above new property “x” is created.

    However, if we change function’s prototype property completely, the reference to the original constructor (as well as to the original prototype) will be lost (because we create the new object which does not have constructor property):

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

    Therefore, this reference should be restored manually:

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

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

    With object’s prototype also sometimes there is a mess — it can be incorrectly treated as explicit reference of the function’s prototype property. Yes, really, it references the same object, as object’s [[Prototype]] property:

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

    Moreover, as we saw in algorithm of creation of objects, [[Prototype]] is set to the same object as prototype property of the constructor function. However, changing prototype property of the constructor does not affect on a prototype of already created objects. Only the prototype property of the constructor is changed. It means that new objects will have a new prototype. But already created objects (before the prototype property change), have reference to the old prototype and this reference cannot be changed anymore:

    // 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();
    alert(a.x); // 10
    
    A.prototype = {
      constructor: A,
      x: 20
      y: 30
    };
    
    // object "а" delegates to
    // the old prototype via
    // implicit [[Prototype]] reference
    alert(a.x); // 10
    alert(a.y) // undefined
    
    var b = new A();
    
    // but new objects at creation
    // get reference to new prototype
    alert(b.x); // 20
    alert(b.y) // 30

    Therefore, sometimes arising statements in articles on JavaScript claiming that “dynamic changing of the prototype (the complete changing of the prototype property of the constructor, assigning it to the new object) 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 completely new object. By using of the explicit prototype reference in the constructor if it still refers to the same object, it is possible just to add new or modify existing properties of the object’s prototype.

    This is by the way the feature of current ECMA-262 version which deviates from the general theory where it is said that the object can change its prototype at any moment.

    However, some implementations, for example, SpiderMonkey (and other), provide the explicit reference to object’s prototype via non-standard __proto__ property (analogy with the __class__ property in Python):

    function A() {}
    A.prototype.x = 10;
    
    var a = new A();
    alert(a.x); // 10
    
    var __newPrototype = {
      constructor: A,
      x: 20,
      y: 30
    };
    
    // reference to new object
    A.prototype = __newPrototype;
    
    var b = new A();
    alert(b.x); // 20
    alert(b.y); // 30
    
    // "a" object still delegates
    // to the old prototype
    alert(a.x); // 10
    alert(a.y); // undefined
    
    // change prototype explicitly
    a.__proto__ = __newPrototype;
    
    // now "а" object references
    // to new object also
    alert(a.x); // 20
    alert(a.y); // 30

    Moreover, in new version of the specification (ECMA-262-5), Object.getPrototypeOf(O) method is provided, which the same as __proto__ returns the reference to the [[Prototype]] property, an original prototype of the object.

    As the object’s prototype is independent from the constructor and its prototype property, theoretically and practically, the constructor after its main objective — creation of the object — can be removed. The object will continue to exist, referencing via [[Prototype]] to properties and methods added in the prototype via prototype property of the constructor:

    function A() {}
    A.prototype.x = 10;
    
    var a = new A();
    alert(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();
    alert(b.x); // 10
    
    // remove both implicit references
    delete a.constructor.prototype.constructor;
    delete b.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
    alert(a.x); // 10
    alert(b.x); // 10

    By the way, with the explicit reference to a prototype — via prototype property of the constructor (to be exact, with the prototype chain), work of the instanceof operator is related. Yes, indeed (I notice because in this case there’s often a mess) — this operator works with the prototype chain defined explicitly (or implicitly) in the constructor. That is when there is the following check:

    if (someObject instanceof SomeConstructor) {
      ...
    }

    it does not mean the check whether the object “someObject” is created by the “SomeConstructor” constructor. The instanceof operator only takes an object prototype — “someObject.[[Prototype]]” and checks its presence in the prototype chain, starring examination from the “SomeConstructor.prototype”. Operator instanceof is activated via the internal [[HasInstance]] method of the constructor.

    Let’s see it on the example:

    function A() {}
    A.prototype.x = 10;
    
    var a = new A();
    alert(a.x); // 10
    
    alert(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]]
    alert(a.x); // 10
    
    // however, instanceof operator
    // can't work anymore, because
    // starts its examination from the
    //prototype property of the constructor
    alert(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 necessary is to set object’s [[Prototype]] property and prototype property of the constructor to the same object:

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

    Therefore the instanceof operator, especially taking into account the duck typing, cannot be so effective.

    The most useful application of the prototype in ECMAScript is the storage of methods, default state and shared properties of objects. Really, objects can have their own states, but methods usually do not vary (though, this model fits ECMAScript to dynamic class based model: state is in object and behavior is in class, however, it is possible to augment other concrete objects). Therefore, methods, for optimization of a memory usage, are usually defined in the prototype. That means that on any quantity of objects created from this constructor, there is always one method to which all these objects can delegate. Moreover, at the prototype creation, it is possible to create an additional initializing context (in the form of surrounding function) and use additional encapsulated helper objects:

    function A(x) {
      this.x = x || 100;
    }
    
    A.prototype = (function () {
    
      // initializing context,
      // use additional object
    
      var _someSharedVar = 500;
    
      function _someHelper() {
        alert('internal helper: ' + _someSharedVar);
      }
    
      function method1() {
        alert('method1: ' + this.x);
      }
    
      function method2() {
        alert('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
    alert(a.method1 === b.method1); // true
    alert(a.method2 === b.method2); // true

    As it has been noted above, for reading and writing properties, internal methods [[Get]] and [[Put]] are used accordingly.

    The [[Get]] method thus analyzes a prototype chain of object; therefore properties of a prototype (any of links of a prototype chain) are accessible to object as own (via delegation).

    The [[Put]] method, in turn, writes an own property to the object. The next call of [[Get]] even if certain property exists in a prototype, will return value of this own property as it will be found directly in object.

    For descriptive reasons let’s show the work of these methods as a pseudo-code.

    [[Get]]:

    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, because of [[Get]] method in one of cases can return undefined, checks on variable presence, like the following are possible:

    if (window.someObject) {
      ...
    }

    Here, property “someObject” will not be found in “window”, then and in its prototype, in the prototype of the prototype etc. — the whole prototype chain will be analyzed, until it will be interrupted (i.e. one of prototypes will be equal to null; in this case it will be Object.prototype.[[Prototype]]); and in this case, by algorithm, undefined value will be returned.

    However, for the check above, it is better to use the in operator which also analyzes a prototype chain:

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

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

    [[Put]]:

    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;

    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};
    
    alert(a.testProperty); // 10, dot notation
    alert(a['testProperty']); // 10, bracket notation
    
    var propertyName = 'Property';
    alert(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, there is anything other as creation of 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
    alert(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
    alert(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 have found out, after the action of the property accessor, not the primitive value “a” but the intermediate created object new Number(a) will be used (which via delegation will find the toString method in the prototype):

    a.toString() ---->
    wrapper = new Number(a); ---->
    wrapper.toString() // "10"

    Secondly, [[Put]] method for the test property is called also regarding this intermediate wrapper:

    a.test = 100 ---->
    wrapper = new Number(a); ---->
    wrapper.test = 100

    After that, as it has been said, wrapper is removed and its newly written .test property is of course also.

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

    alert(a.test); ---->
    wrapper = new Number(a); ---->
    alert(wrapper.test); // undefined

    Therefore the basic conclusion is: the reference to properties/methods from a primitive value (with conversion to intermediate object) 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 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 characteristics then more efficiently primitive values can be used.

    So, as we already know (from the general theory and from analysis of some algorithms), in ECMAScript delegating inheritance based on prototypes is used.

    Chaining, prototypes generate already mentioned prototype chain.

    Actually, all work for implementing delegation and the analysis of a prototype chain is reduced to work of the mentioned above [[Get]] method. If you completely understand the simple algorithm of the [[Get]] method, the question about inheritance in JavaScript will disappear by itself and the answer to it will become clear.

    Often on forums when 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 constructor or object but whole the language is already “penetrated” with the inheritance. This line is very simple:

    alert(1..toString()); // "1"

    Now, when we precisely know the algorithm of the [[Get]] method and property accessors (in this case the dot notation), we can read this code line describing object essence of the ECMAScript: “from a primitive value 1 the wrapper object new Number(1) is created and the inherited method toString is called from this wrapper. Why the inherited? Because objects in ECMAScript can have own properties, and the wrapper object, in this case, has no own toString method, thus it inherits it from a prototype on which if nothing has been changed, references Number.prototype”.

    Pay attention, 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.

    It is necessary to know how to create these prototype chains for the user-defined objects. It is quite simple:

    function A() {
      alert('A.[[Call]] activated');
      this.x = 10;
    }
    A.prototype.y = 20;
    
    var a = new A();
    alert([a.x, a.y]); // 10 (own), 20 (inherited)
    
    function B() {}
    
    // the easiest variant of prototypes
    // chaining is setting child
    // prototype to new object created,
    // from parent constructor
    B.prototype = new A();
    
    // fix .constructor property, else it would be А
    B.prototype.constructor = B;
    
    var b = new B();
    alert([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

    However, this approach has two features. First, B.prototype will contain “x” property. On the first glance, seems that here something is wrong, “x” property is described in “A” as own and is expected in objects of the “B” constructor also as own. However, in a case of prototyping programming it is normal since the descendant object, on ideology, if has no such own property delegates to a prototype (probably, objects created from “B” will not need “x” property); in contrast with the class based model where all properties are copied in a class-descendant). On the other hand, if nevertheless it desirable that “x” property be own for the objects created from “B” constructor for this purpose there are some techniques one of which we will show below.

    Secondly that is already not a feature but a lack — if constructor will show some message (in an example above in the “A” constructor the message “A.[[Call]] activated”) this message will be shown for nothing when the object created by the “A” constructor is used as B.prototype (it is possible to see that this message has been shown twice — at creation of object “a” and at definition of the B.prototype).

    More critical similar case can be a thrown exception in the parent constructor can be: probably, for the real objects created from this constructor this check would fit, but the similar variant is completely impossible with using such parent objects as prototypes:

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

    Thirdly, difficult heavy calculations in the parent constructor can be also a lack; in this case, use of object of the parent constructor for inheritance becomes inefficient.

    For solving these “features/problems” today use a standard template for chaining the prototypes, suggested according to some information by Lasse Reichstein Nielsen (though, there is an opinion that this pattern was suggested by Douglas Crockford). The main goal of this trick consists in creation of the intermediate wrapper constructor which chains prototype property of the necessary constructors. Besides, it is possible to add some “syntactic sugar” for convenient access to the ancestor constructor:

    function A() {
      alert('A.[[Call]] activated');
      this.x = 10;
    }
    A.prototype.y = 20;
    
    var a = new A();
    alert([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();
    alert([b.x, b.y]); // 10 (own), 20 (inherited)

    Now property “x” of object “b” is native. We have achieved it via explicit call in constructor B of the parent constructor A (via B.superproto.constructor) applying this as object of constructor B — B.superproto.constructor.apply (this, arguments).

    Moreover, now the message “A.[[Call]] activated” from constructor A doesn’t “shoot empty” at creation of B.prototype (as B.prototype now is the object created from the empty constructor F and a prototype of this object is A.prototype). However, the message is still shown twice, but now the second time is already expected — we explicitly call the parent constructor A to create own-property “x” in the objects created by constructor B. By the way, nothing prevented us to call the constructor A in constructor B for own-property “x” creation in the first variant — then the message would be shown three times – twice are expected and one is “empty”.

    For not repeating each time of the same action for a prototype chaining (creation of the intermediate constructor, superproto, restoring the original constructor etc.), this template for chaining prototypes can be put in the universal general wrapper (the most simple variant is a function) which will chain prototypes irrespectively 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();
    alert(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;
      };
    })();

    As the real prototype of an object is a [[Prototype]] property, then F.prototype can vary, since child.prototype, being created via new F, will use its prototype property as internal [[Prototype]] property of the child.prototype:

    function A() {}
    A.prototype.x = 10;
    
    function B() {}
    inherit(B, A);
    
    B.prototype.y = 20;
    
    B.prototype.foo = function () {
      alert("B#foo");
    };
    
    var b = new B();
    alert(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.ptototype.foo = function () {
      C.superproto.foo.call(this);
      alert("C#foo");
    };
    
    var c = new C();
    alert([c.x, c.y]); // 10, 20
    
    c.foo(); // B#foo, C#foo

    Also, all existing variations of imitations of “classical inheritance in JS” are based on this principle. Why “classical”? The initial reason is a projection on OOP paradigm with (more habitual) static class based model. However, as we saw, the dynamic class based paradigm, in some variations, can be also similar to prototype based model. And secondly (that it is possible to justify and relate technically to a class based paradigm) is a condition that the prototype chain will be inflexible and invariant (thus, the chain physically is changeable). Also, it is possible to relate creation of the inherited own-properties in “classes”-descendants.

    Actually, it is even not an “imitation of class based inheritance”, as titles of some articles (and codes of various frameworks) sometimes say it; it is simply convenient code reuse for chaining prototypes. By the way, the last can be addressed to those who like to speak when see such titles in similar topics — “JavaScript is another, classes are not needed, use the native approach” — the described above wrapper — is the native approach. Replace in articles about “classical OOP in JavaScript” word “Class” with something another and all will be on their needed places.

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


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

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


Tags: , , , ,

 
 
 

11 Comments:

  1. Gravatar of Nicolas Nicolas
    20. March 2010 at 12:18

    Great article!

    BTW, I think I’ve found a typo that I described here: http://gist.github.com/338559

    Can’t wait for the Functions article to be translated!

    BR,

    Nico.


  2. Gravatar of Dmitry A. Soshnikov Dmitry A. Soshnikov
    20. March 2010 at 13:26

    @Nicolas

    Thanks, yeah, it was a typo of course; fixed.

    Yes, I’m planning translations of all chapters and now have already started translation of the “Chapter 4. Scope chain”. After that “Chapter 5. Functions” will follow.

    Dmitry.


  3. Gravatar of newbee newbee
    28. March 2010 at 01:47

    Hi Dmitry,

    Maybe you can use “Google Translate” as a help when translating these great articles:

    http://translate.google.com/translate?hl=en&sl=ru&tl=en&u=http%3A%2F%2Fdmitrysoshnikov.com%2Fecmascript%2Fru-chapter-5-functions%2F


  4. Gravatar of Dmitry A. Soshnikov Dmitry A. Soshnikov
    28. March 2010 at 12:54

    @newbee

    Hi, yeah it could be taken as a basis, but unfortunately all automatic translators don’t know special terminology and cannot produce correct sentences regarding exactly specific technology. So even after basic translation it is required to work on every sentence.

    Dmitry.


  5. Gravatar of John Merge John Merge
    7. April 2010 at 21:44

    Great article, as usual.
    I can not explain how much I appreciate your work! You should write a book – you already have a lot of wonderful stuff. It will definitely become best-seller.

    Thanks, and keep in this way!

    John


  6. Gravatar of Dmitry A. Soshnikov Dmitry A. Soshnikov
    7. April 2010 at 22:37

    @John Merge

    Thanks, John. And I am glad to see that quantity of interested in deep JS programmers are getting more and more.

    You should write a book – you already have a lot of wonderful stuff. It will definitely become best-seller.

    Yes, I have such plans. Now negotiations are continuing with several publishers. The audience is limited to already experienced in JS (and in programming in a whole) programmers, so it is very important to choose a publisher correctly.

    I think this book will be useful for every professional ECMAScript programmer.

    Dmitry.


  7. Gravatar of John Merge John Merge
    7. April 2010 at 22:39

    Dmitry,

    Your “inherit” function differs from those, used in some JavaScript libraries, for example YUI. Here is it:
    In your code:

    child._super = parent;

    In YUI they do the following:

    child._super = parent.prototype;

    Take a look here (search for “extend”): http://github.com/yui/yui2/blob/master/src/yahoo/js/Lang.js

    This is YUI2, but it is the same in YUI3: http://github.com/yui/yui3/blob/master/src/oop/js/oop.js

    What is your explanation?

    Thanks,
    John


  8. Gravatar of Dmitry A. Soshnikov Dmitry A. Soshnikov
    8. April 2010 at 12:10

    @John Merge

    Your “inherit” function differs from those, used in some JavaScript libraries

    Yes, maybe; as I mentioned in the article, there are a lot of such implementations of code reuse in respect of chaining prototypes.

    So, the reference to parent “class” can be easily set not to parent constructor itself, but to the prototype of an object (i.e. via explicit reference — parent.prototype). And it’s even better, since there is no need to repeat every time intermediate “.prototype.” property on accessing parent methods/properties. And at the same time we still have access to constructor function itself via “_super.constructor”.

    I know that this approach is used in many implementations and frameworks, but in this article it is just an example to show the main principles of how it works — then programmer could understand what is going on there, but not just use a useful pattern.

    But yeah, I think to change it on “parent.prototype” instead of “parent” — in respect of DRY code reuse, it is better.

    And regarding exactly code reuse I also like approach with using just “this._super()” to call the parent method with the same name. And it works for every method — in every child method “this._super()” is correctly set to needed method.

    This approach is also known (for every child method with the same name a wrapper is needed; and in this wrapper correct value of “this._super” is set, then called parent method with the same name, and then “this._super” is restored), although it is less efficient by performance.

    Also it is possible to implement “this._super” more efficiently if to use non-standard caller property and to store the name property for every added method. Then we can in calling “this._super()” to get correct parent context (via caller) and to call the method with the same name (having name property stored in function) from the parent prototype.

    Unfortunately, arguments.caller is deprecated in strict mode of the ECMA-262-5 (although, I don’t like strict mode itself). However, if you use your own system and sure in it, then you can use it on full force and this approach is very good for code reuse, at least much better than every time to repeat “ChildName.superclass.” as it is in many frameworks (e.g. in ExtJS). Much better to have:

    function doThat(arg) {
      // instead of
      // Child.superclass.doThat.call(this, arg)
      // we just do
      this._super(arg);
      // other actions
    }

    Dmitry.


  9. Gravatar of John Merge John Merge
    8. April 2010 at 13:14

    Nice!

    BTW, why do you dislike strict mode of the ECMA-262-5?

    John


  10. Gravatar of Dmitry A. Soshnikov Dmitry A. Soshnikov
    8. April 2010 at 18:18

    @John Merge

    why do you dislike strict mode of the ECMA-262-5

    If to be more exact, not a strict mode itself, but the splitting on strict and non-strict. Because exactly this fact (of splitting) may cause many useless holywars and debates on forums. Some will tell that professional code is only in strict, but it is not so.

    I of course understand reasons for which this feature is provided. The general is the deprecation of some features. Although, I have no idea how this voting was made — what to exclude and what do not.

    In this way Python did the migration from 2.* to 3.* version in more radical manner. They just stop to support the old stylistics and syntax constructs making some of them 3.* completely incompatible with 2.* (although, I think that before this migration there was also some notifications about deprecated things).

    But the thing is that even after the migration on new stylistics and syntax constructs, “use strict” can continue to exists as backward compatibility (as it is in Perl — ask any professional Perl programmer whether he uses strict mode – he’ll answer: “Yes of course”, but ask then “why?” — there will be no unequivocal answer), providing useless overloading in code. And of course the most funny answer is “Programming in strict mode is more professional”.

    So I am not against stylistics that used in strict mode, I just think that there is no much sense in splitting on strict and non-strict.

    I myself can easily use both stylistics including strict. That’s completely OK for me.

    But what I really don’t like in ES5 — the stylistics and new approach of Object’s methods. I again understand reasons for which the did so. It is sort of insurance from that user can simply overwrite e.g. method keys if it would be defined in Object.prototype.

    So they’ve decided to put these methods directly in Object constructor, but not in Object.prototype. What will again cause procedural stylistics instead of object-oriented. Moreover, there is already different stylistist for e.g. hasOwnProperty which is defined in Object.prototype — and the different stylistics for the same semantically entities (both are methods related to objects) is not so good approach.

    Having in ES5 control for [[Enumerable]] (and other) internal property (in ES3 it is {DontEnum}), in own project in which you are sure and completely trust (and therefore can use the language for full force without any limitations) the first thing which can be done, is defining the same methods in Object.prototype with {enumerable: false} descriptor.

    Compare e.g. this (abstract) example:

    var o = Object.freeze(
      Object.seel(
        Object.defineProperties(
          Object.create(proto),
          properties
        )
      )
    );

    with this one:

    var o = Object.create(proto)
      .defineProperties(properties)
      .seel()
      .freeze();

    Obviously this “Object.” prefix which we should repeat every time is not so good for code reuse and the whole stylistics in general looks worth in first case.

    But all this of course is just my own opinion ;)

    I wrote about it before: http://groups.google.ru/group/comp.lang.javascript/msg/7e6f16761ef5c38f?hl=en

    Dmitry.


  11. Gravatar of Dmitry A. Soshnikov Dmitry A. Soshnikov
    27. April 2010 at 13:58

    Thanks Garrett Smith for some English corrections.

    Also, as addition for corresponding section of this article, you can read similar Garrett’s article about property accessors — http://dhtmlkitchen.com/?category=/JavaScript/&date=2007/10/05/&entry=How-Property-Access-Works which puts to rest the myth of “everything in JS is an object”.

    Dmitry.


Leave a Reply

Code: For code you can use tags [js], [text], [ruby] and other.

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>