const F = function () { this.name = 'Jack' } // ƒ () { this.name = 'Jack' }
const e = new F() // F { name: "Jack" }
console.log(e.name) // Jack
构造函数:现在 F 就是构造函数。任何一个函数被 new 使用后,就是构造函数,没被 new 使用过就是普通函数。(简单说 new 后面的函数都是构造函数)
实例对象:现在 e 就叫做实例,在 js 中,只要是被 new 出来的对象都叫做实例对象,也叫实例。(所以说实例都是对象,但是对象就不一定是实例了)
原型对象:现在 F.prototype 就是原型对象,任何一个函数都有 prototype 属性,这个属性是声明函数时 js 自动加的,prototype 初始时是一个空对象,这个对象就叫原型对象。
他们之间的关系就如同下图:
从图中可得知4种关系:
1、构造函数(例子中的 F)new 出来的东西就叫实例;
2、构造函数(例子中的 F)的 prototype 属性就叫原型对象;
3、原型对象(F.prototype)中的 constructor 其实就等于构造函数,可以打印一下 F.prototype.constructor === F // true;
4、实例(例子中的 e)的 __proto__ 属性其实就是构造函数(F)的 prototype 可以打印 e.__proto__ === F.prototype // true。
这个时候我们就知道原型对象就是用来区分它是哪个构造函数引用的,而且如果多个实例中的方法相同,我们就可以把方法写在 prototype 原型对象中,prototype 属性是可以被多个实例共有,想要你就new一下。
__proro__ 是任何对象都有的属性,而在 js 中,万物皆对象。所以会形成一条 __proro__ 连起来的链条,递归访问 __proto__ 最终到头,并且值是 null,这个过程从头到结束就叫原型链。或者说要查一个实例对象中的值时,首先通过本身的 __proto__ 属性找到他的原型对象,然后再通过他的原型对象的 __proto__ 找到他的原型对象,一直找,递归访问 __proto__ 最终到头,并且值是null,这个过程从头到结束就叫原型链。找到了就返回值,找不到就返回 undefind。
还有一个比较重要的,不止构造函数有 __proto__ 属性,普通函数也有,因为普通函数是Function的实例。