正式说继承之前,有两个相关小点:
  1. JS只支持实现继承,即继承实际的方法,不支持接口继承(即继承方法的签名,但JS中函数没签名)
  2. 所有对象都继承了Object.prototype上的属性和方法。
  • 说继承之前还要再说一下原型。原型之所以很重要,原因之一就是可以利用它来实现JavaScript的继承。重写一个函数的原型对象,将其指定为另一个函数的实例,这样便实现了一个简单的原型链继承。
看一个利用原型链来实现继承的基础例子:
 
  1. function Super(){
  2. this.name='super';
  3. }
  4. Super.prototype.getName=function(){
  5. console.log(this.name);
  6. }
  7. function Sub(){
  8. this.name='sub';
  9. }
  10.  
  11. Sub.prototype=new Super();//重写原型,实现继承
  12. var instance=new Sub();
  13. instance.getName();//sub继承了getName方法

重写原型会让Sub的原型获得Super构造函数上和Super原型上的所有属性和方法; 但是这样单纯使用原型来继承也有问题,比如将上面的代码修改一下,在原型上添加一个引用类型的属性:

  1. function Super() {
  2. this.name='super';
  3. }
  4. Super.prototype.getName=function() {
  5. console.log(this.name);
  6. };
  7. Super.prototype.color = ["red", "black"];
  8.  
  9. function Sub() {
  10. }
  11.  
  12. Sub.prototype=new Super();//实现继承
  13.  
  14. var instance=new Sub();
  15. instance.color.push('white');//改变instance的color属性,push一个新的项
  16. var ins = new Sub();
  17. console.log(ins.color); //["red", "black", "white"] 可以看到ins的color属性也被改变了
可以看到在instance中修改color属性,但是在另一个实例ins中这个修改也被反映出来了,这就是一个问题。
  • ①  借用构造函数(又叫经典继承,伪造对象)
如果将属性和方法都写在原型上,利用其共享性来实现继承理论上没有问题,但是原型链的继承共享性固然好,可一个问题就出在其共享性上,对于引用类型的值,当在一个实例上修改了引用类型值之后,其他共享该引用类型的所有实例都随之改变了,如下:
  1. function Arr(){
  2. }
  3. Arr.prototype.array=['red','black'];
  4. arr01=new Arr();
  5. arr02=new Arr();
  6. arr01.array.push('white');
  7. console.log(arr02.array);//["red", "black", "white"]
综上所以一般很少单独使用原型链,于是就有了借用构造函数这种思维,虽然这种做法也有一定的局限,如下: 
  1. function superType(){
  2. this.color=['red','blue','yellow'];
  3. }
  4. function subType(){
  5. //继承了superType
  6. superType.call(this);
  7. }
  8.  
  9. var instance01=new subType();
  10. instance01.color.push('black');
  11. console.log(instance01.color);//['red','blue','yellow','black']
  12.  
  13. var instance02=new subType();
  14. console.log(instance02.color);//['red','blue','yellow']

借用构造函数这种方法主要就是:利用parent . call(this)来继承父级构造函数上公有的属性,且在一个实例上进行修改不会对其他实例造成影响;[ 注意:使用call这种不能继承原型上属性和方法的哦 ]

当然,如果上面的例子中superType()有参数的话,在subType函数内部调用时也可以为其传递参数:superType . call(this,parameter);
 
  • ②  下面来说JS中最常用的继承模式:组合继承
  1. function superType(name){
  2. this.name=name;
  3. this.color=['red','blue','yellow'];
  4. }
  5. superType.prototype.sayName=function(){
  6. console.log(this.name);
  7. }
  8.  
  9. function subType(name,age){
  10. //继承superType的属性
  11. superType.call(this,name);
  12. this.age=age;
  13. }
  14. //继承superType的方法
  15. subType.prototype=new superType();
  16. subType.prototype.constructor=subType;
  17. subType.prototype.sayAge=function(){
  18. console.log(this.age);
  19. };
  20.  
  21. var instance01=new subType('lazy',20);
  22. instance01.color.push('black');
  23. console.log(instance01.color);//['red','blue','yellow','black']
  24. instance01.sayAge();//
  25. instance01.sayName();//lazy
  26.  
  27. var instance02=new subType('chen',21);
  28. console.log(instance02.color);//['red','blue','yellow']
  29. instance02.sayAge();//
  30. instance02.sayName();//chen
 
