一文让你搞懂javascript如何实现继承

这篇具有很好参考价值的文章主要介绍了一文让你搞懂javascript如何实现继承。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、本文想给你聊的东西包含一下几个方面:(仅限于es6之前的语法哈,因为es6里面class这关键字用上了。。)

1.原型是啥?原型链是啥?

2.继承的通用概念。

3.Javascript实现继承的方式有哪些?

 文章来源地址https://www.toymoban.com/news/detail-439522.html

二、原型是啥?原型链是啥?

1.原型是函数本身的prototype属性。

首先js和java不一样,js顶多算是一个基于对象的语言,而不是标准的面向对象的语言。

所以我们谈继承,只能是基于new关键字作用域构造函数的场景。

上代码:

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

    console.log(Person.prototype);

                                                                                                                                               代码 1

一文让你搞懂javascript如何实现继承

                                          图1

 定义一个构造函数,默认起原型就是一个Object对象,相当于一个new Object()。

而且还有一个new出来的对象有一个隐式原型属性__proto__,也指向了构造函数的原型。

也就是说: Person.prototype   === new Person().__proto__。

用图来表示就是:

一文让你搞懂javascript如何实现继承

                                                                                图2

 

在上图中,我把Object.prototype 叫rootObject,那么rootObject中就有了所有对象都共享的方法,如下图:

一文让你搞懂javascript如何实现继承

                                           图3

 如果person.toString()方法调用,那么起自身没有toString方法,就是走__proto__指向的原型对象中找,而object中也没有

所有就找到了根对象。所以构造函数原型对象存在的意义是使得该构造函数产生的对象可以共享属性和方法

所以原型对象中的属性和方法就类似于java类中定义的static属性和方法,所有对象都可以共享。

那么如上图2所示,person  ->  object  -> rootObject之间就形成了原型链

 

二、继承的通用概念

如果一个类B继承了类A,在java中这些写:class B extends A{}  

那么类B就拥有了A中的所有属性和方法。

继承是面向对象编程的一大特性,目的很简单,就是复用。

 

三、javascript中实现继承的方式有哪些?

1.原型链

假如有个构造函数Student想要继承Person函数,想拥有Person中的属性和方法,可以使用原型链来实现。

上代码

// 定义Person
function Person(name,age) {
// 保证属性有初始值
this.name = name ? name : "";
this.age = (age || age === 0) ? age : 0;
this.setName = function (name) {
this.name = name;
}
this.setAge = function (age) {
this.age = age;
}
this.getPersonInfo = function () {
return "[Person]: " + this.name + "_" + this.age;
}
}
// 定义一个所有Person对象都能共享的属性和方法
Person.prototype.typeDesc = "人类";
Person.prototype.hello = function () {
console.log("hello");
}
function Student(score) {
this.score = score;
this.setScore = function (score) {
this.score = score;
}
this.getStudentInfo = function () {
return "[Student:]: " + this.score;
}
}
// 修改Student的原型
Student.prototype = new Person();

let student1 = new Student(90);
let student2 = new Student(80);
let student3 = new Student(70);

console.log(student1.typeDesc); // 能访问

student1.setName("aa");
student1.setAge(99);
console.log(student1.getPersonInfo()); // 能访问

console.log(student1.getStudentInfo()); // 能访问

                                                                                                                                                  代码2

给你一张图吧  更清楚

一文让你搞懂javascript如何实现继承

                                                                                                                     图 4

 

老铁,你思考下?虽然看似student1对象能访问了能访问了Person中定义的方法和属性,但是有没有问题呢?

 本来name,age是对象的私有属性,不属于“类级别”,但是他们却出现在了Student的原型对象中,而且此时如果你

console.log(student2.name),发现其访问到了原型person对象的name属性了,是个初始的空字符串,这里为什么要在Person函数中使用初始值,

这个在工作中是很常见的,对象创建出来一般属性都是需要初始值的。

所以原型链实现继承,缺点是:原型对象中多出了一些没必要的属性。

而且由于student2和student3等其他Student的对象仍然能访问到原型对象person中的属性,这会让人产生错觉,以为他们也拥有name,age的私有属性。

于是,你接着看下面的方式。

 

2.复用构造方法

这东西严格来讲,我感觉不太像继承,但是好像用起来还挺好用,起码省事了。。。。

