zoukankan      html  css  js  c++  java
  • 原型与原型链的理解

    前言

    javascript语言是一种面向对象的语言,它没有"子类"和"父类"的概念,里面所有的数据类型都是对象,这一点与Java非常相似。如何将这些对象联系起来呢?

    Brendan Eich在考虑设计继承机制的时候,参考了C++和JAVA使用new命令,通过调用类的构造函数生成实例的方式,将new命令引入javascript。

    C++的写法是:

    ClassName *object = new ClassName(param);

    Java的写法是:

     Person person = new Person();

    但是,javascript里面没有“类”这个概念,那么,Brendan Eich决定直接在new后面跟一个构造函数,来生成实例。

    原型对象

    构造函数是什么?构造函数与其他函数唯一的区别在于调用方式不同。任何函数只要通过new来调用就可以作为构造函数,它是用来创建特定类型的对象。

    举例来说,下面定义一个构造函数Animal,表示动物对象的原型。

      function Animal(name){
        this.name = name;
        this.sex = 'female';     }

    new运算符的缺点

    通过new命令来生成一个dog实例:

    var dog= new Animal("小K")

    这里,构造函数Animal就是实例对象dog的原型!!!Animal里的this关键字就指的是dog这个对象!

    new出来的dog对象此时已经和Animal再无联系了!也就是说每一个new出来的实例都有自己的属性和方法的副本,是独立的的!修改其中一个不会影响另一个!

    用构造函数生成实例对象,有一个缺点,那就是无法共享属性和方法。

    var dog1= new Animal("小A");
    var dog2= new Animal("小B");
    
    dog2.sex = 'male';
    
    console.log(dog1.sex)      // female
    console.log(dog2.sex)      // male

    但是,我们希望构造函数中的sex属性是一个共有属性,那么此时用这样的方法,每个实例中都有一个相同的sex属性,会造成资源极大的浪费!

    prototype属性的引入

    那么原型对象就即将登场了!Brendan Eich决定给每一个构造函数都设置一个prototype属性,这个属性就指向原型对象。其实原型对象就只是个普通对象,里面存放着所有实例对象需要共享的属性和方法!所以,我们把需要共享的放到原型对象里,把那些不需要共享的属性和方法存在在构造函数里!

            function Animal(name){
                this.name = name;
            }
    
            Animal.prototype.eat= 'food';
    
            var dog1= new Animal("小A");
            var dog2= new Animal("小B");
            
            console.log(dog1.eat)      // food
            console.log(dog1.eat)      // food
    
            Animal.prototype.eat= 'water';
    
            console.log(dog1.eat)      // water
            console.log(dog2.eat)      // water

    可以看出,修改prototype属性会影响它的所有实例的eat的值!!

    实例一旦创建出来就会自动引用prototype对象的属性和方法!所以实例对象的属性和方法一般分为两种:一种是自身的,一种是引用自prototype的。

    具体实现是这样的:

    每当代码读取某个对象的某个属性的时候,都会执行一次搜索。首先从对象实例本身开始,如果在实例中找到了该属性,则返回该属性的值,如果没有找到,则顺着原型链指针向上,到原型对象中去找,如果如果找到就返回该属性值。

    这里要提一点,如果为对象实例添加了一个属性与原型中同名,则该属性会屏蔽掉原型中的同名属性,不会去修改它!使用delete可以删除实例中的属性提到delete那要插一句~delete只能删除对象下的属性,不能删除变量和参数!

    原型链

    事实上,js里依靠"原型链"(prototype chain)模式来实现继承。

    上面说完原型对象。下面要扒一扒proto、prototype、constructor。

    • proto:事实上就是原型链指针!!

    • prototype:上面说到这个是指向原型对象的

    • constructor:每一个原型对象都包含一个指向构造函数的指针,就是constructor

    继承实现方式:

    为了实现继承,proto会指向上一层的原型对象,而上一层的结构依然类似,那么就利用proto一直指向Object的原型对象上!Object.prototype.__proto__ = null;表示到达最顶端。如此形成了原型链继承。

    下面有个图解非常经典,可以自己手画了一遍去理解,真的非常有效~

    大致总结一下就是:

    1、Object是作为众多new出来的实例的基类 function Object(){ [ native code ] }

    2、Function是作为众多function出来的函数的基类 function Function(){ [ native code ] }

    3、构造函数的proto(包括Function.prototype和Object.prototype)都指向Function.prototype

    4、原型对象的proto都指向Object.prototype

    5、Object.prototype.proto指向null




    参考资料:


  • 相关阅读:
    常见的代码报错信息总结(持续更新ing)
    ASCII码对照表
    python ord()与chr()用法以及区别
    Python random模块sample、randint、shuffle、choice随机函数
    日志相关
    tensorflow学习笔记
    tar 解压缩命令详解
    pandas使用
    相似度与距离计算python代码实现
    逻辑回归原理(python代码实现)
  • 原文地址:https://www.cnblogs.com/gaoht/p/11276277.html
Copyright © 2011-2022 走看看