全面理解Javascript的面向对象(二)--创建对象与继承

在前文全面理解Javascript的面向对象(一)中详细介绍了面向对象的主要知识点,可以帮助大家很细致的了解js面向对象的概念,本文作为补充,主要从对象的构建和继承的方式两方面进行分析。

一、创建对象主要的几种方式

1 工厂模式

工厂模式抽象了创建具体对象的过程,用函数封装以特定接口创建对象的细节。

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("Nike",21,"Doctor");
var person2 = createPerson("Frank",21,"Manager");

缺点:没有解决对象的识别问题,即怎样知道一个对象的类别。于是,新的模式:构造函数模式出现了。

2 构造函数模式

像Object、Array这样的原生构造函数,在运行时就会自动创建。此外也可以自定义构造函数,从而定义自定义对象类型的属性和方法。

function Person(name,age,job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function () {
        alert(this.name);
    }
}

var person1 = new Person("Nike",21,"Doctor");
var person2 = new Person("Frank",21,"Manager");

使用构造函数方法创建对象经历了四个过程:
- 创建新对象
- 将构造函数作用域赋给新对象(this指向了新对象)
- 执行构造函数的方法(为新对象添加属性)
- 返回新对象

自定义的构造函数可将它的实例标识为特定的类型,这是胜过工厂模式的地方

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

缺点:每个方法在每个实例上多次创建。这个问题可以通过原型模式解决。

3 原型模式

function Person() {

}
Person.prototype.name = 'frank';
Person.prototype.age = 21;
Person.prototype.sayName = function () {
    alert(this.name);
}

var person1 = new Person();
person1.sayName();

var person2 = new Person();
person2.sayName();

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

更简单的原型语法:

function Person() {

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

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

构造函数模式用于定义实例属性,原型模式用于定义方法和共享的属性。结果,每个实例都会有自己的一份实例属性的副本,同时又共享着方法的引用,最大限度节省内存。

function Person(name,age,job) {
    this.name = name;
    this.age = age;
    this.job = job;
}

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

var person1 = new Person("Nike",21,"Doctor");
var person2 = new Person("Frank",21,"Manager");

二、继承的实现方式

1 原型链

如果对象无法相应某个请求,他会把这个请求委托给他的构造器的原型对象。
将一个原型对象等于另一个实例,这个原型对象包含一个指向另一个原型的指针,相应的,另一个原型也包括一个指向构造函数的指针,这样层层递进,构成了实例与原型的链条

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

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

SubTpye.prototype = new SuperType();

var ins = new SubTpye();
alert(ins.getSuperType());

缺点:创建子类型的实例时,不能向超类型的构造函数中传递参数。

2 借用构造函数

在子类型构造函数中调用超类型构造函数。

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


function SubTpye() {
    SuperType.call(this);
}

var ins1 = new SubTpye();
ins1.colors.push("black");
alert(ins1.colors);   //'red','blue','green','black'

var ins2 = new SubTpye();
alert(ins2.colors);   //'red','blue','green'

与原型链模式相比,借用构造函数的最大优势是子类可以向超类中传递参数。

 function SuperType(name) {
    this. name = name;
}


function SubTpye() {
    SuperType.call(this,"frank");
}

var ins1 = new SubTpye();
alert(ins1.name);   //'frank'

缺点:方法都在构造函数中定义,因此函数复用就无从谈起,超类型的原型中定义的方法,对子类型而言不可见。因此借用构造函数的模式很少单独使用。

3 组合继承

组合继承是将原型链和借用构造函数的方法结合到一起。
思路是
- 使用原型链实现对原型属性和方法的继承;
- 使用借用构造函数的方法实现对实例属性的继承。

这样,通过在原型上定义方法实现函数复用,又能够保证对每个实例有自己的属性。

function SuperType(name){
    this.name = name;
    this.colors = ["red","blue","green"];
}
SuperType.prototype.callName = function(){
    alert(this.name);
}
function SubType(name,age){
    SuperType.call(this,name);
    this.age = age;
}
SubType.prototype = new SuperType();
SubType.prototype={
    constructor:SubType,
    callAge:function(){
        alert(this.age);
    }
}

var ins1 = new SubType("nike",29);
ins1.colors.push("black");
console.log(ins1.colors);
console.log(ins1.callName());
console.log(ins1.callAge());

组合模式是javascript中最常用的模式。

4 原型继承

在上一篇博文全面理解Javascript的面向对象(一)中,介绍过,原型继承的本质是基于原型链的委托机制。

function object(o){
    function F(){}
    F.prototype = o;
    return new F();
}

在object()函数内部,先创建一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回这个临时类型的一个新实例。object()对传入的对象进行了一次浅复制。

var Person = {
    name:"nike",
    friends:["frank","lucy"];
}
var another = object(Person);
another.gentle = "male";
another.friends.push("mike");

在ES5中新增Object.create()方法,规范了原型继承。这个方法又两个传入的参数,一个是对象,另一个是==可选==的额外定义的属性。

var another1 = Object.create(Person);
another.gentle = "male";

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

猜你喜欢

转载自blog.csdn.net/franktaoge/article/details/70232538