继续哈,上代码啊(改变一下代码2)

    // 定义Person
    function Person(name,age) {
        // 保证属性有初始值
        this.name = name ? name : "";
        this.age = (age || age === 0) ? age : 0;
        this.setName = function (name) {
            this.name = name;
        }
        this.setAge = function (age) {
            this.age = age;
        }
        this.getPersonInfo = function () {
            return "[Person]: " + this.name + "_" + this.age;
        }
    }
    // 定义一个所有Person对象都能共享的属性和方法
    Person.prototype.typeDesc = "人类";
    Person.prototype.hello = function () {
        console.log("hello");
    }
    function Student(name, age, score) {
        // 使用call调用函数,可以改变this指向,服用了父类的构造方法
        Person.call(this, name,age);
        this.score = score;
        this.setScore = function (score) {
            this.score = score;
        }
        this.getStudentInfo = function () {
            return "[Student:]: " + this.score;
        }
    }
    let student1 = new Student("aa", 99, 99);
    console.log(student1.typeDesc);  // undefined
    console.log(student1.hello);   // undefined
    console.log(student1.getStudentInfo());  // 能访问
    console.log(student1.getPersonInfo());   // 能访问

                                                                                                                          代码 3

此时虽然,虽然复用了Person构造函数,但是原型Person的原型student1无法访问到。

缺点很明显:虽然复用了Person的构造函数,但是却没有继承Person的原型

好了,我们演变一下。。

 

3.共享原型

基于上述代码3,在Student函数后面加入如下代码:

Student.prototype = Person.prototype;

                                代码 4

其实就是两个构造函数都指向同一原型。。

此时发现,student1能访问Person原型上的内容了。

还是要问一下,这样就行了吗?

问题:一旦Student向原型里面加了变量或者函数,或者修改原型中的变量内容时,哪怕是Person构造出来的对象,

同样也感知到了。。。。  这样互相影响的话,两个构造函数的原型中的变量和函数掺杂在一起,确实不合适

那怎么办呢?

来吧,看看下面的变种。

 

4.圣杯模式

说实话我也不知道为啥取名叫圣杯模式,感觉也不是官方的命名,有些人还叫其他名字。

把代码4替换成如下代码:

    // 定义空函数
    function F() {}
    // 空函数和Person共享原型
    F.prototype = Person.prototype;
    // 改变Student的原型
    Student.prototype = new F();
    // 添加原型上的构造函数
    Student.prototype.constructor = Student;

                                                                                                             代码 5

这样做Student的原型和Person的原型就不是一个对象了,而且不像原型链那样,由于new Person()作为Student.prototype导致该原型对象中包含了Person对象的私有属性。

来吧,给你个最终版本的代码,希望能帮助到你,能力有限,相互借鉴哈。。

 

5.圣杯模式+复用构造函数(算是比较完美了)

 

    // 定义Person
    function Person(name,age) {
        // 保证属性有初始值
        this.name = name ? name : "";
        this.age = (age || age === 0) ? age : 0;
        this.setName = function (name) {
            this.name = name;
        }
        this.setAge = function (age) {
            this.age = age;
        }
        this.getPersonInfo = function () {
            return "[Person]: " + this.name + "_" + this.age;
        }
    }
    // 定义一个所有Person对象都能共享的属性和方法
    Person.prototype.typeDesc = "人类";
    Person.prototype.hello = function () {
        console.log("hello");
    }
    function Student(name, age, score) {
        // 使用call调用函数,可以改变this指向,服用了父类的构造方法
        Person.call(this, name,age);
        this.score = score;
        this.setScore = function (score) {
            this.score = score;
        }
        this.getStudentInfo = function () {
            return "[Student:]: " + this.score;
        }
    }
    // 定义空函数
    function F() {}
    // 空函数和Person共享原型
    F.prototype = Person.prototype;
    // 改变Student的原型
    Student.prototype = new F();
    // 添加原型上的构造函数
    Student.prototype.constructor = Student;


    let student1 = new Student("aa", 99, 99);
    console.log(student1.typeDesc);  // 人类
    student1.hello();   // hello
    console.log(student1.getStudentInfo());  // 能访问
    console.log(student1.getPersonInfo());   // 能访问

    let student2 = new Student("bb", 33, 88);
    student2.setScore(89);
    // student2和student1都各自有自己的私有属性,并不会受影响。
    console.log(student1.getStudentInfo());
    console.log(student2.getStudentInfo());

    Student.prototype.temp = "新加属性";
    console.log(Person.prototype.temp);  // undefined

                                                                                                               代码 6

总结:可能我们在平常工作中很少这样写代码,或者用到这种继承模式,但是框架中很有可能会用到这些思想。

圣杯模式是共享原型模式的一个变种,使用空函数F来作为中间桥梁,巧妙得解决了共享原型模式的问题,同时

也解决了原型链模式的产生多余属性的问题。

 

