JavaScript - shawfdong/hyades GitHub Wiki

JavaScript is not a classical language, but a prototypal language. In Javascript, there is no class; objects inherit directly from other objects. Here we use the REPL (Read-Eval-Print-Loop) of node.js to help us understand some of JavaScript's confusing features.

Except simple types, all values, including functions, are objects. Objects in JavaScript are mutable keyed collections; simple types are immutable.

Object is a function object whose name is Object. What a mouthful! It is a constructor, intended be used with the new prefix. By convention, constructors are kept in variables with a capitalized name.

> Object
[Function: Object]
> typeof Object
'function'

Every object is linked to a prototype object from which it can inherit properties. All objects created from object literals are linked to Object.prototype, an object that comes standard with JavaScript. Object.prototype is an empty object to start with.

> Object.prototype
{}
> typeof Object.prototype
'object'

Let's augment Object.prototype:

> Object.prototype.foo = 'bar';
'bar'
> var empty_object = {};
undefined
> empty_object['foo']
'bar'
> empty_object.hasOwnProperty('foo')
false
> 'a'.foo
'bar'
> var a = new Object();
undefined
> a
{}
> a.foo
'bar'

Function is a function object whose name is Function. It is a constructor as well.

> Function
[Function: Function]
> typeof Function
'function'

Function objects are linked to Function.prototype, which is itself linked to Object.prototype. Function.prototype is a function whose name is Empty.

> Function.prototype
[Function: Empty]
> typeof Function.prototype
'function'
> Function.foo
'bar'

Let's augment Function.prototype:

> Function.prototype['baz'] = 'qux';
'qux'
> Function.prototype
{ [Function: Empty] baz: 'qux' }
> var empty_function = function () {};
undefined
> empty_function.foo
'bar'
> empty_function.baz
'qux'

Every function object is also created with a prototype property. Its value is an object with a constructor property whose value is the function. This is distinct from the hidden link to Function.prototype.

> empty_function.prototype
{}
> empty_function.prototype.constructor
[Function]
> empty_function.prototype.constructor === empty_function
true
> empty_function.constructor
[Function: Function]
> empty_function.constructor === Function
true

By comparison:

> empty_object.prototype
undefined
> empty_object.constructor
[Function: Object]
> empty_object.constructor === Object
true
> a.constructor
[Function: Object]
> 'a'.constructor
[Function: String]

Add a create method to the Object function:

if (typeof Object.create !== 'function') {
     Object.create = function (o) {
         var F = function () {};
         F.prototype = o;
         return new F();
     };
}

Add a method method to the Function.prototype:

Function.prototype.method = function (name, func) {
    if (!this.prototype[name]) {
        this.prototype[name] = func;
        return this;
    }
};
> Number.method('integer', function (  ) {
.....     return Math[this < 0 ? 'ceil' : 'floor'](this);
..... });
[Function: Number]
> Number
[Function: Number]
> Number.prototype
{ integer: [Function] }
> 1.5.integer()
1

Pseudoclassical pattern: JavaScript is conflicted about its prototypal nature. Its prototype mechanism is obscured by some complicated syntactic business that looks vaguely classical. Instead of having objects inherit directly from other objects, an unnecessary level of indirection is inserted such that objects are produced by constructor functions.

var Mammal = function (name) {
    this.name = name;
};

Mammal.prototype.get_name = function (  ) {
    return this.name;
};

Mammal.prototype.says = function (  ) {
    return this.saying || '';
};
var Cat = function (name) {
    this.name = name;
    this.saying = 'meow';
};

Cat.prototype = new Mammal(  );

Cat.prototype.purr = function (n) {
    var i, s = '';
    for (i = 0; i < n; i += 1) {
        if (s) {
            s += '-';
        }
        s += 'r';
    }
    return s;
};

Cat.prototype.get_name = function (  ) {
    return this.says(  ) + ' ' + this.name + ' ' + this.says(  );
};
> var myMammal = new Mammal('Herb the Mammal');
undefined
> myMammal.get_name();
'Herb the Mammal'
> myMammal
{ name: 'Herb the Mammal' }
> myMammal.name
'Herb the Mammal'
> myMammal.prototype
undefined

Note that it is the constructor function, not the object itself, that has the property prototype. However,

> myMammal.__proto__
{ get_name: [Function], says: [Function] }
> Object.getPrototypeOf(myMammal)
{ get_name: [Function], says: [Function] }
> myMammal.__proto__ === Mammal.prototype
true
> var myCat = new Cat('Henrietta');
undefined
> myCat.__proto__
{ name: undefined,
  purr: [Function],
  get_name: [Function] }

Equality

> 5 == '5'
true
> 5 === '5'
false
> 0 == ''
true

References

⚠️ **GitHub.com Fallback** ⚠️