6 面向对象的程序设计

  • 理解对象
  • 创建对象
  • 继承

理解对象


In [3]:
// golbal define function alert
if((typeof alert) === 'undefined') {
    global.alert = function(message) {
        console.log(message);
    }
}

var person = new Object();
person.name = "Nicholas";
person.age = 29;
person.job = "Software Engineer";
person.sayName = function(){
    alert(this.name);
};

person.sayName();


Nicholas
Out[3]:
undefined

属性类型

数据属性

  • Configurable
  • Enumerable
  • Writable
  • Value

In [4]:
var person = {};
Object.defineProperty(person, "name", {
    writable: false,
    value: "Nicholas"
});

alert(person.name);
person.name = "Michael";
alert(person.name);


Nicholas
Nicholas
Out[4]:
undefined

In [5]:
var person = {};
Object.defineProperty(person, "name", {
    configurable: false,
    value: "Nicholas"
});

alert(person.name);
delete person.name;
alert(person.name);


Nicholas
Nicholas
Out[5]:
undefined

In [6]:
var person = {};
Object.defineProperty(person, "name", {
    configurable: false,
    value: "Nicholas"
});

//throws error
Object.defineProperty(person, "name", {
    configurable: true,
    value: "Nicholas"
});


TypeError: Cannot redefine property: name
    at Function.defineProperty (native)
    at evalmachine.<anonymous>:8:8
    at ContextifyScript.Script.runInThisContext (vm.js:25:33)
    at Object.exports.runInThisContext (vm.js:77:17)
    at run ([eval]:608:19)
    at onRunRequest ([eval]:379:22)
    at onMessage ([eval]:347:17)
    at emitTwo (events.js:106:13)
    at process.emit (events.js:191:7)
    at process.nextTick (internal/child_process.js:719:12)

访问器属性

  • Configurable
  • Enumerable
  • Get
  • Set

In [7]:
var book = {
    _year: 2004,
    edition: 1
};

Object.defineProperty(book, "year", {
    get: function(){
        return this._year;
    },
    set: function(newValue){

        if (newValue > 2004) {
            this._year = newValue;
            this.edition += newValue - 2004;

        }
    }
});

book.year = 2005;
alert(book.edition);   //2


2
Out[7]:
undefined

In [8]:
var book = {
    _year: 2004,
    edition: 1
};

//legacy accessor support
book.__defineGetter__("year", function(){
    return this._year;    
});

book.__defineSetter__("year", function(newValue){
    if (newValue > 2004) {
        this._year = newValue;
        this.edition += newValue - 2004;
    }    
});


book.year = 2005;
alert(book.edition);   //2


2
Out[8]:
undefined

定义多个属性


In [9]:
var book = {};
        
Object.defineProperties(book, {
    _year: {
        value: 2004
    },

    edition: {
        value: 1
    },

    year: {            
        get: function(){
            return this._year;
        },

        set: function(newValue){
            if (newValue > 2004) {
                this._year = newValue;
                this.edition += newValue - 2004;
            }                  
        }            
    }        
});

book.year = 2005;
alert(book.edition);   //1


1
Out[9]:
undefined

读取属性的特性


In [10]:
var book = {};
        
Object.defineProperties(book, {
    _year: {
        value: 2004
    },

    edition: {
        value: 1
    },

    year: {            
        get: function(){
            return this._year;
        },

        set: function(newValue){
            if (newValue > 2004) {
                this._year = newValue;
                this.edition += newValue - 2004;
            }                  
        }            
    }        
});

var descriptor = Object.getOwnPropertyDescriptor(book, "_year");
alert(descriptor.value);          //2004
alert(descriptor.configurable);   //false
alert(typeof descriptor.get);     //"undefined"

var descriptor = Object.getOwnPropertyDescriptor(book, "year");
alert(descriptor.value);          //undefined
alert(descriptor.enumerable);     //false
alert(typeof descriptor.get);     //"function"


2004
false
undefined
undefined
false
function
Out[10]:
undefined

