本系列文章是针对前端面试之道网站所做的个人注解
原文引用
原文对原型的描述并不清晰,下面将尽量清晰直观的让大家彻底理解原型。
原型
预知识
预知识背下来即可,可以当作数学里的公理。
- 函数也是一种对象,只不过是一种特殊的对象。毕竟JS引用类型都叫Object。
- Object.prototype 是由引擎创建的,除了这个对象,其他对象都是通过构造器 new 出来的。
let a = { b: 1 }
这个字面量内部也是使用了new Object()
。 - Function.prototype是由引擎创建的,除了这个函数,其他函数都是new Function()出来的,
function Foo() {}
function 就是个语法糖,内部等同于 `new Function()。 - 实例:
let o1=new Object();
o1是Object()的实例对象。 - 构造函数:
let o1=new Object();
Object()是o1的构造函数。 - Function.proto === Function.prototype
原型定义
原型是个对象,全称是原型对象。
xxx的原型对象里包含xxx的公有属性和方法。你可以理解为原型对象是一个容器,里面装着xxx对象需要用到的各种方法。比如打印Array.prototype会出现~
原型让你无需重复声明公有属性。省代码,省内存。
prototype属性
prototype 属性是一个显式原型属性,只有函数才拥有该属性。除了let fun = Function.prototype.bind()这样创建出来的函数,基本上所有函数都有这个属性。
xxx.prototype包含一个指针,这个指针指向的内存里存储了xxx的原型对象。
prototype 如何产生的
有些函数已经内置了prototype属性,比如上文提到的Array。
除了已经内置prototype属性的函数,当我们新声明一个函数时,prototype这个属性也会被自动创建。
function Foo() {} // 此时,Foo.prototype就被自动创建了,并且Foo.prototype指向的原型对象里也拥有一个自动创建的属性:constructor。
复制代码
constructor属性
constructor也包含指针,指向prototype对应的函数。在上面的例子中,指向的就是 Foo。
constructor 是一个公有且不可枚举的属性。一旦我们改变了函数的 prototype ,那么新对象就没有这个属性了(当然可以通过原型链取到 constructor)。
那么你肯定也有一个疑问,这个属性到底有什么用呢?其实这个属性可以说是一个历史遗留问题,在大部分情况下是没用的,在我的理解里,我认为他有两个作用:
1.让实例对象知道是什么函数构造了它
2.如果想给某些类库中的构造函数增加一些自定义的方法,就可以通过 xx.constructor.method 来扩展
_proto_属性
这是每个对象都有的隐式原型属性,指向了创建该对象的构造函数的原型。
_ proto _ 如何产生的
当我们使用 new 操作符时, 新对象被添加了 proto 并且链接到构造函数的原型上。
prototype和_proto_的区别
prototype和_proto_都存着原型的地址,只不过_proto_所有对象都有,prorotype只挂载在函数上。
原型链
实例可以通过_proto_来寻找上层属性。_proto_将各个对象连接起来组成了原型链。
总结
读完上面的内容之后,把总结背下来就可以轻松面对所有原型相关问题啦~
- 每个函数都有 prototype 属性,除了 Function.prototype.bind()创建的函数,该属性指向该函数的原型对象。
- 原型对象存储了函数的公有属性和方法。让你无需重复声明公有属性。省代码,省内存。
- 每个原型对象都有constructor属性,指向对应的函数。
- 每个对象(实例)都_proto_有属性,指向了创建该对象(实例)的构造函数的原型。
- _proto_将各个对象连接起来组成了原型链。