为了账号安全,请及时绑定邮箱和手机立即绑定

关于原型你需要知道的几个问题

标签:
JavaScript

为了良好的代码高亮阅读体验,建议您查看github原文

前言

prototype是js面向对象的一个重要机制,于是总结了以下几个问题,理解起来会比较有针对性。

1. prototype__proto__ 的关系是什么?

prototype是只有函数才会有的属性;而__proto__是所有对象都有的属性。

几乎所有的函数都有一个prototype属性,prototype上挂载的所有属性和方法都可以被这个函数的实例继承。

对于

function Foo(){}const foo=new Foo()// 注意这里:无论在实例化前后在prototype上添加属性实例都会继承Foo.prototype.isTestable=trueconsole.log(foo.isTestable) // true

Foo.prototype===foo.__proto__ //truefoo.constructor===Foo // trueFoo.constructor===Function // trueFoo===foo.__proto__.constructor // true

是不是看起来很乱?祭上我多年收藏的此图!!OVO

webp

demo

2. 自有属性和原型属性又是什么?

上面的例子中,在调用foo.isTestable时,先会在实例上查询是否有isTestable这个属性;如果没有找到,再往它的__proto__上查询这个属性;直至查到底层没有则返回undefined

function Foo(){}const foo=new Foo()
Foo.prototype.isTestable=trueconsole.log(foo.isTestable) // true

那么如何区分某个对象的属性时其自身的还是继承的呢?我们就需要hasOwnProperty()这个方法来确认。

其中isTestable这个属性对于foo来说就是原型上的属性,所以它返回false

foo.hasOwnProperty('isTestable') // false

如果我们在foo上直接添加isTestable这个属性,那么他与__proto__上的isTestable是否冲突?

function Foo(){}const foo=new Foo()
foo.isTestable=falseFoo.prototype.isTestable=trueconsole.log(foo.hasOwnProperty('isTestable')) // trueconsole.log(foo.isTestable) // falseconsole.log(foo.__proto__.isTestable) // true// 删除实例上的isTestable属性delete foo.isTestableconsole.log(foo.hasOwnProperty('isTestable')) // falseconsole.log(foo.isTestable) // true 这时又从__proto__上找到isTestable了// 来,我们把__proto__上面的也删掉delete foo.__proto__.isTestableconsole.log(foo.isTestable) // false, isTestable终于没了

当然hasOwnProperty()只能知道某个属性是否在实例上,如果我们想要知道某个属性是否在__proto__上,就需要自己写一个函数:

 const hasPrototypeProperty=(obj,key)=>(key in obj)&&(!obj.hasOwnProperty(key))

3. 每个实例之间的关系是什么?

对于以下由一个构造函数创建的实例

function Foo(){}const foo1=new Foo()const foo2=new Foo()

有下列关系

foo1==foo2 // false,这是因为在这里都指向不同的内存,{}==={} // falseJSON.stringify(foo1)===JSON.stringify(foo2) // truefoo1.constructor===foo2.constructor // true 这里的构造函数都指向Foo,所以为truefoo1.__proto__===foo2.__proto__ // 当然这个也为truefoo1.__proto__===Foo.prototype // trueObject.getPrototypeOf(foo1)===Object.getPrototypeOf(foo2) // true

4. 在构造函数中添加属性后实例怎么继承

对于在构造函数内部添加的属性,它的实例会继承它的属性;

function Foo(){this.name='foo'}
Foo.age=10const foo1=new Foo()

然而直接挂载在Foo上的属性不会在实例上被继承;

foo1.name // 'foo'foo1.age // undefined

如果实例上和原型上都挂载了同样的属性,会优先从实例上获取:

function Foo(){this.name='foo'}const foo1=new Foo()
foo1.name='ahaha'foo1.name //'ahaha'

参考文档

  1. 详解prototype与 __proto__  区别

  2. 一张图理解prototype、__proto__ 和constructor的三角关系



作者:mytac
链接:https://www.jianshu.com/p/bb02c403f86c


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消