创建对象

工厂模式


In [11]:
function createPerson(name, age, job){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function(){
        alert(this.name);
    };    
    return o;
}

var person1 = createPerson("Nicholas", 29, "Software Engineer");
var person2 = createPerson("Greg", 27, "Doctor");

person1.sayName();   //"Nicholas"
person2.sayName();   //"Greg"


Nicholas
Greg
Out[11]:
undefined

构造函数模型


In [12]:
function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function(){
        alert(this.name);
    };    
}

var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");

person1.sayName();   //"Nicholas"
person2.sayName();   //"Greg"

alert(person1 instanceof Object);  //true
alert(person1 instanceof Person);  //true
alert(person2 instanceof Object);  //true
alert(person2 instanceof Person);  //true

alert(person1.constructor == Person);  //true
alert(person2.constructor == Person);  //true

alert(person1.sayName == person2.sayName);  //false


Nicholas
Greg
true
true
true
true
true
true
false
Out[12]:
undefined

In [14]:
function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function(){
        alert(this.name);
    };
}

var person = new Person("Nicholas", 29, "Software Engineer");
person.sayName();   //"Nicholas"

Person("Greg", 27, "Doctor");  //adds to global
sayName();   //"Greg"

var o = new Object();
Person.call(o, "Kristen", 25, "Nurse");
o.sayName();    //"Kristen"


Nicholas
Greg
Kristen
Out[14]:
undefined

In [15]:
function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = sayName;
}

function sayName(){
    alert(this.name);
}

var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");

person1.sayName();   //"Nicholas"
person2.sayName();   //"Greg"

alert(person1 instanceof Object);  //true
alert(person1 instanceof Person);  //true
alert(person2 instanceof Object);  //true
alert(person2 instanceof Person);  //true

alert(person1.constructor == Person);  //true
alert(person2.constructor == Person);  //true

alert(person1.sayName == person2.sayName);  //true


Nicholas
Greg
true
true
true
true
true
true
true
Out[15]:
undefined

原型模式

我们创建的每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。


In [16]:
function Person(){
}

Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
    alert(this.name);
};

var person1 = new Person();
person1.sayName();   //"Nicholas"

var person2 = new Person();
person2.sayName();   //"Nicholas"

alert(person1.sayName == person2.sayName);  //true

alert(Person.prototype.isPrototypeOf(person1));  //true
alert(Person.prototype.isPrototypeOf(person2));  //true

//only works if Object.getPrototypeOf() is available
if (Object.getPrototypeOf){
    alert(Object.getPrototypeOf(person1) == Person.prototype);  //true
    alert(Object.getPrototypeOf(person1).name);  //"Nicholas"
}


Nicholas
Nicholas
true
true
true
true
Nicholas
Out[16]:
undefined

通过对象实例重写原型中的值:


In [17]:
function Person(){
}

Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
    alert(this.name);
};

var person1 = new Person();
var person2 = new Person();

person1.name = "Greg";
alert(person1.name);   //"Greg" - from instance
alert(person2.name);   //"Nicholas" - from prototype


Greg
Nicholas
Out[17]:
undefined

In [18]:
function Person(){
}

Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
    alert(this.name);
};

var person1 = new Person();
var person2 = new Person();

person1.name = "Greg";
alert(person1.name);   //"Greg" - from instance
alert(person2.name);   //"Nicholas" - from prototype

delete person1.name;
alert(person1.name);   //"Nicholas" - from the prototype


Greg
Nicholas
Nicholas
Out[18]:
undefined

hasOwnProperty():区分实例属性和原型属性:


In [19]:
function Person(){
}

Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
    alert(this.name);
};

var person1 = new Person();
var person2 = new Person();

alert(person1.hasOwnProperty("name"));  //false
alert("name" in person1);  //true

person1.name = "Greg";
alert(person1.name);   //"Greg" - from instance
alert(person1.hasOwnProperty("name"));  //true
alert("name" in person1);  //true

