资讯专栏INFORMATION COLUMN

JavaScript 继承方式详解

YuboonaZhang / 3335人阅读

摘要:原型继承与类继承类继承是在子类型构造函数的内部调用父类型的构造函数原型式继承是借助已有的对象创建新的对象,将子类的原型指向父类。

JavaScript 继承方式的概念

js 中实现继承有两种常用方式:

</>复制代码

  1. 原型链继承(对象间的继承)
  2. 类式继承(构造函数间的继承)

JavaScript不是真正的面向对象的语言,想实现继承可以用JS的原型prototype机制或者callapply方法

在面向对象的语言中,可以使用类来创建一个自定义对象,当然ES6中也引入了class来创建类。在这之前,我们需要使用js的原型来创建自定义对象。

原型继承与类继承

类继承是在子类型构造函数的内部调用父类型的构造函数

</>复制代码

  1. function Super (){
  2. this.colors = ["blue","red"];
  3. }
  4. function Sub () {
  5. Super.call(this);
  6. }

原型式继承是借助已有的对象创建新的对象,将子类的原型指向父类。

</>复制代码

  1. function Super (id) {
  2. this.id = id;
  3. }
  4. Super.prototype.toString = function () {
  5. return "Super" + this.id;
  6. }
  7. function Sub (id) {
  8. this.id = id;
  9. }
  10. Sub.prototype = new Super(); // 这句即原型式继承的核心代码
原型链继承

为了让子类继承父类的属性和方法,首先需要定义一个构造函数,然后将父类的实例赋值给构造函数的原型。

</>复制代码

  1. function Parent () {
  2. this.name = "Parent";
  3. }
  4. function Child () {
  5. this.age = 10;
  6. }
  7. Chid.prototype = new Parent(); // Chid继承Parent,形成原型链
  8. var test = new Child();
  9. console.log(test.name) // Parent
  10. console.log(test.age) // 10 得到被继承的属性
  11. // 继续原型链继承
  12. function Brother () {
  13. this.weight = 60;
  14. }
  15. Brother.prototype = new Child();
  16. var peter = new Brother();
  17. console.log(peter.name) //继承了Child和Parent,输出Parent
  18. console.log(peter.age) // 输出10

所有的构造函数都继承自Object,它是自动完成继承的并不需要我们手动继承,那么接着看它们的从属关系

确定原型和实例的关系

可以通过两种方式确定原型和实例的关系,通过操作符instanceofisPrototypeof()方法

</>复制代码

  1. console.log(peter instanceof Object); //true
  2. console.log(test instanceof Brother) //false,test是brother的父类
  3. console.log(peter instanceof Child) //true
  4. console.log(peter instanceof Parent) //true

只要是原型链中出现过的原型,都可以说是改原型链派生的实例的原型。因此,isProtptypeof()方法也会返回true

在JS中,被继承的函数成为父类(或者 基类、超类),继承的函数成为子类(派生类)。使用原型继承主要有两个问题,一是字面量重写原型会中断关系,使用引用类型的原型,并且子类型无法给父类型传递参数。

伪类解决引用共享和超类型无法传参的问题,我们可以采用"类式继承"的方式

类式继承(借用构造函数)

</>复制代码

  1. function Parent (age) {
  2. this.colors = ["blue","red","green"];
  3. this.age = age;
  4. }
  5. function Child (age) {
  6. Parent.call(this,age);
  7. }
  8. var peter = new Child(20);
  9. console.log(peter.age) //20
  10. console.log(peter.colors) //blue,red,green
  11. peter.colors.push("white");
  12. console.log(peter.colors) //blue,red,green,white

借用构造函数虽然解决了上面两张问题,但没有原型,所以我们需要原型链+借用构造函数的模式,这种模式成为组合继承

组合继承

</>复制代码

  1. function Parent (age) {
  2. this.colors = ["blue","red","green"];
  3. this.age = age;
  4. }
  5. Parent.prototype.run = function () {
  6. return this.colors + " is " +this.age;
  7. }
  8. function Child (age) {
  9. Parent.call(this,age); //对象冒充,给父类型传参
  10. }
  11. Child.prototype = new Parent(); //原型链继承
  12. var peter = new Child(20);
  13. console.log(peter.run()); //blue,red,green is 20

组合继承是一种比较常用的方法,思路是使用原型链实现对原型属性和方法的继承,借用构造函数来实现对实例属性的继承。这样,既实现了原型上定义方法的函数复用,又保证每个实例都有自己的属性。

call()与apply()的用法:调用一个对象的一个方法,用另一个对象替换当前对象。

</>复制代码

  1. call(thisObj,Object); // call接收一个对象
  2. apply(thisObj,[argArray]) //apply接收一个数组
原型式继承

这种继承借助原型并基于已有的对象创建新的对象,同时还不用创建自定义类型的方式成为原型式继承

</>复制代码

  1. function obj(o) {
  2. function F() {}
  3. F.prototype = o;
  4. return new F();
  5. }
  6. var box = {
  7. name : "peter",
  8. arr : ["blue","red","green"]
  9. };
  10. var b1 = obj(box);
  11. console.log(b1.name) // peter
  12. b1.name = "jack";
  13. console.log(b1.name) //jack
  14. console.log(b1.arr) //blue,red,green
  15. b1.arr.push("white") //blue,red,green,white
  16. var b2 = obj(box);
  17. console.log(b2.name) // peter
  18. console.log(b1.arr) //blue,red,green

