java prototype_js中的原型对象/prototype

前置任务

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

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

引用类型

15dbc36793416be342488bf13520983f.png

2f13060d61625e15b19f4cd6bba29285.png

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

引用类型

值类型

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

var num = 9527 //值类型

var str = "一段字符串" // 值类型

var obj = { // 引用类型

attr_1:"qwer",

attr_2:"df"

}

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

48badc70578e7d85e8c2b09b5e5cde71.png

可以看到

值类型的num和str两个变量,变量名直接对应具体值

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

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

849a6141f897153c320eb4b7a0d1d318.png

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

for(var i=0;i<5;i++){

var 妹妹i号=new 妹妹()

}

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

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

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

9a3da789d83a5976faad833ac8e1e571.png

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是地址,内存中这个地址的位置上的东西才是原型对象

函数也是对象,所以函数也可以有属性

b84ac35cc680d205930520ff3d404e3f.png

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

cd410be384818fe41e89f5cbcd749e21.png

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

f96c58f1f169f452a0777ca9cc623855.png

思考题:为什么a.prototype.constructor==a

答案:a.prototype.constructor和a指向同一块内存

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

20c50b7c5be9689d50690d2c06d86065.png

然鹅:

050ac67dc00b19e045e7315f772956a8.png

ad42d43291631ed8f59f0d7c79bb7497.png

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

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

5bdbc31467bae69b6c1055b3e2a12216.png

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

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

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

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

再来看一遍这段代码:

5bdbc31467bae69b6c1055b3e2a12216.png

a.prototype指向原型对象,原型对象是由构造函数Ojbect生成的

Object也是一个函数,是Object.prototype指向Object的原型对象

思考题: a.prototype.__proto__是函数a的原型对象的一条属性,这个属性的属性值是一个地址,那么内存中这个地址存的是什么?

答案: 存的是Object的原型对象

附内存图一张,方便理解:

6f3e49d866a4686585a8b15cdb4a7bf8.png

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值