重新理解JavaScript的六种继承方式

发布时间 - 2026-01-11 00:20:26    点击率:

类式继承(构造函数)

JS中其实是没有类的概念的,所谓的类也是模拟出来的。特别是当我们是用new 关键字的时候,就使得“类”的概念就越像其他语言中的类了。类式继承是在函数对象内调用父类的构造函数,使得自身获得父类的方法和属性。call和apply方法为类式继承提供了支持。通过改变this的作用环境,使得子类本身具有父类的各种属性。

var father = function() {
this.age = 52;
this.say = function() {
alert('hello i am '+ this.name ' and i am '+this.age + 'years old');
}
}
var child = function() {
this.name = 'bill';
father.call(this);
}
var man = new child();
man.say();

 原型继承

原型继承在开发中经常用到。它有别于类继承是因为继承不在对象本身,而在对象的原型上(prototype)。每一个对象都有原型,在浏览器中它体现在一个隐藏的__proto__属性上。在一些现代浏览器中你可以更改它们。比如在zepto中,就是通过添加zepto的fn对象到一个空的数组的__proto__属性上去,从而使得该数组成为一个zepto对象并且拥有所有的方法。话说回来,当一个对象需要调用某个方法时,它回去最近的原型上查找该方法,如果没有找到,它会再次往下继续查找。这样逐级查找,一直找到了要找的方法。 这些查找的原型构成了该对象的原型链条。原型最后指向的是null。我们说的原型继承,就是将父对像的方法给子类的原型。子类的构造函数中不拥有这些方法和属性。

var father = function() {
}
father.prototype.a = function() {
}
var child = function(){}
//开始继承
child.prototype = new father();
var man = new child();
man.a();

可以看到第七行实现了原型继承。很多人并不陌生这种方式。通过在浏览器中打印man我们就可以查看各个原型的继承关系。

可以看到逐级的关系child->object(father实例化的对象)->father。child是通过中间层继承了father的原型上的东西的。但是为什么中间还有一层object呢, 为什么不把child.prototype = father.prototype。 答案是如果这样做child和father就没有区别了。大家应该还记得在prototype中有个constructor属性,指向的是构造函数。按照正常的情况我们要把constructor的值改回来指向child的构造函数。但如果直接把father.prototype赋值给child.prototype,那么constructor应该指向谁呢?所以很显然只能通过中间层才能使得child和father保持为独立的对象。

类式继承和原型继承的对比

构造函数(类)式继承

首先,构造函数继承的方法都会存在父对象之中,每一次实例,都会将funciton保存在内存中,这样的做法毫无以为会带来性能上的问题。

其次,类式继承是不可变的。无法复用,在运行时,无法修改或者添加新的方法,这种方式是一种固步自封的死方法。实践中很少单纯使用。

原型继承

优点:

原型链可改变:原型链上的父类可替换可扩展

可以通过改变原型链接而对子类进行修改的。另外就是类式继承不支持多重继承,而对于原型继承来说,你只需要写好extend对对象进行扩展即可。

但是原型链继承也有2个问题。

第一,包含引用类型值的原型属性会被所有实例共享(可以这样理解:执行sub1.arr.push(2);先对sub1进行属性查找,找遍了实例属性(在本例中没有实例属性),没找到,就开始顺着原型链向上找,拿到了sub1的原型对象,一搜身,发现有arr属性。于是给arr末尾插入了2,所以sub2.arr也变了)。

第二,在创建子类型的实例时,不能向超类型的构造函数中传递参数。(实际上,应该说没有办法在不影响所有对象实例的情况下,给超类型的构造函数传递参数)实践中很少单纯使用原型链。

function Super(){
this.val = 1;
this.arr = [1];
}
function Sub(){
// ...
}
Sub.prototype = new Super(); // 核心
var sub1 = new Sub();
var sub2 = new Sub();
sub1.val = 2;
sub1.arr.push(2);
alert(sub1.val); // 2
alert(sub2.val); // 1
alert(sub1.arr); // 1, 2
alert(sub2.arr); // 1, 2

总结:

类式继承在实例化时,父类可传参,不能复用(父类不可变,每一次实例都会将父类内容保存在内存中)

原型继承在实例化时,父类不可传参,可以复用(原型链可改变(父类可替换可扩展),父类不会保存在内存中,而是顺着原型链查找,但是结果是原型属性会被所有实例共享(尤其影响引用类型值))

组合继承(最常用)

组合继承将原型链和借用构造函数的技术结合到一起,发挥两者之长的一种继承模式。

思路是使用原型链实现对原型属性和方法的继承,通过借用构造函数实现对实例属性的继承。

function SuperType(name){
this.name = name;
this.numbers = [1,2,3];
}
SuperType.prototype.sayName = function(){
console.log(this.name);
}
function SubType(name,age){
SuperType.call(this,name);
this.age = age;
}
SubType.prototype = new SuperType();
SubType.prototype.sayAge = function(){
console.log(this.age);
}
var instance1 = new SubType('aaa',21);
instance1.numbers.push(666);
console.log(instance1.numbers);
instance1.sayName();
instance1.sayAge();
var instance2 = new SubType('bbb',22);
console.log(instance2.numbers);
instance2.sayName();
instance2.sayAge();

