zoukankan      html  css  js  c++  java
  • js中的原型对象/prototype

    前置任务

    在说原型对象是什么之前,我们先讨论一下对象是什么东西
    在说对象是什么之前,我们又得讨论一下引用类型

    引用类型


    首先,js 中变量的值分两种类型

    • 引用类型
    • 值类型

    关于这两种类型,我们需要从内存的角度来看

    var num = 9527            //值类型
    var str = "一段字符串"     // 值类型
    var obj = {               // 引用类型
      attr_1:"qwer",
      attr_2:"df"
      }
    

    上面这些数据,在内存中可能是这样的

    可以看到

    • 值类型的numstr两个变量,变量名直接对应具体值
    • 引用类型的obj这个变量对应的是一段地址,而这个地址的位置存的才是真正的obj的具体值(对象)

    至于为什么要这么存,这跟内存的管理有关就不展开说,简单的

    你妈妈给你生了五个可爱的妹妹

      for(var i=0;i<5;i++){
        var 妹妹i号=new 妹妹()
      }
    

    每个妹妹都是new出来的一个对象,她们都有一些属性,比如

    妹妹1号:{
      age:3
      name:妹妹1号,
      parent:{
        妈妈:你的妈妈,
        爸爸:你的爸爸
      }
    }
    

    每个妹妹的agename属性都是不同的,而parent属性都是相同的,这时候如果每个妹妹都存一份parent就太浪费内存了,所以我们可以存个地址.内存中这个地址的位置存真正的parent信息,这样就可以很好的利用起宝贵的内存空间啦

    ps: 我们建立一个概念,一个对象是一个独立的'块',而不是妹妹i号.parent这样一条属性,妹妹i号.parent这条属性指向一个对象,也不用纠结,先往下看

    对象

    前面我们说了,对象是独立的块内存,要想访问或者操作对象,就得通过该对象的的地址,而变量存储的就是这个地址

    然后我们来看

    var obj = {
      attr_1: "qwer",
      attr_2: "df"
    };
    var obj_2=obj
    
    obj_2.attr_1="qwqaqaaaaaawer"
    
    console.log(obj.attr_1) //qwqaqaaaaaawer
    

    这样,为什么改的是obj_2.attr_1而打印obj.attr_1的时候是qwqaqaaaaaawer应该就很清楚了

    原型对象

    无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个 prototype 属性,这个属性指向函数的原型对象

    注意两点

    • 函数的prototype属性指向函数的原型对象,而不是说prototype就是原型对象,prototype是地址,内存中这个地址的位置上的东西才是原型对象
    • 函数也是对象,所以函数也可以有属性

    拓展阅读: 为什么要创建原型对象

    在默认情况下,所有原型对象都会自动获得一个 constructor(构造函数)属性,这个属性包含一个指向 prototype 属性所在函数(下图这个例子中的a)的地址。看图理解:

    到目前为止,内存中是这样的

    思考题:为什么a.prototype.constructor==a
    答案:a.prototype.constructora指向同一块内存

    上面说,创建了自定义的构造函数之后,其原型对象默认会取得 constructor 属性

    然鹅:


    这个a.prototype.toString函数根本没有定义,上面的内存图中也看不到它,那它是从哪哪冒出来的???

    至于其原型对象的其他方法,则都是从 Object 继承而来的。

    (这个__proto__是什么,看下面的详细讲解)

    当调用构造函数创建一个新实例后(是一个对象),该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象。

    es5 中管这个指针叫[[Prototype]]。虽然在 js 中没有标准的方式访问[[Prototype]]

    但 Firefox、Safari 和 Chrome 在每个对象(函数的原型对象也是对象,所以也有__proto__属性)上都支持一个属性__proto__

    再来看一遍这段代码:

    • a.prototype指向原型对象,原型对象是由构造函数Ojbect生成的
    • Object也是一个函数,是Object.prototype指向Object的原型对象
    • 思考题: a.prototype.__proto__是函数a的原型对象的一条属性,这个属性的属性值是一个地址,那么内存中这个地址存的是什么?
      答案: 存的是Object的原型对象
      附内存图一张,方便理解:

    这个连接存在于实例的原型对象与构造函数的原型对象之间,而不是存在于实例与构造函数之间

    a的原型对象是由构造函数Object生成的,他们两个之间存在链接(通过__proto__)

    接着说,js中,有这样一条规则:访问一条属性(假设是属性attr)时,在当前对象(假设是obj)中找不到的,就往obj.__proto__找,即obj.__proto__.attr,再找不到,就往obj.__proto__.__proto__找,直到找到或者obj.__proto__.......null才停止

    所以 前面的a.prototype.toString实际上是a.prototype.__proto__.toString也就是Object.tostring

  • 相关阅读:
    数据挖掘入门系列教程(九)之基于sklearn的SVM使用
    问题_001_Vivian
    TypeScript学习笔记(五)
    TypeScript学习笔记(四)
    TypeScript学习笔记(三)
    TypeScript学习笔记(二)
    TypeScript学习笔记(一)
    使用Visual Studio Code开发Asp.Net Core WebApi学习笔记(十)-- 发布(Windows)
    使用Visual Studio Code开发Asp.Net Core WebApi学习笔记(九)-- 单元测试
    使用Visual Studio Code开发Asp.Net Core WebApi学习笔记(八)-- 多环境开发
  • 原文地址:https://www.cnblogs.com/riwang/p/12409928.html
Copyright © 2011-2022 走看看