JavaScript 面向对象之继承

简介: JavaScript 面向对象之继承

继承

1、原型链

概念

构造函数或构造器具有prototype属性,对象具有__proto__属性,这就是之前学习的原型。


如果构造函数或对象A,A的原型指向构造函数或对象B,B的原型再指向构造函数或对象C,以此尖推,最终的构造函数或对象的原型指向Object的原型。由此形成一条链状结构,被称之为原型链。


按照上述的描述,在B中定义的属性或方法,可以直接在A中使用并不需要定义。这就是继承,它允许每个对象来访问其原型链上的任何属性或方法。


原型链是ECMAScript标准中指定的默认实现继承的方式。

//1、定义构造函数A
function A(){
    this.a = 'a';
}
// 通过构造函数方式创建对象a
var a  = new A();
console.log(a.a)//a
//2、定义构造函数B
function B(){
    this.b = 'b';
}
// 将B原型指向对象a
B.prototype = a;
//通过构造函数方式创建对象b
var b  = new B();
console.log(b.b)//b
console.log(b.a)//a
//3、定义构造函数C
function C(){
    this.c = 'c';
}
// 将C的原型指向对象b
C.prototype = b;
// 通过构造函数方式创建对象c
var c  = new C();
console.log(c.c)//c
console.log(c.b)//b
console.log(c.a)//a

解析图如下:

2、只继承于原型

出于对效率的考虑,尽可能地将属性和方法添加到原型上。可以采取以下方式:

不要为继承关系单独创建新对象。

尽量减少运行时的方法搜索。

示例代码如下:

function A() {};
// 将自有属性改为原型属性
A.prototype.a='a'
function B() {};
// 将B的原型指向A的原型
B.prototype = A.prototype;
// 为对象B使用原型新增属性b
B.prototype.b='b';
function C() {
    this.c='c';
};
// 将C的原型指向B的原型
C.prototype = B.prototype;
var c=new C();
console.log(c.c)
console.log(c.b)
console.log(c.a)

原型链的问题

原型链虽然很强大,用它可以实现JavaScript中的继承,但同时也存在着一些问题。

原型链实际上是在多个构造函数或对象之间共享属性和方法

创建子类的对象时,不能向父级的构造函数传递任何参数。

综上所述,在实际开发中很少会单独使用原型链。

function A() {};
// 将自有属性改为原型属性
A.prototype.a='a'
function B() {};
// 将B的原型指向A的原型
B.prototype = A.prototype;
// 为对象B使用原型新增属性b
B.prototype.b='b';
function C() {};
// 将C的原型指向B的原型
C.prototype = B.prototype;
C.prototype.c = 'c';
// 实现多个构造函数原型链之间的属性共享
var c=new C();
console.log(c.c)
console.log(c.b)
console.log(c.a)
var b = new B();
console.log(b.c)
console.log(b.b)
console.log(b.a)
var a= new A();
console.log(a.c)
console.log(a.b)
console.log(a.a)

3、原型式继承(1)

所谓原型式继承,就是定义一个函数,该函数中创建一个临时性的构造函数,将作为参数传入的对象作为这个构造函数的原型,最后返回这个构造函数的实例对象。

根据原型式继承所总结的object()函数实现继承,如下代码示例:

/*
    定义一个函数 - 用于实现对象之间的继承
    * 参数
        * obj: 表示继承关系中的父级对象
        * prop : 对象格式,表示继承关系中的子级对象的属性和方法
*/
function fn(obj,prop) {
        // 定义一个临时的 构造函数
    function Fun() {
        // 遍历对象的属性和方法
        for (var attrName in prop){
            this[attrName] = prop[attrName];
        }
    }
    // 将函数的参数作为构造函数的原型
    Fun.prototype = obj;
    // 将构造函数创建的对象进行返回
    return new Fun();
}
var obj = {
    name : '猪猪侠'
}
// 调用函数
var result = fn(obj,{
    age:18,
    sayMe : function () {
        console.log('我叫猪猪侠');
    }
});
console.log(result.age);
result.sayMe();

注:这种原型式继承要求必须具有一个对象可以作为另一个对象的基础。

原型式继承(2)

也可以利用Obiect 的create()方法替代自定义的object()函数,从而实现规范化。

// 利用Object.create()方法实现继承
var obj = {
    name:'猪猪侠'
}
var newobj = Object.create(obj,{
    age : {
        value:18
    },
    sayMe : {
        value : function () {
            console.log('我叫猪猪侠');
        }
    }
});
console.log(newobj.age);//18
newobj.sayMe();//我叫猪猪侠

4、借助构造函数方式实现继承

无论是原型链还是原型式继承,都具有相同的问题。想要解决这样的问题的话,可以借助构造函数(也可以叫做伪造对象或经典继承)。