到了这里,关于一文让你搞懂javascript如何实现继承的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android 动态分区详解(一) 5 张图让你搞懂动态分区原理

    本文主要包含动态分区的物理数据布局,内存核心数据结构和动态分区映射示例 3 个部分。 如果你对动态分区没啥概念,建议直接从头阅读 如果只关心动态分区在设备上是如何存储的,请跳转到第 3 节 如果只关心动态分区在内存中的数据结构,请跳转到第 4 节 如果想看动态

    2023年04月08日
    浏览(29)
  • 【C标准库】详解fopen函数 一篇让你搞懂fopen函数

    创作不易,感谢支持! ‾ underline{创作不易,感谢支持! } 创作不易,感谢支持! ​ fopen函数 头文件:stdio.h 功能是打开一个文件,其声明格式是: 文件指针名 = fopen(文件名,使用文件方式) “文件名”是被打开文件的文件名,类型是C风格字符串。 “使用文件方式”是指文

    2024年02月03日
    浏览(25)
  • 一篇文章让你搞懂TypeScript中的typeof()、keyof()是什么意思

    知识专栏 专栏链接 TypeScript知识专栏 https://blog.csdn.net/xsl_hr/category_12030346.html?spm=1001.2014.3001.5482 有关TypeScript的相关知识可以前往TypeScript知识专栏查看复习!! 最近在 前端的深入学习过程 中,接触了与 网络请求 相关的内容,于是计划用三个专栏( HTTP 、 Axios 、 Ajax )和零碎

    2023年04月21日
    浏览(43)
  • Nginx配置详解,一文带你搞懂Nginx

    1 基本概念 1.1 Nginx简介 Nginx是一个高性能的HTTP和反向代理服务器,特点是占用内存少,并发能力强,事实上Nginx的并发能力确实在同类型的网页服务器中表现好。Nginx专为性能优化而开发,性能是其最重要的考量,实现上非常注重效率,能经受高负载的考验,有报告表明能支

    2024年01月16日
    浏览(33)
  • 一文带你搞懂sklearn.metrics混淆矩阵

    一般的二分类任务需要的评价指标有4个 accuracy precision recall f1-score 四个指标的计算公式如下   计算这些指标要涉及到下面这四个概念,而它们又构成了混淆矩阵 TP (True Positive) FP (False Positive) TN (True Negative) FN (False Negative) 混淆矩阵 预测值 0 1 实际值 0 TN FP 1 FN TP 这里我给出的

    2024年02月06日
    浏览(29)
  • C/S、B/S架构详解,一文带你搞懂

      CS架构(Client-Server Architecture)是一种分布式计算模型,其中客户端和服务器之间通过网络进行通信。在这种架构中,客户端负责向服务器发送请求,并接收服务器返回的响应。服务器则负责处理客户端的请求,并返回相应的结果。CS架构通常用于构建大型的网络应用程序,

    2024年02月16日
    浏览(72)
  • 一文带你搞懂PyTorch中所有模型查看的函数model.modules()系列

    model一般继承nn.Model 他的实例一般具有几个有序 字典 , _modules,_parameters,_buffers,表示当前model的子模块,自己注册的parameters和buffers 注意,_modules字典keys对应子模块名字,value对应子模块的实例,所以可以迭代的调用子模块的子模块,比如下面两个函数 因为是字典,所以可

    2024年02月06日
    浏览(31)
  • 【MDX】一文带你搞懂SQL Server Analysis Services 的安装和使用

    目录 Step 1: Install developer and management tools 安装 new stand-alone SQL Server installation or add the feature to an existing installation 安装 SQL Server Management Studio 安装 SSDT 安装 Visual Studio Step 2: Install databases Step 3: Install projects Step 4: 创建项目 Step 5: 定义数据源 Step 6: 部署Analysis Services项目 Step 7: F

    2023年04月08日
    浏览(38)
  • 【微信小程序】一文带你搞懂小程序的页面配置和网络数据请求

    每个小程序页面都有一个 .json 文件,该文件用来对小程序的页面进行配置。 小程序中,每个页面都有自己的.json配置文件,用来对当前页面的窗口外观、页面效果等进行配置。 小程序中,app.json中的 window 节点,可以全局配置小程序中 每个页面 的窗口表现。 如:当在app.js

    2024年02月02日
    浏览(32)
  • 让你搞懂怎么解决LF、CRLF问题LF will be replaced by CRLF the next time Git touched it

    大家好,我是小饼鹅,让我们一起学习吧   如果我们正在应用的windows系统进行开发工作的话,我们很有可能在对代码进行git add 的时候会看到以下warning: LF will be replaced by CRLF the next time Git touched it 很多人可能并不会特别在意,因为它貌似并没有对我们产生什么影响,可是真

    2024年02月09日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包