zoukankan      html  css  js  c++  java
  • js原型链结构理解

    在一般的面向对象的语言中,都存在类(class)的概念,类就是对象的模板,对象就是类的实例。

    但在js中是没有类的定义的(万物皆是对象)。  题外话:但是在ES6中提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。

    为了在对象直接建立联系(如继承),起初通过构造函数(constructor)实现。但是构造函数存在一个弊端,那就是同一个对象实例之间,无法共享属性。如下:

     1 function Person(name,height){
     2   this.name=name;
     3   this.height=height;
     4   this.hobby=function(){
     5     return 'watching movies';
     6   }
     7 }
     8 var boy=new Person('aa',180);
     9 var girl=new Person('bb',153);
    10 console.log(boy.name); //'aa'
    11 console.log(girl.name); //'bb'
    12 console.log(boy.hobby===girl.hobby); //false

    上面代码中boy和girl的hobby方法是不一样的。也就是说,每当你使用new来调用构造函数放回一个对象实例的时候,都会创建一个hobby方法。这既没有必要,又浪费资源,因为所有hobby方法都是同样的行为,完全可以被两个对象实例共享。

    为了解决构造函数的对象实例之间无法共享属性的缺点,js提供了prototype属性,即引入了原型链的概念。

    下面我们进入正题:

    原型即构造函数的prototype属性,对于该构造函数的实例通过__proto__来访问。对于构造函数来说,它是一个属性,对于对象实例来说,它是一个原型对象。

    首先明确: 函数(Function)才有prototype属性,对象(除Object)只拥有__proto__。

    关于构造函数、实例、原型直接的关系,话不多说,直接上图:

    其中要说明的是Function是js中的一等公民,所有函数都是Function的实例:

        ①本地对象:独立于宿主环境(浏览器)的对象——包括Object、Array、Date、RegExp、Function、Error、Number、String、Boolean

        ②内置对象——包括Math、Global(window,在js中就是全局变量),使用的时候不需要new

        ③宿主对象——包括自定义对象、DOM、BOM

    理解完结构之后,来看代码:

     1 function Person(name,height){
     2   this.name=name;
     3   this.height=height;
     4 }
     5 Person.prototype.hobby=function(){
     6   return 'watching movies';
     7 }
     8 var boy=new Person('aa',180);
     9 var girl=new Person('bb',153);
    10 console.log(boy.name); //'aa'
    11 console.log(girl.name); //'bb'
    12 console.log(boy.hobby===girl.hobby); //true

    将hobby方法放在原型对象上,那么两个实例对象都共享着同一个方法。

    其中原型对象的属性不是对象实例的属性。对象实例的属性是继承自构造函数定义的属性,因为构造函数内部有一个this关键字来指向将要生成的对象实例。

    对象实例的属性,其实就是构造函数内部定义的属性。只要修改原型对象上的属性和方法,变动就会立刻体现在所有对象实例上。

    原型链(prototype chains)

      对象的属性和方法,有可能是定义在自身,也有可能是定义在它的原型对象。由于原型对象本身对于对象实例来说也是对象,它也有自己的原型,所以形成了一条原型链(prototype chain)。

    即通过图片最右侧的线路fun --> Fun()的prototype --> Object的prototype

    所有一切的对象的原型顶端,都是Object.prototype,即Object构造函数的prototype属性指向的那个对象。

    当然,Object.prototype对象也有自己的原型对象,那就是没有任何属性和方法的null对象,而null对象没有自己的原型。

    console.log(Object.getPrototypeOf(Object.prototype)); //null   getPrototypeOf用来返回对象Objiect.prototype指向的原型(即Object.prototype.__proto__) 
    console.log(Person.prototype.isPrototypeOf(boy))
    //true isPrototypeOf用来判断Person.prototype是否在boy的原型链(不单单只上一个原型)上

    原型链(prototype chain)的特点有:

        a:读取对象的某个属性时,JavaScript引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。如果直到最顶层的Object.prototype还是找不到,则返回undefined。

        b:如果对象自身和它的原型,都定义了一个同名属性,那么优先读取对象自身的属性,这叫做“覆盖”(overiding)。

        c:一级级向上在原型链寻找某个属性,对性能是有影响的。所寻找的属性在越上层的原型对象,对性能的影响越大。如果寻找某个不存在的属性,将会遍历整个原型链。

    还有一个问题就是原型是如何产生的呢?其实就是通过new关键字来实现的。

    此处应该明确函数(Function)才有prototype属性,对象(除Object)只拥有__proto__。

    这就是自定义的构造函数的实例没有prototype属性的原因,个人认为是Function在定义时内部就写好了protoytpe属性(这个一个对象)供其实例继承。

    下面就是new关键字进行的操作:

    var obj  = {};
    obj.__proto__ = Base.prototype;  //我们将这个对象obj的__proto__成员指向了构造函数Base对象的prototype属性(成员对象)
    Base.call(obj);  //当通过原型链调用到Base对象的prototype成员对象中的属性时,this指针仍执行obj

    结构学习完毕,其作用以及利用其实现多种继承方式的功能还在学习中。

    个人总结日志,若有相似之处,是因为您文章写的特别好,学习借鉴了一下,还忘见谅。

  • 相关阅读:
    JSP基础语法
    Tomcat服务器的安装及配置
    数据库连接失败出现4064错误
    错误页跳转
    Eclipse配置jstl标准标签库详解
    tomcat文件目录结构及功能介绍
    警告: [SetPropertiesRule]{Context/Loader} Setting property 'useSystemClassLoaderAsParent' to 'false' did not find a matching property.
    tomcat:A docBase * inside the host appBase has been specifi, and will be ignored
    Prim算法
    (值类型引用类型)和null的关系
  • 原文地址:https://www.cnblogs.com/GisNicer/p/12584553.html
Copyright © 2011-2022 走看看