这种方法就是既利用了call()来继承构造函数中公有的属性,同时又利用原型来继承原型对象上的属性和方法;这样让subType的实例既可以分别拥有各自独立的属性,也可以共用相同的方法了。
 
JS中用得做多的继承是组合式继承,而组合式继承最大的问题就是每次new一个subType的实例时,都会两次调用父级构造函数superType;
第一次是在重写subType的原型  : subType.prototype = new superType()  的时候。这一次调用让subType获得了superType构造函数上和原型对象上的属性和方法,且这些属性和方法是加在subType的原型对象中的;
第二次是在function subType(){

    superType.call(this,name);

      }
的时候,这一次在调用call方式时只获得了superType构造函数上的属性。注意这一次是在调用subtype构造函数创建subtype的实例,所以这次获得的属性方法是加在subType的实例中的,且这些实例中的属性其实会覆盖前面原型中同名的属性;
这样算起来每new一个subType的实例,就会两次调用superType。虽然这样两次下来就完全包含了superType的全部实例属性和方法,但执行了两次superType效率不算高。所以我们再来看另一个方法:
  • ③  寄生组合式继承
这种方法可以解决两次调用superType的情况,实际上 思路跟组合式继承是一样的;
  1. function superType(name){
  2. this.name=name;
  3. this.color=['red','blue','yellow'];
  4. }
  5. superType.prototype.sayName=function(){
  6. console.log(this.name);
  7. }
  8.  
  9. function subType(name,age){
  10. //继承superType
  11. superType.call(this,name);
  12. this.age=age;
  13. }
  14.  
  15. function inheritPrototype(sub,sup){
  16. //创建超类型构造函数的原型副本
  17. var prototype=Object(sup.prototype);
  18. //为其指定构造函数,增强对象
  19. prototype.constructor=sub;
  20. //重写sub的原型对象
  21. sub.prototype=prototype;
  22. }
  23.  
  24. //copy一份超类型构造函数的原型对象给子类型构造函数
  25. inheritPrototype(subType,superType);
  26.  
  27. subType.prototype.sayAge=function(){
  28. console.log(this.age);
  29. };
  30.  
  31. var instance01=new subType('lazy',20);
  32. instance01.color.push('black');
  33. console.log(instance01.color);//['red','blue','yellow','black']
  34. instance01.sayAge();//
  35. instance01.sayName();//lazy
  36.  
  37. var instance02=new subType('chen',21);
  38. console.log(instance02.color);//['red','blue','yellow']
  39. instance02.sayAge();//
  40. instance02.sayName();//chen

这种方法主要依然是利用   借用构造函数的方法来继承构造函数的属性,利用原型链的混合方法来继承方法;基本思路是:不必为了重写subType的原型而去调用一次superType,因为我们需要的也只是superType的原型对象的一个副本而已,所以有了inheritPrototype函数:

  1. function inheritPrototype ( sub ,super) {
  2. var prototype = Object( super.prototype ); //创建副本
  3. sub.prototype = prototype ;
  4. prototype . constructor = sub ;
  5. }
相比组合式继承这种方法高效率的地方就在于它只调用了一次superType构造函数;
  • ④寄生式继承 :在主要考虑对象而不是自定义类型和构造函数的情况下,寄生式继承也是一种很有用的模式,看个例子:
  1. function createAnother(original) {
  2. var clone = Object(original);
  3. clone.sayHi = function () {
  4. console.log('hi');
  5. };
  6. return clone;
  7. }
  8.  
  9. var person = {
  10. name: 'lazy',
  11. friends:[1,2,3]
  12. };
  13.  
  14. var anotherPerson = createAnother(person);
  15. anotherPerson.sayHi();
  16. console.log(anotherPerson.name);

这个例子中,基于person对象创建了一个新的对象anotherPerson,这个新的对象不仅具有person的所有属性和方法,而且还有自己的sayHi方法;

菜鸟小白一枚,可能上述有错误或理解不对的地方,恳请指出~~谢谢!

