10.1 JS中的原型

start

多年以前学过JS中的原型,但是并没有彻底理解。导致每次看到 prototype —> 头大。

深入学习JS的过程中才发现,原型无处不在。

时至今日,就让我再学习一次 JavaScript 中的原型,顺便做个总结。


1. prototype属性

我定义一个函数 Tomato,然后打印一下它。

function Tomato() {

}

// 为了展示更详细的信息,我这里使用 `console.dir`
console.dir(Tomato)

image.png

可以发现函数Tomato,除了基本的几个属性,它还有一个属性:prototype

函数的prototype属性是什么?可以到上面的截图,就是一个对象。

结论

在JavaScript中,我们创建一个函数A(就是声明一个函数), 那么浏览器就会在内存中创建一个对象B,而且每个函数都默认会有一个属性 prototype 指向了这个对象B( 即:prototype的属性的值是这个对象 )。这个对象B就是函数A的原型对象,简称函数的原型。


2. [[Prototype]]

基于函数 Tomato,我去new 一个对象 t1,然后打印一下t1

function Tomato() {
}

var t1 = new Tomato

console.dir(t1)

image.png

new 出来的对象 t1 只有一个属性 [[Prototype]]

小提示:

  • 双中括号的属性是系统内置属性。

如何打印它

  • 可以通过Object.getPrototypeOf(t1)来获取t1的属性[[Prototype]]

  • 也可以通过t1.__proto__来获取t1的属性 [[Prototype]] (ps:不要觉得__proto__看起来很复杂,简单理解它就是一个属性名。某些时候为了防止变量名重复,命名时会在名称前后加两个下划线。)

打印出来的效果

console.log(t1.__proto__)
console.log(Object.getPrototypeOf(t1))

image.png

结论

对象的__proto__属性是什么?可以看到它的打印,也是一个对象。

每个实例对象都有一个属性__proto__,它也指向了一个对象。

3. prototype__proto__之间的联系

我们去比较一下prototype__proto__这两个属性的值。

function Tomato() {

}

var t1 = new Tomato()

// 直接全等于,发现返回的是true。
console.log(t1.__proto__ === Tomato.prototype)  // true

得到它们的关系图
image.png

结论

对象的__proto__属性,默认值为构造函数的prototype属性值


4. prototype__proto__区分

这个地方容易混淆,这里单独拿出来记录一下。

  • 每个函数function都有一个prototype,即显式原型(属性)
  • 每个实例对象都有一个 __proto__,即隐式原型(属性 )
  • 对象的隐式原型的值为对应构造函数的显式原型的值.

5. 原型对象中的constructor

image.png

上面打印可以看到,原型对象中有一个constructor属性,它指向我们函数对象。

image.png


6. 原型链

既然我们new出来的对象t1有一个属性__proto__,并且指向了一个原型对象。原型对象也是对象啊,那么原型对象的属性__proto__指向什么?

打印一下

function Tomato() {
    console.log('我是Tomato')
}

var t1 = new Tomato()
console.log(t1.__proto__)
console.log(t1.__proto__.__proto__)
console.log(t1.__proto__.__proto__.__proto__)

image.png

代码不清晰,我继续画图

image.png

这个__proto__指向的链条就是我们的原型链。感觉就是对象和对象之间的隐式链条,它的终点是null

7. 知道这些东西有什么用?

废话不多说,直接上代码:

function Tomato() {

}

// 1. 首先既然 `Tomato.prototype` 是一个对象,那么现在给对象中添加一些属性
Tomato.prototype.a = '我是Tomato的原型对象上的属性a'
Tomato.prototype.b = '我是Tomato的原型对象上的属性b'

Tomato.prototype.c = function () {
    console.log('我是Tomato的原型对象上的方法c')
}
Tomato.prototype.d = function () {
    console.log('我是Tomato的原型对象上的方法d')
}

var t1 = new Tomato()


// 2. 其次 t1 本身是一个空对象。 我也给它添加一些属性
t1.a = '你好'

// 3. 打印一下t1
console.log(t1)
console.log(t1.a)
console.log(t1.b)
console.log(t1.c)
console.log(t1.d)

console.log(t1.e)

输出结果:

image.png

确认一下,是不是从原型对象上获取的。

console.log(t1.b===Tomato.prototype.b) // true
console.log(t1.c===Tomato.prototype.c) //true

执行完上方的代码会发现,t1本身是只有一个a属性的,但是我打印 t1.b,t1.c,
会将Tomato.prototype上的同名属性打印出来了。

当我们访问一个对象的属性的时候

  1. 先在自身属性上寻找,找到了就返回。
  2. 如果没有 就沿着__proto__这条链向上查找,找到返回。
  3. 如果最终没有找到,就返回 undefined。

第二条我这里没有演示,可以自行测试一下。

end

  • 原型的基本知识点就这些啦。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lazy_tomato

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值