当我们看原型的各种文章的时候, 你总是会看到 __proto__, prototype, construcotr, function, Object 这些关键字。 可能你看完了文章, 你以为你懂了, 其实。。你没有。。。。 我这篇文章就不去解析那些图了, 因为放上来看完也是一脸懵逼, 没有很直观。 我们就把这几个关键字理清楚,他们之间的各种关弄明白,那么原型和原型链这个东西 也就差不多明白了。
__proto__
__proto__, 这个东西在js中,每个对象都会有(null除外)。 不相信的现在打开console 试试看, 随便写一个 const test = 1, test.__proto__ 是有东西打印出来的。 那么大家会好奇,这个东西干嘛的,打印出来的是啥玩意。 这里先不过多的去解释, 先笼统的总结一下, 在我的理解中这个东西就是大家经常说的原型链的'链'。然后他‘链’的是个啥? 以上面的test 为例,test.__proto__ 指向的是创建test的类的 ‘prototpye’, 也就是我们所说的原型。 好了,下面我们就可以开始介绍prototype 这个玩意了。
prototype
prototype, 之前我看文章的时候以为只要是对象应该都有prototype这个东西。。。, 那其实是错误的. 那么js中哪些东西才有prototpye这个玩意呢? 总结一下: js中能拿来new的东西都有prototype, 带有prototype的对象是可以用来产生实例的。 我们现在来分析一下, 我们定义先定义个function
function foo(name){
this.name = name
}
这个写法其实也等于下面的写法
let foo = new Function('name', 'this.name = name')
那么按照上面说法 'test.__proto__ 指向的是创建test的类的'prototpye', 那么这里我们是不是可以判断 foo.__proto__ === Function.prototype 呢? 是的,大家可以试试。那么foo有没有prototype呢,大家可以在这里暂停一下好好想一想。。。。。, 答案是有的。 为什么,foo 是可以拿来new 的,用它去生产一个实例
let bar = new foo('new instance')
套用上面的理论: 能被拿来创建实例的对象是带有prototype的。然后我们可以判断出 bar.__proto__ === foo.prototype。 这里在抛出一个问题, bar 有没有prototype? 我想很多人已经知道了,没有. 因为我们无法通过bar 去new一个实例出来。 所以bar.prototype是unfedined。
bar.__proto__ === foo.prototype
foo.__proto__ === Function.prototype
我们在来看看prototype里面都有什么,大家自己console打印一下会发现,里面有一个constructor属性,和__proto__, 前面说过了对象都会有__proto__ 属性的,prototype也不例外。 下面我们在说说constructor 这个东西
constructor
constructor, 我们称它构造函数。 这个东西是生成的prototype时候自动生成属性,它指向函数本身。 也就是说 foo.prototype.constructor === foo. 这里需要引入一个概念,'引用类型'(reference type)。 foo就是一个引用类型, 它指向的是内存中的一段地址, 而这个地址的位置存在的才是foo的具体的值。 那么foo.prototype.constructor 指向的也是这个地址,所以才会说prototype.constructor 指向的是函数本身,也就是foo. 然后foo它本身也是有constructor的。foo下的constructor指向的是创建foo的构造函数, 也就是Function, 所以 foo.constructor==== Function。 同理 bar.constructor === foo。 foo.constructor 是干嘛的, foo就是通过foo.constructor 创建出来的, 具体new的实现过程可以去自学下,这里就不阐述了。
Object
在这里我们要讲Object。我们打印出Object 会发现他有__proto__, 和prototype, 然后在展开Object.prototype 你会发现, 他下面是没有__proto__ , 这意味着什么,意味着原型链到这里就没有了, Object.prototype 就是原型链的源头, 万恶之源。
懵逼了吗大家。懵逼了就先暂停下, 从头在看一遍, 理解消化了之后我们在往下走。
实践 && 总结
现在我们用上面总结的东西来实践一下,看看原型链是怎么个链法。
function Person(){
this.name = 'Tom'
}
const newPerson = new Person()
我们知道 newPerson.__proto__ === Person.prototype, 然后我们打印一下 Perosn, 发现Person.prototype 的 __proto__ 指向的是Object。 也就是说 Person.prototype.__proto__ === Object.prototype。 我们之前提到Object.prototype 是原型链的尽头了, 也就是说我们这里得到了一条完整的原型链
newPerson.__proto__ === Person.prototype
Person.prototype.__proto__ === Object.prototype
从而得到 newPerson.__proto__.__proto__ === Object.prototype 正常情况下我们想给newPerson添加一个属性,我们会这样操作 newPerson.age = 11. 但是其实我们也可以这样,把age添加到Object.prototype 上。 Object.prototype.birthday = '2010-09-27', 然后可以尝试打印 newPerson.birthday, 显示的就是'2010-09-27'。 为什么newPerson能访问到这个属性呢, 这就是因为原型链的关系。当我们尝试去访问birthday 的时候, 会在newPerson下找存不存在, 不存在就去newPerson 下的__proto__ 中去找(这个时候newPerson.__proto__ 指向是的Person.prototype)。 如果还没找到, 就在沿着newPerson.__proto__.__proto__去找(这个时候newPerson.__proto__.__proto__ 指向是的Object.prototype)。 然后我们在里面找到了birthday 这个属性,如何还没有就返回undefiend了, 因为已经路已经到头了。 再举一个例子。
const c = 1
c.toString()
这个toString其实不是再c下面的,而是Object.prototype 下面。
到这里原型链的作用我们可以总结一下了, 原型链可以让对象实现一个属性的共享和继承。 由构造函数生成的实例都可以访问构造函数原型中的方法和属性。 其实这里面还有东西没有讲, 那就是Function, 他比较特殊。放在这里一起讲怕到大家弄混淆了,如果大家感兴趣打算单独开一篇文章讲。 看到这里其实原型链的概念就差不多了,从原型链里面也可以延伸出很多其他的知识点, 比如new, this 等等。 以后会慢慢开始写,尽量通俗易懂的把这些讲清楚。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!