原型、原型链
翻看了一下午的原型、原型链方面的内容,以下是学习后整理的记录。
三个属性
1.prototype
prototype只有构造函数才有,它指向的是当前构造函数的原型对象。
2.__proto__
__proto__属性是任何对象都有的,任何一个对象都是有这个属性的,它指向的是当前对象的<构造函数的原型对象,由__proto__构成的链就是原型链。
3.constructor
constructor只有原型对象才有,它指向的是prototype属性所在的构造函数
对象等级划分
我们认为在JavaScript这门语言中一切皆是对象,包括任何变量和值,而Object就是这些对象当中处于最顶层的一员。接下来就是Function,然后是String、Date、Number、Boolen等内建对象处于第三层。剩下的处于最底层。
在此,我们还要知道,在JavaScript中不管什么类型的对象,都一定有构造函数,包括构造函数本身。
一步一步分解原型和原型链
function test(name){
this.name = name;
console.log("name is"+name)
}
var test1 = new test(123)
根据之前我们对三个属性的定义,实例test1的__proto__应该指向test1的构造函数的原型对象,也就是test的原型对象。而test的prototype指向的是当前构造函数的原型对象,也就是test的原型对象。综上,我们知道test的prototype和test1的__proto__指向的应该是相同的。
同时test的原型函数应该是有一个constructor属性的,它指回是test这个构造函数。
根据我们刚刚得到这些内容,我们就可以画出下面的示意图。
这里我们可以看到test的原型对象和test的__proto__的指向是未知的。我们接下来就对这两个对象的__proto__属性进行探讨。
console.log(test1.__proto__.__proto__) //test原型对象的构造函数的原型对象
console.log(test1.__proto__.__proto__.constructor) //test原型对象的构造函数的原型对象的构造函数
console.log(test.__proto__) //test构造函数的指向
根据__proto__属性的定义,我们可以知道test原型对象的__proto__指向应该是test原型对象的构造函数的原型对象 Object。根据constructor属性的定义我们知道test原型对象的构造函数的原型函数的构造函数是function Object()。
test构造函数的__proto__的指向是function()。
那么我们就可以接着向下画。
既然已经拿到了Function的原型对象,那我们也可以拿到Function的构造函数,也就是test.__proto__.constructor。我们将这里的prototype和__proto__展开,可以看到prototype和__proto__指向的是同一个东西,都是Function的原型对象。我们在这里进行一步验证。
console.log(test.__proto__.constructor.prototype === test.__proto__.constructor.__proto__) //true
也就是说,Function的原型对像的构造函数的原型对象就是Function的构造函数
那么我们再把上图继续画下去。
OK,进行到这一步我们已经快要逼近最后的答案了,接下来让我们验证Function原型对象的__proto__属性指向和Object的构造函数的Prototype属性和__proto__属性的指向。
我们可以清楚的看到Object的构造函数的prototype属性指向和Function原型对象的__proto__指向是相同的,都是Object的原型对象。
而Object的__proto__属性指向的是Function原型对象。
那么我们就可以把这张图画完整了。
总结
我们从最开始的test1实例对象来看,它的原型链应该是
test1实例—>test原型对象—>Object原型对象
也就是 对象实例—>对象实例的构造函数的原型对象—>Object原型对象