alert(person2.name);   //"Nicholas" - from prototype
alert(person2.hasOwnProperty("name"));  //false
alert("name" in person2);  //true

delete person1.name;
alert(person1.name);   //"Nicholas" - from the prototype
alert(person1.hasOwnProperty("name"));  //false
alert("name" in person1);  //true


false
true
Greg
true
true
Nicholas
false
true
Nicholas
false
true
Out[19]:
undefined

hasPrototypeProperty()只在属性存在于原型时返回true:


In [20]:
function hasPrototypeProperty(object, name){
    return !object.hasOwnProperty(name) && (name in object);
}

function Person(){
}

Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
    alert(this.name);
};

var person = new Person();        
alert(hasPrototypeProperty(person, "name"));  //true

person.name = "Greg";
alert(hasPrototypeProperty(person, "name"));  //false


true
false
Out[20]:
undefined

使用for-in循环,返回的是所有能够通过对象访问的、可枚举的属性,其中既包括存在于实例中的属性,也包括存在于原型中的属性:


In [21]:
var o = {
    toString : function(){
        return "My Object";
    }
}

for (var prop in o){
    if (prop == "toString"){
        alert("Found toString");
    }
}


Found toString
Out[21]:
undefined

Object.keys()取得对象上所有可枚举的实例属性


In [24]:
function Person(){
}

Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
    alert(this.name);
};

var keys = Object.keys(Person.prototype);
alert(keys);   //"name,age,job,sayName"

var p1 = new Person();
p1.name = "Rob";
p1.age = 31;
var p1keys = Object.keys(p1);
alert(p1keys);   //"name,age"


[ 'name', 'age', 'job', 'sayName' ]
[ 'name', 'age' ]
Out[24]:
undefined

getOwnPropertyNames()取得对象上所有实例属性,无论是否可枚举:


In [25]:
function Person(){
}

Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
    alert(this.name);
};

var keys = Object.getOwnPropertyNames(Person.prototype);
alert(keys);   //"constructor,name,age,job,sayName"


[ 'constructor', 'name', 'age', 'job', 'sayName' ]
Out[25]:
undefined

更简单的原型语法:


In [26]:
function Person(){
}

Person.prototype = {
    name : "Nicholas",
    age : 29,
    job: "Software Engineer",
    sayName : function () {
        alert(this.name);
    }
};

var friend = new Person();

alert(friend instanceof Object);  //true
alert(friend instanceof Person);  //true
alert(friend.constructor == Person);  //false
alert(friend.constructor == Object);  //true


true
true
false
true
Out[26]:
undefined

In [27]:
function Person(){
}

Person.prototype = {
    constructor : Person, //注意与上例区别
    name : "Nicholas",
    age : 29,
    job: "Software Engineer",
    sayName : function () {
        alert(this.name);
    }
};

var friend = new Person();

alert(friend instanceof Object);  //true
alert(friend instanceof Person);  //true
alert(friend.constructor == Person);  //true
alert(friend.constructor == Object);  //false


true
true
true
false
Out[27]:
undefined

In [28]:
function Person(){
}

Person.prototype = {
    constructor: Person,
    name : "Nicholas",
    age : 29,
    job : "Software Engineer",
    sayName : function () {
        alert(this.name);
    }
};

var friend = new Person();

Person.prototype.sayHi = function(){
    alert("hi");
};

friend.sayHi();   //"hi" - works!


hi
Out[28]:
undefined

调用构造函数时会为实例添加一个指向最初原型的Prototype指针,而把原型修改为另一个对象就等于切断了构造函数与最初原型之间的联系。记住:实例中的指针仅指向原型,而不指向构造函数:


In [29]:
function Person(){
}

var friend = new Person();

Person.prototype = {
    constructor: Person,
    name : "Nicholas",
    age : 29,
    job : "Software Engineer",
    sayName : function () {
        alert(this.name);
    }
};

friend.sayName();   //error


