相信很多对javascript原型初步了解的人都知道prototype,constructor,__proto__这些名词,也在一定程度上可以使用这些对象、属性。甚至知道在构造函数的原型上定义方法供实例对象使用。但是很多人对原型的整个构成以及prototype和constructor等的关系没有明确的知识架构,现在就随我看一下他们之间的关系到底是什么样的吧~(本文默认读者已经对原型有一定了解,如果还没有开始了解原型建议阅读《javascript高级程序设计》一书关于原型的章节)
好的,现在我们就以一段代码为基础对原型进行分析
1 function Foo() {}; 2 var foo = new Foo(); 3 console.log(Foo.prototype); 4 console.log(foo.__proto__); 5 console.log("Foo.prototype.constructor----" + Foo.prototype.constructor); 6 console.log("foo.__proto__.constructor----" + foo.__proto__.constructor); 7 console.log("foo.constructor----" + foo.constructor);
首先贴出这段代码的答案在进行分析
可以看出 Foo.prototype 和 foo.__proto__ 为相同的值,并且值为一个对象,其实 __proto__ 是为了方便查找一个实例化对象的构造函数的原型而专门设置出的属性,所以他的值必然与他构造函数的prototype相同。那prototype是怎么产生的呢?来看图
当Foo函数作为构造函数实例化foo对象时,会创建出一个新对象并将它关联在Foo.prototype上(答案1),并且为foo创建与Foo.prototype的连接(foo.__proto__(答案2))。foo独立保存Foo内部的属性及方法并单独执行操作,如果在foo内部查找不到需要的属性(方法只是属性类型为函数是的一个别名)则向上查找,如果存在于Foo.prototype中,怎只用或修改构造函数原型上的属性。
Foo.prototype是一个对象,有上面代码的答案就可看出,这个对象存在一个不可枚举的属性 constructor ,指向创建出它的构造函数,所以Foo.prototype.constructor 是Foo这个函数(答案3)。因为foo.__proto__与Foo.prototype相等,所以foo.__proto__.constructor是Foo这个函数(答案4)。又因为foo可以通过原型链查找并使用Foo.prototype的属性,所以~~foo可以使用constructor属性,而constructor属性的指向前面已经说过,所以foo.constouctor也是Foo这个函数(答案5)。