这种方式实现非常简单,就是在子对象的构造函数中调用父对象的构造函数。具体可以通过调用apply()和call()方法实现。


apply()和call()方法都允许传递指定某个对象的this。对于继承来讲,可以实现在子对象的构造函数中调用父对象的构造函数时,将子对象的this和父对象的this绑定在一起。


示例代码如下:

// 定义父级对象的构造函数
function Parent() {
    this.parent = 'parent';
}
// 定义子级对象的构造函数
function Child(){
    // 调用父级对象的构造函数 -> 使用apply()方法或call()方法
    Parent.call(this);
    this.child = 'child';
}
// 创建子级对象
var child = new Child();
console.log(child);

上述示例代码 分析如下:

5、组合方式继承

组合继承,也叫做伪经典继承,指的是将原型链或原型式继承和借助构造函数的技术组合在一起,发挥二者长处的一种继承方式。


具体实现的思路就是:


使用原型链或原型式继承实现对原型的属性和方法的继承。

通过借助构造函数实现对实例对象的属性的继承。

这样,既通过在原型上定义方法实现了函数的重用,又可以保证每个对象都有自己的专有属性。


示例代码如下所示:

function Parent(){
// 构造函数的自有属性
    this.name = '猪猪侠'
}
// 构造函数的原型属性
Parent.prototype.age = 20;
function Child() {
// 继承父级构造函数的自有属性
    Parent.call(this);
    this.job = '主角';
}
// 继承父级构造函数中的原型属性
Child.prototype = Parent.prototype;
var child = new Child();
// 打印子级上的job
console.log(child.job);//主角
// 打印父级上的age
console.log(child.age);//20
// 打印父级上的name
console.log(child.name)//猪猪侠
目录
相关文章
|
9天前
|
JavaScript 前端开发
如何在 JavaScript 中使用 __proto__ 实现对象的继承?
使用`__proto__`实现对象继承时需要注意原型链的完整性和属性方法的正确继承,避免出现意外的行为和错误。同时,在现代JavaScript中,也可以使用`class`和`extends`关键字来实现更简洁和直观的继承语法,但理解基于`__proto__`的继承方式对于深入理解JavaScript的面向对象编程和原型链机制仍然具有重要意义。
|
18天前
|
JavaScript 前端开发
Javascript如何实现继承?
【10月更文挑战第24天】JavaScript 中实现继承的方式有很多种,每种方式都有其优缺点和适用场景。在实际开发中,我们需要根据具体的需求和情况选择合适的继承方式,以实现代码的复用和扩展。
|
12天前
|
JavaScript 前端开发
如何使用原型链继承实现 JavaScript 继承?
【10月更文挑战第22天】使用原型链继承可以实现JavaScript中的继承关系,但需要注意其共享性、查找效率以及参数传递等问题,根据具体的应用场景合理地选择和使用继承方式,以满足代码的复用性和可维护性要求。
|
12天前
|
JavaScript 前端开发 开发者
js实现继承怎么实现
【10月更文挑战第26天】每种方式都有其优缺点和适用场景,开发者可以根据具体的需求和项目情况选择合适的继承方式来实现代码的复用和扩展。
28 1
|
5月前
|
设计模式 JavaScript 前端开发
在JavaScript中,继承是一个重要的概念,它允许我们基于现有的类(或构造函数)创建新的类
【6月更文挑战第15天】JavaScript继承促进代码复用与扩展,创建类层次结构,但过深的继承链导致复杂性增加,紧密耦合增加维护成本,单继承限制灵活性,方法覆盖可能隐藏父类功能,且可能影响性能。设计时需谨慎权衡并考虑使用组合等替代方案。
46 7
|
5月前
|
JavaScript 前端开发
在 JavaScript 中,实现继承的方法有多种
【6月更文挑战第15天】JavaScript 继承常见方法包括:1) 原型链继承,利用原型查找,实例共享原型属性;2) 借用构造函数,避免共享,但方法不在原型上复用;3) 组合继承,结合两者优点,常用但有额外开销;4) ES6 的 class,语法糖,仍基于原型链,提供直观的面向对象编程。
37 7
|
2月前
|
自然语言处理 JavaScript 前端开发
一文梳理JavaScript中常见的七大继承方案
该文章系统地概述了JavaScript中七种常见的继承模式,包括原型链继承、构造函数继承、组合继承、原型式继承、寄生式继承、寄生组合继承等,并探讨了每种模式的实现方式及其优缺点。
一文梳理JavaScript中常见的七大继承方案
|
2月前
|
JavaScript 前端开发
js之class继承|27
js之class继承|27
|
2月前
|
JSON JavaScript 前端开发
js原型继承|26
js原型继承|26
|
2月前
|
JavaScript 前端开发 开发者
JavaScript 类继承
JavaScript 类继承
19 1