TypeError: friend.sayName is not a function
    at evalmachine.<anonymous>:16:8
    at ContextifyScript.Script.runInThisContext (vm.js:25:33)
    at Object.exports.runInThisContext (vm.js:77:17)
    at run ([eval]:608:19)
    at onRunRequest ([eval]:379:22)
    at onMessage ([eval]:347:17)
    at emitTwo (events.js:106:13)
    at process.emit (events.js:191:7)
    at process.nextTick (internal/child_process.js:719:12)
    at _combinedTickCallback (internal/process/next_tick.js:67:7)

通过原生对象的原型,不仅可以取得所有默认方法的引用,而且可以定义新方法:


In [30]:
alert(typeof Array.prototype.sort);         //"function"
alert(typeof String.prototype.substring);   //"function"

String.prototype.startsWith = function (text) {
    return this.indexOf(text) == 0;
};

var msg = "Hello world!";
alert(msg.startsWith("Hello"));   //true


function
function
true
Out[30]:
undefined

原型中所有属性是被很多实例共享的:


In [31]:
function Person(){
}

Person.prototype = {
    constructor: Person,
    name : "Nicholas",
    age : 29,
    job : "Software Engineer",
    friends : ["Shelby", "Court"],
    sayName : function () {
        alert(this.name);
    }
};

var person1 = new Person();
var person2 = new Person();

person1.friends.push("Van");

alert(person1.friends);    //"Shelby,Court,Van"
alert(person2.friends);    //"Shelby,Court,Van"
alert(person1.friends === person2.friends);  //true


[ 'Shelby', 'Court', 'Van' ]
[ 'Shelby', 'Court', 'Van' ]
true
Out[31]:
undefined

组合使用构造函数和原型模式


In [32]:
function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ["Shelby", "Court"];
}

Person.prototype = {
    constructor: Person,
    sayName : function () {
        alert(this.name);
    }
};

var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");

person1.friends.push("Van");

alert(person1.friends);    //"Shelby,Court,Van"
alert(person2.friends);    //"Shelby,Court"
alert(person1.friends === person2.friends);  //false
alert(person1.sayName === person2.sayName);  //true


[ 'Shelby', 'Court', 'Van' ]
[ 'Shelby', 'Court' ]
false
true
Out[32]:
undefined

动态原型模式

这里只在sayName()方法不存在的情况下,才会将它添加到原型中。


In [34]:
function Person(name, age, job){
        
    //properties
    this.name = name;
    this.age = age;
    this.job = job;

    //methods
    if (typeof this.sayName != "function"){

        Person.prototype.sayName = function(){
            alert(this.name);
        };

    }
}

var friend = new Person("Nicholas", 29, "Software Engineer");
friend.sayName();


Nicholas
Out[34]:
undefined

寄生构造函数模式


In [35]:
function Person(name, age, job){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function(){
        alert(this.name);
    };    
    return o;
}

var friend = new Person("Nicholas", 29, "Software Engineer");
friend.sayName();  //"Nicholas"


Nicholas
Out[35]:
undefined

In [36]:
function SpecialArray(){       
 
    //create the array
    var values = new Array();

    //add the values
    values.push.apply(values, arguments);

    //assign the method
    values.toPipedString = function(){
        return this.join("|");
    };

    //return it
    return values;        
}

var colors = new SpecialArray("red", "blue", "green");
alert(colors.toPipedString()); //"red|blue|green"

alert(colors instanceof SpecialArray);


red|blue|green
false
Out[36]:
undefined

继承

原型链


In [37]:
function SuperType(){
    this.property = true;
}

SuperType.prototype.getSuperValue = function(){
    return this.property;
};

function SubType(){
    this.subproperty = false;
}

//inherit from SuperType
SubType.prototype = new SuperType();

SubType.prototype.getSubValue = function (){
    return this.subproperty;
};

var instance = new SubType();
alert(instance.getSuperValue());   //true

alert(instance instanceof Object);      //true
alert(instance instanceof SuperType);   //true
alert(instance instanceof SubType);     //true