详细理解JS中的继承的更多相关文章

  1. 【学习笔记】六:面向对象的程序设计——理解JS中的对象属性、创建对象、JS中的继承

    ES中没有类的概念,这也使其对象和其他语言中的对象有所不同,ES中定义对象为:“无序属性的集合,其属性包含基本值.对象或者函数”.现在常用的创建单个对象的方法为对象字面量形式.在常见多个对象时,使用工 ...

  2. 怎么理解js中的事件委托

    怎么理解js中的事件委托 时间 2015-01-15 00:59:59  SegmentFault 原文  http://segmentfault.com/blog/sunchengli/119000 ...

  3. JS中的继承(上)

    JS中的继承(上) 学过java或者c#之类语言的同学,应该会对js的继承感到很困惑--不要问我怎么知道的,js的继承主要是基于原型(prototype)的,对js的原型感兴趣的同学,可以了解一下我之 ...

  4. 图文结合深入理解 JS 中的 this 值

    图文结合深入理解 JS 中的 this 值 在 JS 中最常见的莫过于函数了,在函数(方法)中 this 的出现频率特别高,那么 this 到底是什么呢,今天就和大家一起学习总结一下 JS 中的 th ...

  5. 深入理解JS中的对象(三):class 的工作原理

    目录 序言 class 是一个特殊的函数 class 的工作原理 class 继承的原型链关系 参考 1.序言 ECMAScript 2015(ES6) 中引入的 JavaScript 类实质上是 J ...

  6. 深入理解Js中的this

    深入理解Js中的this JavaScript作用域为静态作用域static scope,但是在Js中的this却是一个例外,this的指向问题就类似于动态作用域,其并不关心函数和作用域是如何声明以及 ...

  7. js中实现继承的几种方式

    首先我们了解,js中的继承是主要是由原型链实现的.那么什么是原型链呢? 由于每个实例中都有一个指向原型对象的指针,如果一个对象的原型对象,是另一个构造函数的实例,这个对象的原型对象就会指向另一个对象的 ...

  8. 如何更好的理解js中的this,分享2段有意思的代码

    关于js中this的浅析,大家可以点击[彻底理解js中this的指向,不必硬背]这篇博客了解. 今天遇到2段比较有意思的代码. ----------------第一段----------------- ...

  9. JS中的继承(下)

    JS中的继承(下) 在上一篇 JS中的继承(上) 我们介绍了3种比较常用的js继承方法,如果你没看过,那么建议你先看一下,因为接下来要写的内容, 是建立在此基础上的.另外本文作为我个人的读书笔记,才疏 ...

随机推荐

  1. 11-jQuery简介和选择器

    # jQuery > jQuery是一个是免费.开源的javascript库, 也是目前使用最广泛的javascript函数库.>> jQuery极大的方便你完成web前段的相关操作 ...

  2. NodeJS、npm安装步骤和配置(windows版本)

    https://jingyan.baidu.com/article/48b37f8dd141b41a646488bc.html 上面这个链接很详细了,怕它没了自己记一遍.我的简洁一点. 1. 打开no ...

  3. C# 模拟页面登录

    using System; using System.Collections; using System.Collections.Generic; using System.IO; using Sys ...

  4. Kintex7XC7K325T板卡七仙女

  5. Taro -- 定义全局变量

    Taro定义全局变量 方法1:在taro中 getApp()只能取到一开始定义的值,并不能取到改变后的值 // app.js文件中 class App extends Component { cons ...

  6. LINUX VSFTP配置及安装

    ------------------转载:亲身实践,确实好用(http://www.cnblogs.com/jack-Star/p/4089547.html) 1.VSFTP简介 VSFTP是一个基于 ...

  7. 02scikit-learn模型训练

    模型训练 In [6]: import numpy as np import matplotlib.pyplot as plt from sklearn.linear_model import Lin ...

  8. keras 下载预训练模型报错SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:852)

    import ssl ssl._create_default_https_context = ssl._create_unverified_context https://stackoverflow. ...

  9. bzoj5118 Fib数列2 二次剩余+矩阵快速幂

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5118 题解 这个题一看就是不可做的样子. 求斐波那契数列的第 \(n\) 项,\(n \leq ...

  10. IndexError: list index out of range的错误原因

    第1种可能情况list[index]index超出范围 第2种可能情况list是一个空的 没有一个元素进行list[0]就会出现该错误 ————————————————版权声明:本文为CSDN博主「m ...