ES5中的继承

ES中只支持实现继承,且其继承是通过原型链来实现的。

基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。让一个原型对象等于另一个类型的实例。

原型链有个严重的问题,就是包含引用类型值的原型,属性会被所有实例共享。还有一个问题是无法向超类的构造函数传参。

比如:

function SuperType(){

this.colors=["blue","red"];

}

function SubType(){}

SubType.prototype=new SuperType();

var sub=new SubType();

var sub2=ew SubType();

此时sub的原型是SuperType的实例,每个subType的原型都有不同的colors数组,但是所有subType的实例都指向同一个原型,所以sub和sub1中有同一个数组。

1.为了解决上述问题,借用构造函数方法产生了

function SuperType(color){

this.colors=["blue","red"];

this.colost.push(color);

}

function SubType(){

SuperType.call(this,"black")

}

var instance=new SubType();

缺点:类似构造函数的问题,方法都在构造函数中定义无法复用

2.组合继承

将原型链和构造函数结合。使用原型链实现对源性属性和方法的继承,使用借用构造函数来实现对实例属性的继承。

function SuperType(name){

this.colors=["blue","red"];

this.name=name;

}

SuperType.somefuncion={

//

};

function SubType(name){

SuperType.call(this,name)

}

SubType.prototype=new SuperType();

SubType.constructor=SubType;

sub = new Subtype("name")

3.原型继承:在只想要一个和其他对象差不多的对象时使用

可以直接用create函数,

var person={name="ha",age=10};

var anotherperson=Object.create(person)

注意这里和原型链差不多,引用类型会被所有新创建的副本共享。

其中create函数的实现是这样的:

function object(o){

function F(){};

F.prototype=o;

return new F();

}

4.寄生式继承

与原型式紧密相关,与寄生构造和函数和工厂模式类似。创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象。

function createAnother(original){

var clone=object(original);

clone.sayHi=function(){};

return clone;

}

但是同样存在不能复用的问题。

5.寄生组合式继承

组合继承有一个缺点,就是会调用两次超类的构造函数,一次是在创建子类型原型的时候,一次是在子类型构造函数的内部。

这样子类型的原型上会有多余的属性

通过这样一个函数

inherit(subtype,supertype){

var prototype=object(supertype.prototype);

prototype.constructor=subtype;

subtype.prototype=prototype;;

}

来替换subtype.prototype=new supertype();

即省略了一次调用超类构造函数的过程。


参考文献:《JS高程》


<think>嗯,用户想了解ES5中的继承实现方式。我之前整理过相关引用,里面有提到七种方法,但具体怎么解释呢?首先得回顾一下各个引用的内容。引用[1]提到了7种方法,包括借用构造函数、原型链、组合继承等等。引用[2]和[3]详细说明了组合继承的优缺点,比如调用两次父类构造函数的问题。引用[4]讨论了原型链继承的缺点,比如共享属性和无法传递参数。引用[5]则是一个关于原型和new操作的例子。 用户可能需要一个清晰的分类,把每种方法的特点、步骤、优缺点讲清楚。比如,先讲原型链继承,然后是构造函数继承,接着组合继承,再其他方法。每种方法都要有示例代码,这样用户更容易理解。同时,要注意引用对应的部分,比如组合继承的问题在引用[2]里提到过。 另外,用户可能对为什么需要多种方法感兴趣,所以得解释每种方法的适用场景和问题。比如原型链继承会导致引用类型共享,而构造函数继承无法继承原型方法。组合继承结合了两者,但效率问题如何。还有寄生式继承、寄生组合式继承这些高级方法,可能需要对比说明它们的改进之处。 还要注意代码示例的正确性,比如构造函数继承时,子类实例无法访问父类原型的方法,如引用[3]中的例子。组合继承中,父类构造函数被调用两次,这个在代码中要体现出来。寄生组合式继承作为最优解,需要详细说明如何避免调用两次构造函数。 最后,生成相关问题时要覆盖各个方法的优缺点、比较以及应用场景,帮助用户进一步学习。确保回答结构清晰,分点列出,每个方法都有步骤、示例和优缺点,并正确标注引用来源。</think>### ES5继承的实现方式详解 在ES5中实现继承主要通过**原型链**和**构造函数**的组合使用,以下是6种典型方法的实现原理及特点: --- #### 1. **原型链继承** **原理**:子类的原型指向父类实例 **实现步骤**: ```javascript function Parent() { this.name = '张三'; } Parent.prototype.getName = function() { return this.name }; function Child() {} Child.prototype = new Parent(); // 核心操作 ``` **特点**: - 子类可继承父类实例属性及原型方法 - 所有子类实例**共享父类引用类型属性**(如数组),修改会相互影响[^4] - 无法向父类构造函数传参[^4] --- #### 2. **构造函数继承** **原理**:在子类构造函数中调用父类构造函数 **实现步骤**: ```javascript function Parent(name) { this.name = name; } function Child(name) { Parent.call(this, name); // 核心操作 } ``` **特点**: - 每个子类实例**独立拥有父类属性**,避免共享问题[^3] - 可向父类构造函数传参 - **无法继承父类原型方法**(如`Parent.prototype.getName`)[^3] --- #### 3. **组合继承(经典继承)** **原理**:结合原型链继承与构造函数继承 **实现步骤**: ```javascript function Parent(name) { this.name = name; } Parent.prototype.getName = function() { return this.name }; function Child(name) { Parent.call(this, name); // 第1次调用父类构造函数 } Child.prototype = new Parent(); // 第2次调用父类构造函数 Child.prototype.constructor = Child; ``` **特点**: - 既能继承实例属性,又能继承原型方法 - 父类构造函数被**调用两次**,导致子类原型中存在冗余属性[^2] - 子类实例中存在两份`name`属性(实例自身和原型链上) --- #### 4. **寄生式继承** **原理**:通过封装对象增强功能 **实现步骤**: ```javascript function createObj(original) { let clone = Object.create(original); clone.sayHi = function() { console.log('Hi') }; return clone; } ``` **特点**: - 类似工厂模式,为对象添加新方法 - **无法复用方法**,每个实例都创建新方法 --- #### 5. **寄生组合式继承(最优方案)** **原理**:通过`Object.create()`优化原型链 **实现步骤**: ```javascript function Parent(name) { this.name = name; } Parent.prototype.getName = function() { return this.name }; function Child(name) { Parent.call(this, name); // 仅调用1次父类构造函数 } Child.prototype = Object.create(Parent.prototype); // 核心优化 Child.prototype.constructor = Child; ``` **特点**: - **只调用一次父类构造函数**,避免冗余属性[^2] - 完美继承实例属性和原型方法 - ES6的`class extends`底层实现原理 --- #### 6. **直接继承prototype** **原理**:子类原型直接指向父类原型 **实现步骤**: ```javascript function Parent() {} Parent.prototype.name = '张三'; function Child() {} Child.prototype = Parent.prototype; Child.prototype.constructor = Child; // 破坏父类原型 ``` **特点**: - 子类修改原型会直接影响父类[^4] - 已淘汰的非安全方案 --- ### 方案对比 | 方法 | 属性继承 | 方法继承 | 调用父类次数 | 实例隔离性 | |------------------|----------|----------|--------------|------------| | 原型链继承 | ✔️ | ✔️ | 1 | ❌ | | 构造函数继承 | ✔️ | ❌ | 1 | ✔️ | | 组合继承 | ✔️ | ✔️ | 2 | ✔️ | | 寄生组合式继承 | ✔️ | ✔️ | 1 | ✔️ | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值