alert(Object.prototype.isPrototypeOf(instance));    //true
alert(SuperType.prototype.isPrototypeOf(instance)); //true
alert(SubType.prototype.isPrototypeOf(instance));   //true


true
true
true
true
true
true
true
Out[37]:
undefined

子类型需要覆盖超类的方法,或者需要添加超类型中不存在的方法。当不管怎样,给原型添加方法的代码一定要放在替换原型的语句之后:


In [38]:
function SuperType(){
    this.property = true;
}

SuperType.prototype.getSuperValue = function(){
    return this.property;
};

function SubType(){
    this.subproperty = false;
}

//inherit from SuperType
SubType.prototype = new SuperType();

//new method
SubType.prototype.getSubValue = function (){
    return this.subproperty;
};

//override existing method
SubType.prototype.getSuperValue = function (){
    return false;
};

var instance = new SubType();
alert(instance.getSuperValue());   //false


false
Out[38]:
undefined

演示刚刚把SuperType的实例赋值给原型,紧接着又将原型替换成一个对象字面量:


In [39]:
function SuperType(){
    this.property = true;
}

SuperType.prototype.getSuperValue = function(){
    return this.property;
};

function SubType(){
    this.subproperty = false;
}

//inherit from SuperType
SubType.prototype = new SuperType();

//try to add new methods - this nullifies the previous line
SubType.prototype = {
    getSubValue : function (){
        return this.subproperty;
    },

    someOtherMethod : function (){
        return false;
    }
};

var instance = new SubType();
alert(instance.getSuperValue());   //error!


TypeError: instance.getSuperValue is not a function
    at evalmachine.<anonymous>:28:16
    at ContextifyScript.Script.runInThisContext (vm.js:25:33)
    at Object.exports.runInThisContext (vm.js:77:17)
    at run ([eval]:608:19)
    at onRunRequest ([eval]:379:22)
    at onMessage ([eval]:347:17)
    at emitTwo (events.js:106:13)
    at process.emit (events.js:191:7)
    at process.nextTick (internal/child_process.js:719:12)
    at _combinedTickCallback (internal/process/next_tick.js:67:7)

原型链的一些问题

  • 引用类型值的原型属性会被所有实例共享
  • 在创建子类型的实例时,不能向超类型的构造函数传递参数

In [40]:
function SuperType(){
    this.colors = ["red", "blue", "green"];
}

function SubType(){            
}

//inherit from SuperType
SubType.prototype = new SuperType();

var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors);    //"red,blue,green,black"

var instance2 = new SubType();
alert(instance2.colors);    //"red,blue,green,black"


[ 'red', 'blue', 'green', 'black' ]
[ 'red', 'blue', 'green', 'black' ]
Out[40]:
undefined

借用构造函数

解决原型中包含引用类型值所带来的问题-借用构造函数技术:在子类构造函数内部调用超类构造函数:


In [41]:
function SuperType(){
    this.colors = ["red", "blue", "green"];
}

function SubType(){  
    //inherit from SuperType
    SuperType.call(this);
}

var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors);    //"red,blue,green,black"

var instance2 = new SubType();
alert(instance2.colors);    //"red,blue,green"


[ 'red', 'blue', 'green', 'black' ]
[ 'red', 'blue', 'green' ]
Out[41]:
undefined

向超类构造函数传递参数:


In [42]:
function SuperType(name){
    this.name = name;
}

function SubType(){  
    //inherit from SuperType passing in an argument
    SuperType.call(this, "Nicholas");

    //instance property
    this.age = 29;
}

var instance = new SubType();
alert(instance.name);    //"Nicholas";
alert(instance.age);     //29


Nicholas
29
Out[42]:
undefined

借用构造函数问题

方法都在构造函数中定义,因此函数复用就无从谈起了。而且,在超类型的原型中定义的方法,对子类而言是不可见的,结果所有类型都只能使用构造函数模式。

组合继承

  • 使用原型链实现对原型属性的继承,通过借用构造函数来实现对实例属性的继承。
  • 缺点是两次调用超类型构造函数。

