0

0

关于JS继承的详解

php中世界最好的语言

php中世界最好的语言

发布时间:2018-03-13 17:31:30

|

1472人浏览过

|

来源于php中文网

原创

这次给大家带来关于js继承的详解,使用js继承的注意事项有哪些,下面就是实战案例,一起来看一下。

ECMAScript 实现继承的方式不止一种。这是因为 JavaScript 中的继承机制并不是明确规定的,而是通过模仿实现的。这意味着所有的继承细节并非完全由解释程序处理。可以根据需求决定适合的继承方式。

对象冒充

构造函数使用this关键字给所有属性和方法赋值(即采用类声明的构造函数方式)。因为构造函数只是一个函数,所以可使ClassA构造函数成为ClassB的方法,然后调用它。ClassB就会收到ClassA的构造函数中定义的属性和方法。

function ClassA(name) {    this.name = name;    this.sayName = function () {        console.log(this.name);
    };
}function ClassB(name,age) {    this.classA = ClassA;    this.classA(name);    delete this.classA;    this.age = age;    this.sayAge = function(){        console.log(this.age);
    }
}var tom = new ClassA('Tom');var jerry = new ClassB('Jerry',25);
tom.sayName();                         //'Tom'jerry.sayName();                       //'Jerry'jerry.sayAge();                        //25console.log(tom instanceof ClassA);    //trueconsole.log(jerry instanceof ClassA);  //falseconsole.log(jerry instanceof ClassB);  //true

所有新属性和新方法都必须在删除了新方法的代码行后定义,因为可能会覆盖超类的相关属性和方法

对象冒充可以实现多重继承
如果存在ClassA和ClassB,这时ClassC想继承这两个类,如下:

function ClassA(name){    this.name = name;    this.sayName = function (){        console.log(this.name);
    }
}function ClassB(age){    this.age = age;    this.sayAge = function(){        console.log(this.age);
    }
}function ClassC(name,age){    this.method = ClassA;    this.method(name);    
    this.method = ClassB;    this.method(age);    delete this.method;
}var tom = new ClassC('Tom',25);
tom.sayName();                       //'Tom';tom.sayAge();                        //25console.log(tom instanceof ClassA);  //falseconsole.log(tom instanceof ClassB);  //falseconsole.log(tom instanceof ClassC);  //true

这种实现方式的缺陷是:如果两个类ClassA和ClassB具有同名的属性或方法,ClassB具有高优先级,因为它从后面的类继承。
由于这种继承方法的流行,ECMAScript的第三版为Function对象加入了两个方法,即call()和apply()。

call方法是与经典的对象冒充方法最相似的方法。它的第一个参数用作this的对象,其他参数都直接传递给函数自身

function sayName(prefix) {    console.log(prefix + this.name);
};var tom = {};
tom.name = "Tom";
sayName.call(tom, 'This is ');  //'This is Tom'

函数sayName在对象外定义,但也可以引用this。
call方法改写对象冒充