原型式继承首先在obj()函数内部创建一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回这个临时类型的新实例。

寄生式继承

这种继承方式是把原型式+工厂模式结合起来,目的是为了封装创建的过程。

</>复制代码

  1. function create(o){
  2. var f = obj(o);
  3. f.run = function () {
  4. return this.arr;//同样,会共享引用
  5. };
  6. return f;
  7. }
组合式继承的问题

组合式继承是JS最常用的继承模式,但组合继承的父类型会在使用过程中被调用两次,一次是创建子类型的时候,另一次是在子类型构造函数的内部

</>复制代码

  1. function Parent(name){
  2. this.name = name;
  3. this.arr = ["哥哥","妹妹","父母"];
  4. }
  5. Parent.prototype.run = function () {
  6. return this.name;
  7. };
  8. function Child(name,age){
  9. Parent.call(this,age);//第二次调用
  10. this.age = age;
  11. }
  12. Child.prototype = new Parent();//第一次调用

以上代码是组合继承,那么寄生组合继承解决了两次调用的问题

寄生组合继承

</>复制代码

  1. function obj() {
  2. function F() {}
  3. F.prototype = o;
  4. return new F();
  5. }
  6. function create(parent,test) {
  7. var f = obj(parent.prototype); //创建对象
  8. f.constructor = test; //增强对象
  9. }
  10. function Parent(name){
  11. this.name = name;
  12. this.arr = ["brother","sister","parents"];
  13. }
  14. Parent.prototype.run = function () {
  15. return this.name;
  16. };
  17. function Child(name,age){
  18. Parent.call(this,name);
  19. this.age =age;
  20. }
  21. inheritPrototype(Parent,Child); //通过这里实现继承
  22. var test = new Child("peter",20);
  23. test.arr.push("new");
  24. console.log(test.arr); //brother,sister,parents,new
  25. console.log(test.run()); //只共享了方法
  26. var test2 = new Child("jack",22);
  27. console.log(test2.arr); //引用问题解决
call和apply

call和apply可以用来改变函数中this的指向:

</>复制代码

  1. // 定义一个全局函数
  2. function f () {
  3. console.log(this.name);
  4. }
  5. // 定义一个全局变量
  6. var name = "peter";
  7. var obj = {
  8. name: "jack";
  9. };
  10. f.apply(window); //apple, 此时this 等于window 相当于window.f()
  11. f.apply(obj); //jack, 此时this === obj 相当于obj.f()

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/79043.html

相关文章

  • JavaScript继承方式详解

    摘要:可以通过构造函数和原型的方式模拟实现类的功能。原型式继承与类式继承类式继承是在子类型构造函数的内部调用超类型的构造函数。寄生式继承这种继承方式是把原型式工厂模式结合起来,目的是为了封装创建的过程。 js继承的概念 js里常用的如下两种继承方式: 原型链继承(对象间的继承) 类式继承(构造函数间的继承) 由于js不像java那样是真正面向对象的语言,js是基于对象的,它没有类的概念。...

    Yangyang 评论0 收藏0
  • JavaScript深入浅出

    摘要:理解的函数基础要搞好深入浅出原型使用原型模型,虽然这经常被当作缺点提及,但是只要善于运用,其实基于原型的继承模型比传统的类继承还要强大。中文指南基本操作指南二继续熟悉的几对方法,包括,,。商业转载请联系作者获得授权,非商业转载请注明出处。 怎样使用 this 因为本人属于伪前端,因此文中只看懂了 8 成左右,希望能够给大家带来帮助....(据说是阿里的前端妹子写的) this 的值到底...

    blair 评论0 收藏0
  • javaScript原型及原型链详解(二)

    摘要:当然这还没完,因为我们还有重要的一步没完成,没错就是上面的第行代码,如果没有这行代码实例中的指针是指向构造函数的,这样显然是不对的,因为正常情况下应该指向它的构造函数,因此我们需要手动更改使重新指向对象。 第一节内容:javaScript原型及原型链详解(二) 第一节中我们介绍了javascript中的原型和原型链,这一节我们来讲利用原型和原型链我们可以做些什么。 普通对象的继承 ...

    widuu 评论0 收藏0
  • javascript对象详解:__proto__和prototype的区别和联系

    摘要:当这步完成,这个对象就与构造函数再无联系,这个时候即使构造函数再加任何成员,都不再影响已经实例化的对象了。此时,对象具有了和属性,同时具有了构造函数的原型对象的所有成员,当然,此时该原型对象是没有成员的。 前言 本篇文章用来记录下最近研究对象的一些心得,做一个记录与总结,以加深自己的印象,同时,希望也能给正在学习中的你一点启发。本文适合有一定JavaScript基础的童鞋阅读。原文戳这...

    chavesgu 评论0 收藏0
  • 前端文档收集

    摘要:系列种优化页面加载速度的方法随笔分类中个最重要的技术点常用整理网页性能管理详解离线缓存简介系列编写高性能有趣的原生数组函数数据访问性能优化方案实现的大排序算法一怪对象常用方法函数收集数组的操作面向对象和原型继承中关键词的优雅解释浅谈系列 H5系列 10种优化页面加载速度的方法 随笔分类 - HTML5 HTML5中40个最重要的技术点 常用meta整理 网页性能管理详解 HTML5 ...

    jsbintask 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<