初探JavaScript之Prototype

原创 一者乎 随笔 JavaScript 96阅读 2019-02-25 15:28:01 举报

Array.prototype

每一个函数,都有一个 prototype 属性,不管是你自定义的,还是函数内置的。

image

这里的 fn.prototype 打印出一个对象,对象里的 constructor 属性又指回了该函数本身 fn。

每个原型都有一个 consctructor 属性指向关联的构造函数,比如:

image

我们接着看:

这里,除了 constructor 属性,还有其他内置的属性,即我们经常使用的操作数组的方法。

__proto__(隐式原型)

所有通过函数 new (构造函数)出来的东西,都有一个 __proto__ 指向该函数的 prototype,比如:

image

说白了,通过构造函数 new 出来的函数,该函数的__proto__属性指向构造函数的原型对象(即Array.prototype),所以,该函数与构造函数之间没有什么关联,是通过 原型对象 产生了联系,这也就是原型链继承的雏形吧。

举个关于继承 extends 的例子:

上面看明白了,那么ES6的继承我们也就可以明白原理了,即 class Dog extends Animal 相当于 Dog.prototype = new Animal()

接下来,我们就清楚为什么能这样:

当我们要使用一个对象(数组)的某个功能时,如果该对象本身具有这个功能,直接调用,没有的话,那就去自身的__proto__属性中去找

hasOwnProperty()就可以得出这个属性是否是属于该对象本身的属性:

  • myfn 是我们自定义的,obj.hasOwnProperty('myfn')为 true
  • toString() 我们不是自定义的,却可以使用,查一下是否属于自定义属性,obj.hasOwnProperty('toString'),答案为false
  • 既然不属于自定义属性,那就去自身的__proto__去找,然后去原型对象上查一下,obj.__proto__.hasOwnProperty('toString'),哦,原来在这儿

在源码中,我们经常看到Array.prototype.concat,其实就是我们使用的[].concat[],因为[].__proto__ === Array.prototype

__proto__是可修改的

比如,我们新增一个addClass()方法:

image

但是,这里要注意,如下重写之后,就没有了诸如 push、concat等方法:

Object.prototype的原型

万物皆对象,到最后依旧是对象,最后这个东东是个啥,我们来看一下:

总结:

  • 所有的函数都有一个 prototype属性,该属性指向了一个对象,该对象就是调用该构造函数而创建出来的实例(如myfn)的原型(如myfn.__proto__),即:myfn.__proto__ === Person.prototype
  • 所有的对象(除null)都具有一个__proto__属性,该属性指向该对象的原型,比如:myfn.__proto__ === Person.prototype
  • 原型也是一个对象,根据上条,那原型的原型,就是Object.prototype
  • 最后的null对象,可以当做是 什么都没有

盗一张图,我们就更加清楚了(蓝色这条表示的是原型链)
image

PS: 关于原型对象这一块本来就很绕,自己看懂了不一定就真的懂了,自己梳理的时候还是漏洞百出,而且还乱,就算现在我梳理了一遍,过些日子,我要是不再继续翻阅,应该又讲不通了,下面的资料很详细,在我学习的过程中提供了很大的帮助,在此感谢作者们!

参考资料:

写于 初探JavaScript之Prototype

评论 ( 0 )
最新评论
暂无评论

赶紧努力消灭 0 回复