function ClassA(name){    this.name = name;    this.sayName = function(){        console.log(this.name);    }}function ClassB(name,age){    //this.method = ClassA;    //this.method(name);    //delete this.method;    ClassA.call(this,name);    this.age = age;    this.sayAge = function (){        console.log(this.age);    }}var tom = new ClassB('Tom',25);tom.sayName();                       //'Tom'tom.sayAge();                        //25console.log(tom instanceof ClassA);  //falseconsole.log(tom instanceof ClassB);  //true

call方法替代了使用属性引用ClassA的方式。

apply

apply方法有两个参数,用作this的对象和要传递给函数的参数数组

function sayName(prefex,mark) {    console.log(prefex+ this.name+ mark);
};var tom = {};
tom.name = 'Tom';
sayName.apply(tom, ['This is ','!']);  //'This is Tom!'

同样可以使用apply改写对象冒充

function ClassA(name){    this.name = name;    this.sayName = function(){        console.log(this.name);    }}function ClassB(name,age){    ClassA.apply(this,arguments);    this.age = age;    this.sayAge = function (){        console.log(this.age);    }}var tom = new ClassB('Tom',25);tom.sayName();                       //'Tom'tom.sayAge();                        //25  console.log(tom instanceof ClassA);  //falseconsole.log(tom instanceof ClassB);  //true

只有超类中参数顺序和子类中的参数完全一致时才可以传递参数数组

原型链

prototype对象是个模板,要实例化的对象都以这个模板为基础,prototype对象的任何属性和方法都被传递给这个类的所有实例,原型链就是利用这种功能来实现继承机制。

function ClassA() {}ClassA.prototype.name = 'Tom';ClassA.prototype.sayName = function () {    console.log(this.name);};function ClassB() {}ClassB.prototype = new ClassA();var tom = new ClassB();tom.sayName();                       //'Tom'console.log(tom instanceof ClassA);  //trueconsole.log(tom instanceof ClassB);  //true

这里把ClassB的prototype属性设置称ClassA的实例,避免逐个赋值prototpye属性。
在调用ClassA时没有设置参数,因为在原型链中要确保构造函数是无参的。
在原型链中,instanceof的结果也有了变化,对于ClassA和ClassB都返回了true。

因为prototype属性的重指定,子类中的新属性都必须出现在prototype被赋值后。

阳光订餐系统
阳光订餐系统

欢迎使用阳光订餐系统,本系统使用PHP5+MYSQL开发而成,距离上一个版本1.2.8发布已经有一年了。本系统集成了留言本,财务管理,菜单管理,员工管理,安全管理,WAP手机端等功能,并继续继承1.X老版本简单、实用、美观的特点,在老版本上的基础上做了如下更新:1.更简洁的前台与后台,菜单及功能布局更合理。2.更合理的文件结构,合理适度的模板机制以及OO运用,更易于理解的代码,更适于二次开发;3.

下载
function ClassA() {}ClassA.prototype.name = 'Tom';ClassA.prototype.sayName = function () {    console.log(this.name);};function ClassB() {}ClassB.prototype = new ClassA();ClassB.prototype.age = 25;ClassB.prototype.sayAge = function () {    console.log(this.age);};var tom = new ClassA();var jerry = new ClassB();tom.sayName();                         //'Tom'jerry.sayName();                       //'Tom'jerry.name = 'Jerry';tom.sayName();                         //'Tom'jerry.sayName();                       //'Jerry'jerry.sayAge();                        //25console.log(tom instanceof ClassA);    //trueconsole.log(jerry instanceof ClassA);  //trueconsole.log(jerry instanceof ClassB);  //true

原型链的缺陷是不能实现多重继承,因为类的prototype会被重写。

混合方式

对象冒充的问题是必须使用构造函数方式,而使用原型链就无法使用带参数的构造函数,不过,可以试试两者结合。
用对象冒充继承构造函数的属性,用原型链继承prototype的方法。

function ClassA(name) {    this.name = name;
}
ClassA.prototype.sayName = function () {    console.log(this.name);
};function ClassB(name, age) {
    ClassA.call(this, name);    this.age = age;
}
ClassB.prototype = new ClassA();
ClassB.prototype.sayAge = function () {    console.log(this.age);
};var tom = new ClassA('Tom');var jerry = new ClassB('Jerry',25);console.log(tom instanceof ClassA);                    //trueconsole.log(jerry instanceof ClassA);                  //trueconsole.log(jerry instanceof ClassB);                  //trueconsole.log(jerry.constructor === ClassA);             //trueconsole.log(ClassB.prototype.constructor === ClassA);  //true

在ClassB构造函数中用对象冒充继承了ClassA的name属性,用原型链继承了ClassA的sayName方法,由于使用了原型链继承方式,instanceof运行方式正常。
但是constructor属性暴露出了问题,每一个prototype对象都有一个constructor属性指向它的构造函数,而ClassB实例的构造函数却指向了ClassA,这会导致继承链的错乱。可以手动修改constructor的指向。

function ClassA(name) {    this.name = name;
}
ClassA.prototype.sayName = function () {    console.log(this.name);
};function ClassB(name, age) {
    ClassA.call(this, name);    this.age = age;
}
ClassB.prototype = new ClassA();
ClassB.prototype.constructor = ClassB;
ClassB.prototype.sayAge = function () {    console.log(this.age);
};var tom = new ClassA('Tom');var jerry = new ClassB('Jerry',25);console.log(tom instanceof ClassA);                    //trueconsole.log(jerry instanceof ClassA);                  //trueconsole.log(jerry instanceof ClassB);                  //trueconsole.log(ClassA.constructor === ClassB);            //falseconsole.log(jerry.constructor === ClassA);             //falseconsole.log(ClassB.prototype.constructor === ClassA);  //false

直接继承原型链

为了节省内存,可以不执行创建ClassA实例,直接让ClassB的原型指向ClassA的原型

function ClassA(name) {    this.name = name;
}
ClassA.prototype.sayName = function () {    console.log(this.name);
};function ClassB(name, age) {
    ClassA.call(this, name);    this.age = age;
}
ClassB.prototype = ClassA.prototype;
ClassB.prototype.constructor = ClassB;
ClassB.prototype.sayAge = function () {    console.log(this.age);
};var tom = new ClassA('Tom');var jerry = new ClassB('Jerry',25);console.log(ClassA.prototype.hasOwnProperty('sayAge'));  //trueconsole.log(ClassA.prototype.constructor === ClassB);   //true

这样的缺陷是由于直接修改原型链指向,对于ClassB原型链中的属性也会影响到ClassA上,于是就出现了ClassA具有sayAge方法、ClassA的构造函数属性为ClassB。

空对象作中介

为解决直接继承原型链的缺点,可以利用一个空对象作为中介。

function ClassA(name) {    this.name = name;
}
ClassA.prototype.sayName = function () {    console.log(this.name);
};function ClassB(name, age) {
    ClassA.call(this, name);    this.age = age;
}var fn = function(){};
fn.prototype = ClassA.prototype;
ClassB.prototype = new fn();
ClassB.prototype.constructor = ClassB;
ClassB.prototype.sayAge = function () {    console.log(this.age);
};console.log(ClassA.prototype.hasOwnProperty('sayAge'));  //falseconsole.log(ClassA.prototype.constructor === ClassB);    //false

虽然还是创建了对象实例,但由于空对象几乎不占内存,修改ClassB的原型也不会影响到ClassA。

封装成extends方法

function extends(child,parent){    var fn = function (){};
    fn.prototype = parent.prototype;
    child.prototype = new fn();
    child.prototype.constructor = child;
    child.super = parent.prototype;
}

JS的灵活性使我们可以通过多种方式实现继承,了解其中的原理和实现可以帮助我们在不同的场景中选择适合的方法。

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

用JS代码做出弹幕效果

用H5的canvas做出弹幕效果

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
俄罗斯Yandex引擎入口
俄罗斯Yandex引擎入口

2026年俄罗斯Yandex搜索引擎最新入口汇总,涵盖免登录、多语言支持、无广告视频播放及本地化服务等核心功能。阅读专题下面的文章了解更多详细内容。

178

2026.01.28

包子漫画在线官方入口大全
包子漫画在线官方入口大全

本合集汇总了包子漫画2026最新官方在线观看入口,涵盖备用域名、正版无广告链接及多端适配地址,助你畅享12700+高清漫画资源。阅读专题下面的文章了解更多详细内容。

35

2026.01.28

ao3中文版官网地址大全
ao3中文版官网地址大全

AO3最新中文版官网入口合集,汇总2026年主站及国内优化镜像链接,支持简体中文界面、无广告阅读与多设备同步。阅读专题下面的文章了解更多详细内容。

79

2026.01.28

php怎么写接口教程
php怎么写接口教程

本合集涵盖PHP接口开发基础、RESTful API设计、数据交互与安全处理等实用教程,助你快速掌握PHP接口编写技巧。阅读专题下面的文章了解更多详细内容。

2

2026.01.28

php中文乱码如何解决
php中文乱码如何解决

本文整理了php中文乱码如何解决及解决方法,阅读节专题下面的文章了解更多详细内容。

4

2026.01.28

Java 消息队列与异步架构实战
Java 消息队列与异步架构实战

本专题系统讲解 Java 在消息队列与异步系统架构中的核心应用,涵盖消息队列基本原理、Kafka 与 RabbitMQ 的使用场景对比、生产者与消费者模型、消息可靠性与顺序性保障、重复消费与幂等处理,以及在高并发系统中的异步解耦设计。通过实战案例,帮助学习者掌握 使用 Java 构建高吞吐、高可靠异步消息系统的完整思路。

8

2026.01.28

Python 自然语言处理(NLP)基础与实战
Python 自然语言处理(NLP)基础与实战

本专题系统讲解 Python 在自然语言处理(NLP)领域的基础方法与实战应用,涵盖文本预处理(分词、去停用词)、词性标注、命名实体识别、关键词提取、情感分析,以及常用 NLP 库(NLTK、spaCy)的核心用法。通过真实文本案例,帮助学习者掌握 使用 Python 进行文本分析与语言数据处理的完整流程,适用于内容分析、舆情监测与智能文本应用场景。

24

2026.01.27

拼多多赚钱的5种方法 拼多多赚钱的5种方法
拼多多赚钱的5种方法 拼多多赚钱的5种方法

在拼多多上赚钱主要可以通过无货源模式一件代发、精细化运营特色店铺、参与官方高流量活动、利用拼团机制社交裂变,以及成为多多进宝推广员这5种方法实现。核心策略在于通过低成本、高效率的供应链管理与营销,利用平台社交电商红利实现盈利。

122

2026.01.26

edge浏览器怎样设置主页 edge浏览器自定义设置教程
edge浏览器怎样设置主页 edge浏览器自定义设置教程

在Edge浏览器中设置主页,请依次点击右上角“...”图标 > 设置 > 开始、主页和新建标签页。在“Microsoft Edge 启动时”选择“打开以下页面”,点击“添加新页面”并输入网址。若要使用主页按钮,需在“外观”设置中开启“显示主页按钮”并设定网址。

72

2026.01.26

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 4.3万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 2.5万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号