JS 中创建对象和实现继承的常用方式

旧文一篇,2014年发布于前端乱炖中,是当时学习的整理,现在拿过来备份凑个篇数;

创建对象

JS中的面向对象是不完整的,没有标准的类的”声明”方式

最常用的类的声明及对象的创建方式如下,不同的书中对其有不同的命名

function Person(name, age) {
    // 属性是不相同的,每个有一份
    this.name=name;
    this.age=age;
}

// 方法是相同的,调用同一个
Person.prototype.showName=function () {
    alert(this.name);
};
Person.prototype.showAge=function () {
    alert(this.age);
};

var p1=new Person('super', 24);
p1.showName();
p1.showAge();

继承

准则:创建出来的子类实例,
1、用 instanceof 检测父类、子类均返回 true;
2、实例的 constructor 指向该子类;
3、子类添加方法,不会添加到父类上;

同样,JS中实现继承也没有一个标准,所以会有很多实现方式,个人觉得比较常用的两种方式如下:

1、组合继承

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

Person.prototype.showName = function () {
    alert(this.name);
};
Person.prototype.showAge = function () {
    alert(this.age);
};

function Worker(name, age, job) {
    // 1.继承父级的属性
    Person.apply(this, arguments);

    // 2.添加自己的属性
    this.job = job;
}

// 3.继承父级的方法
Worker.prototype = new Person();
Worker.prototype.constructor = Worker;

// 4.添加自己的方法
Worker.prototype.showJob = function () {
    alert(this.job);
};

var oW=new Worker('super', 24, 'Programmer');

oW.showName();
oW.showAge();
oW.showJob();

alert(oW instanceof Person);    // true
alert(oW instanceof Worker);    // true
alert(oW.constructor);          // 指向Worker

唯一的缺点就是调用了两次 Persion 方法。

2、寄生组合模式,解决了组合模式的缺点

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

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

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

Person.prototype.showName=function () {
    alert(this.name);
};
Person.prototype.showAge=function () {
    alert(this.age);
};

function Worker(name, age, job) {
    // 1.继承父级的属性
    Person.apply(this, arguments);

    // 2.添加自己的属性
    this.job=job;
}

// 3.继承父级的方法
inheritPrototype(Worker, Person);

// 4.添加自己的方法
Worker.prototype.showJob=function () {
    alert(this.job);
};

var oW=new Worker('Super', 24, 'Programmer');
oW.showName();
oW.showAge();
oW.showJob();

alert(oW instanceof Person);    // true
alert(oW instanceof Worker);    // true
alert(oW.constructor);          // 指向Worker

个人觉得还是第一种 – 组合继承方便。

3、继承的封装

组合继承模式的封装

// 参数:父类型(构造函数)、子类的构造、子类的方法
function inherit(parentType, childConstructor, methods) {
    //Child——子级的构造函数
    function Child() {
        //arguments -> ['Super', 24, 'Programmer']
        // 1.继承父级的属性
        parentType.apply(this, arguments);

        // 2.添加子级的属性
        childConstructor.apply(this, arguments);
    }

    // 3.继承父级的方法
    Child.prototype = new parentType();
    Child.prototype.constructor = Child;

    // 4.添加子级的方法
    for(var i in methods) {
        Child.prototype[i] = methods[i];
    }

    return Child;
}

// ====================== 测试 ====================

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

Person.prototype.showName = function () {
    alert(this.name);
};
Person.prototype.showAge = function () {
    alert(this.age);
};

//继承
var Worker = inherit( Person, function (name, age, job){
    this.job = job;
}, {
    showJob: function () {
        alert(this.job);
    }
});

var oW = new Worker('Super', 24, 'Programmer');
oW.showName();
oW.showAge();
oW.showJob();

alert(oW instanceof Person);    // true
alert(oW instanceof Worker);    // true
alert(oW.constructor);          // 指向 Child

这里只简单的封装了一下所谓的组合继承,实际项目中还真是没有用过继承,有点儿心虚,不好意思往下写了,另一个自己封装吧。
继承在游戏中应该用的多一些吧,现在模块化已经流行开来,似乎比面向对象开发更方便。

如果这篇文章对你有用,可以点击下面的按钮告诉我

0

发表回复