把实例函数都放在原型对象上,通过Sub.prototype = new Super();继承父类函数,以实现函数复用。

保留借用构造函数方式的优点,通过Super.call(this);继承父类的基本属性和引用属性,以实现传参;

优缺点

优点:

  1. 可传参
  2. 函数可复用
  3. 不存在引用属性共享问题(图纸)

缺点:

(一点小瑕疵)子类原型上有一份多余的父类实例属性,因为父类构造函数被调用了两次,生成了两份,而子类实例上的那一份屏蔽了子类原型上的。。。又是内存浪费,比刚才情况好点,不过确实是瑕疵。

以上所述是小编给大家介绍的JavaScript的六种继承方式,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!


# javascript的继承方式  # 6种JavaScript继承方式及优缺点(小结)  # JavaScript的六种继承方式(推荐)  # js的三种继承方式详解  # 浅谈js中的三种继承方式及其优缺点  # Javascript中的几种继承方式对比分析  # 浅析2种JavaScript继承方式  # Javascript编程中几种继承方式比较分析  # JavaScript中的继承方式详解  # js的2种继承方式详解  # javascript学习笔记(九)javascript中的原型(prototype)及原型链的继承方  # JavaScript 常见的继承方式汇总  # 子类  # 复用  # 的是  # 中间层  # 可以看到  # 器中  # 会将  # 小编  # 是在  # 都有  # 也有  # 是一种  # 是因为  # 放在  # 固步自封  # 有个  # 你可以  # 又是  # 实践中  # 在此 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 香港服务器网站推广:SEO优化与外贸独立站搭建策略  Laravel如何使用Eloquent ORM进行数据库操作?(CRUD示例)  如何在 Pandas 中基于一列条件计算另一列的分组均值  浅析上传头像示例及其注意事项  Linux系统命令中screen命令详解  如何用好域名打造高点击率的自主建站?  Laravel如何与Inertia.js和Vue/React构建现代单页应用  如何用狗爹虚拟主机快速搭建网站?  奇安信“盘古石”团队突破 iOS 26.1 提权  rsync同步时出现rsync: failed to set times on “xxxx”: Operation not permitted  如何用搬瓦工VPS快速搭建个人网站?  Laravel如何使用API Resources格式化JSON响应_Laravel数据资源封装与格式化输出  Swift开发中switch语句值绑定模式  Laravel事件和监听器如何实现_Laravel Events & Listeners解耦应用的实战教程  Laravel Eloquent模型如何创建_Laravel ORM基础之Model创建与使用教程  如何快速生成橙子建站落地页链接?  Android中AutoCompleteTextView自动提示  如何在IIS服务器上快速部署高效网站?  图片制作网站免费软件,有没有免费的网站或软件可以将图片批量转为A4大小的pdf?  如何构建满足综合性能需求的优质建站方案?  ,怎么在广州志愿者网站注册?  如何做网站制作流程,*游戏网站怎么搭建?  常州企业网站制作公司,全国继续教育网怎么登录?  Laravel如何连接多个数据库_Laravel多数据库连接配置与切换教程  Laravel如何使用Sanctum进行API认证?(SPA实战)  EditPlus中的正则表达式实战(6)  在centOS 7安装mysql 5.7的详细教程  如何快速搭建FTP站点实现文件共享?  HTML 中动态设置元素 name 属性的正确语法详解  软银砸40亿美元收购DigitalBridge 强化AI资料中心布局  Laravel项目如何进行性能优化_Laravel应用性能分析与优化技巧大全  如何在Ubuntu系统下快速搭建WordPress个人网站?  Laravel怎么实现模型属性的自动加密  Laravel如何配置Horizon来管理队列?(安装和使用)  laravel怎么为应用开启和关闭维护模式_laravel应用维护模式开启与关闭方法  Laravel Docker环境搭建教程_Laravel Sail使用指南  Win11怎么开启自动HDR画质_Windows11显示设置HDR选项  如何在阿里云服务器自主搭建网站?  文字头像制作网站推荐软件,醒图能自动配文字吗?  大连 网站制作,大连天途有线官网?  Laravel如何使用缓存系统提升性能_Laravel缓存驱动和应用优化方案  Laravel怎么防止CSRF攻击_Laravel CSRF保护中间件原理与实践  UC浏览器如何切换小说阅读源_UC浏览器阅读源切换【方法】  头像制作网站在线观看,除了站酷,还有哪些比较好的设计网站?  如何用VPS主机快速搭建个人网站?  谷歌浏览器如何更改浏览器主题 Google Chrome主题设置教程  简历在线制作网站免费版,如何创建个人简历?  如何在企业微信快速生成手机电脑官网?  如何撰写建站申请书?关键要点有哪些?  如何在VPS电脑上快速搭建网站?