In [43]:
function SuperType(name){
    this.name = name;
    this.colors = ["red", "blue", "green"];
}

SuperType.prototype.sayName = function(){
    alert(this.name);
};

function SubType(name, age){  
    SuperType.call(this, name);// 第二次调用SuperType()

    this.age = age;
}

SubType.prototype = new SuperType();// 第一次调用SuperType()

SubType.prototype.sayAge = function(){
    alert(this.age);
};

var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
alert(instance1.colors);  //"red,blue,green,black"
instance1.sayName();      //"Nicholas";
instance1.sayAge();       //29


var instance2 = new SubType("Greg", 27);
alert(instance2.colors);  //"red,blue,green"
instance2.sayName();      //"Greg";
instance2.sayAge();       //27


[ 'red', 'blue', 'green', 'black' ]
Nicholas
29
[ 'red', 'blue', 'green' ]
Greg
27
Out[43]:
undefined

原型式继承

一种实现继承的方法,这种方法没有使用严格意义上的构造函数。在object()函数内部,先创建了一个临时的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回了这个临时类型的一个新实例。从本质上讲,object()对传入其中的对象执行了一次浅复制。


In [44]:
function object(o){
    function F(){}
    F.prototype = o;
    return new F();
}

var person = {
    name: "Nicholas",
    friends: ["Shelby", "Court", "Van"]
};

var anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");

var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");

alert(person.friends);   //"Shelby,Court,Van,Rob,Barbie"


[ 'Shelby', 'Court', 'Van', 'Rob', 'Barbie' ]
Out[44]:
undefined

ECMAScript5通过新增Object.create()方法规范化了原型式继承:


In [45]:
var person = {
    name: "Nicholas",
    friends: ["Shelby", "Court", "Van"]
};

var anotherPerson = Object.create(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");

var yetAnotherPerson = Object.create(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");

alert(person.friends);   //"Shelby,Court,Van,Rob,Barbie"


[ 'Shelby', 'Court', 'Van', 'Rob', 'Barbie' ]
Out[45]:
undefined

Object.create()方法的第二个参数与Object.defineProperties()方法的第二个参数格式相同:每个属性是通过自己的描述符定义的。以这种方式指定的任何属性都会覆盖原型对象上的同名属性:


In [46]:
var person = {
    name: "Nicholas",
    friends: ["Shelby", "Court", "Van"]
};

var anotherPerson = Object.create(person, {
    name: {
        value: "Greg"
    }
});

alert(anotherPerson.name);  //"Greg"


Greg
Out[46]:
undefined

寄生组合式继承

  • 避免了组合继承两次调用构造函数。
  • 基本思路:不必为了指定子类型的原型而调用超类型的构造函数,所需要的无非就是超类型原型的一个副本而已。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。

In [47]:
function object(o){
    function F(){}
    F.prototype = o;
    return new F();
}

function inheritPrototype(subType, superType){
    var prototype = object(superType.prototype);   //create object
    prototype.constructor = subType;               //augment object
    subType.prototype = prototype;                 //assign object
}

function SuperType(name){
    this.name = name;
    this.colors = ["red", "blue", "green"];
}

SuperType.prototype.sayName = function(){
    alert(this.name);
};

function SubType(name, age){  
    SuperType.call(this, name);

    this.age = age;
}

inheritPrototype(SubType, SuperType);

SubType.prototype.sayAge = function(){
    alert(this.age);
};

var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
alert(instance1.colors);  //"red,blue,green,black"
instance1.sayName();      //"Nicholas";
instance1.sayAge();       //29


var instance2 = new SubType("Greg", 27);
alert(instance2.colors);  //"red,blue,green"
instance2.sayName();      //"Greg";
instance2.sayAge();       //27


[ 'red', 'blue', 'green', 'black' ]
Nicholas
29
[ 'red', 'blue', 'green' ]
Greg
27
Out[47]:
undefined

In [ ]: