• javascript原型链继承


    一、关于javascript原型的基本概念:

    prototype属性:每个函数都一个prototype属性,这个属性指向函数的原型对象。原型对象主要用于共享实例中所包含的的属性和方法。

    constructor属性:每个原型对象都有一个constructor属性,这个constructor属性包含一个指向prototype属性所在函数的指针。 例如 Foo.prototype.constructor指向Foo函数。这个属性是只读的。

    __proto__属性(ES6通过对__proto__属性进行标准化):创建一个构造函数的实例后,这个实例包含一个指针,指向这个构造函数的原型对象,这个指针叫做[[Prototype]],在chrome、Safari、Firefox下可通过对象的__proto__属性访问。__proto__属性是实例才拥有的,在javascript中函数也是对象,它是Function类型的实例, 所以函数也有__proto__属性。

    我们来看这样一个关系图:

        (图片来自:http://www.mollypages.org/misc/js.mp)

      通过这个关系图,我们可以得到以下信息:

    • 实例的__proto__属性始终指向它构造函数的原型对象:
    1 function Foo(){};
    2 var foo=new Foo();
    3 console.log(foo.__proto__===Foo.prototype); //true
    4 console.log(Foo.__proto__===Foo.constructor.prototype);//ture
    • 所有对象的原型最终都会指向Object对象的原型:
    1 function Foo(){};
    2 var foo=new Foo();
    3 console.log(foo.__proto__); //指向Foo构造函数的原型
    4 console.log(foo.__proto__.__proto__); //指向Object构造函数的原型
    5 console.log(foo.__proto__.__proto__.__proto__); //null
    • 用户自定义函数的__proto__属性指向Function.prototype,所以它们都是Function构造函数的实例。

    二、开始说原型链继承:

      现在,有了前面基本概念的了解,我再说关于原型链的继承,首先来看以下代码:

     1 function Foo(name){
     2     this.name=name;
     3 }
     4 Foo.prototype.myName=function(){
     5         console.log("My name is "+this.name);
     6 }
     7 
     8 function Bar(name){
     9      this.name=name;
    10 }
    11 Bar.prototype=new Foo(); //Bar的原型指向Foo的实例
    12 var bar=new Bar("Tom");
    13 bar.myName();//输出:”my name is Tom“

      以上代码实现了Bar构造函数继承了Foo构造函数的myName()方法。继承是通过原型链的查找来实现的,原型链的查找规则是:当实例调用一个属性(或方法)时,首先会在这个实例中查找该属性(或方法),在没有找到的情况下,会继续在这个实例的原型上查找,如果依旧找不到这个属性(或方法),搜索过程会沿着原型链向上查找,直到原型链的末端,整个查找过程才会停止。上面例子的原型链关系如图:

         例子中当实例bar调用myName()方法时,会首先在bar这个实例中查找有没有myName()这个方法,如果没有找到,则会在Bar.prototype上查找,在Bar.prototype上没有找到的情况下,继续在Foo.prototype上查找,结果在Foo.prototype上找到了该方法。

       为什通过 “Bar.prototype=new Foo()” 能够实现这样有继承关系的原型链呢?我们可以通过以下代码来验证:

     1 function Foo(name){
     2     this.name=name;
     3 }
     4 Foo.prototype.myName=function(){
     5         console.log("my name is "+this.name);
     6 }
     7 
     8 function Bar(name){
     9      this.name=name;
    10 }
    11 
    12 var foo=new Foo();
    13 Bar.prototype=foo;
    14 var bar=new Bar();
    15 bar.__proto__===Bar.prototype;  //返回true
    16 bar.__proto__===foo; //返回true
    17 bar.__proto__.__proto__===foo.__proto__; //返回true
    18 foo.__proto__===Foo.prototype; //返回true,证明了Bar 继承了Foo

       或许你会问通过“Bar.prototype=new Foo()”能够实现继承,为什么不是“Bar.prototype=Foo.prototype”呢?好的,下面先看这段简单的代码:  

    1 a={a:1,b:2};
    2 b=a;
    3 b.c=3;
    4 console.log(a.c); //3 ,a和b是引用类型

      看完这段代码,我们想象一下,Bar.prototype  和Foo.prototype也是Object类型的,所以它们之间相互赋值,将指向相同数据地址,若修改Bar原型上的属性,Foo原型上的同名属性也会被修改,来看看下面的示例:

     1 function Foo(){}
     2 Foo.prototype.name="Tom";
     3 Foo.prototype.sayName=function(){
     4  console.log("My name is " +this.name);
     5 }
     6 var foo=new Foo();
     7 foo.sayName();//"My name is Tom"
     8 function Bar(){}
     9 
    10 Bar.prototype=Foo.prototype;
    11 Bar.prototype.name="Jerry";
    12 var bar=new Bar();
    13 bar.sayName();//"My name is Jerry",也能Foo原型上的方法
    14 foo.sayName();//"My name is Jerry",Foo原型上的name属性已经被修改

      通过上面的示例我们可以看到,当“Bar.prototype=Foo.prototype”时,如果给Bar.prototype上添加一个name属性,Foo.prototype上name属性也将随之被修改,我们知道继承的目的就是子函数(子类)复用、重写、扩展父函数(父类)的方法,但继承决不允许改变父函数(父类)的方法和属性 ,所以Bar.prototype=Foo.prototype是不能实现继承的。
      那么让“Bar.prototype=Foo”能不能实现继承呢?我们来用代码验证一下:

    1 function Foo(){}
    2 function Bar(){}
    3 Bar.prototype=Foo;
    4 var bar=new Bar();
    5 bar.__proto__===Bar.prototype; //true
    6 bar.__proto__===Foo; //true
    7 Foo.__proto__===Function.prototype; //ture
    8 Function.prototype.__proto__===Object.prototype; //ture
    9 Object.prototype.__proto__===null; //ture

      通过bar.__proto__向上查找不到Foo.prototype,所以Bar构造函数是不能继承Foo构造函数的。

    参考资料:《javascript高级程序设计》

    =============================================================================================

    本文地址:http://www.cnblogs.com/liubaozhe/p/4618989.html 

  • 相关阅读:
    MySQL——sql语句处理时间——时间、字符串、时间戳互相转换
    MySQL——sql语句处理时间——日期加减天数
    Spring Boot——jpaProperties.getHibernateProperties()的使用
    Spring Boot——SpringBoot2+JPA+druid配置多数据源
    Spring Boot——log4j日志配置案例
    git命令——git 分支操作
    windows如何删除默认打开方式
    excel导出出现弹框
    笔记
    javascript中三个等号"==="是什么意思
  • 原文地址:https://www.cnblogs.com/liubaozhe/p/4618989.html
Copyright © 2020-2023  润新知