本文为了解决如下问题:javascript
__proto__
(实际原型)和prototype
(原型属性)不同!!!java
constructor
属性(原型对象中包含这个属性,实例当中也一样会继承这个属性)函数
prototype
属性(constructor.prototype
原型对象)this
__proto__
属性(实例指向原型对象的指针)spa
首先弄清楚几个概念:.net
若干属性的集合prototype
原型是一个对象,其余对象能够经过它实现继承。指针
全部的对象在默认状况下都有一个原型,由于原型自己也是对象,因此每一个原型自身又有一个原型(只有一种例外,默认的对象原型在原型链的顶端)code
接下来就是最核心的内容:htm
constructor
属性始终指向建立当前对象的构造函数。
var arr=[1,2,3]; console.log(arr.constructor); //输出 function Array(){} var a={}; console.log(arr.constructor);//输出 function Object(){} var bool=false; console.log(bool.constructor);//输出 function Boolean(){} var name="hello"; console.log(name.constructor);//输出 function String(){} var sayName=function(){} console.log(sayName.constrctor)// 输出 function Function(){} //接下来经过构造函数建立instance function A(){} var a=new A(); console.log(a.constructor); //输出 function A(){}
以上部分即解释了任何一个对象都有constructor属性,指向建立这个对象的构造函数
注意:prototype是每一个函数对象
都具备的属性,被称为原型对象,而__proto__
属性才是每一个对象才有的属性。一旦原型对象被赋予属性和方法,那么由相应的构造函数建立的实例会继承prototype
上的属性和方法
//constructor : A //instance : a function A(){} var a=new A(); A.prototype.name="xl"; A.prototype.sayName=function(){ console.log(this.name); } console.log(a.name);// "xl" a.sayName();// "xl" //那么由constructor建立的instance会继承prototype上的属性和方法
每一个函数都有prototype
属性,而这个prototype
的constructor
属性会指向这个函数。
function Person(name){ this.name=name; } Person.prototype.sayName=function(){ console.log(this.name); } var person=new Person("xl"); console.log(person.constructor); //输出 function Person(){} console.log(Person.prototype.constructor);//输出 function Person(){} console.log(Person.constructor); //输出 function Function(){}
若是咱们重写(从新定义)这个Person.prototype
属性,那么constructor
属性的指向就会发生改变了。
Person.prototype={ sayName:function(){ console.log(this.name); } } console.log(person.constructor==Person); //输出 false (这里为何会输出false后面会讲) console.log(Person.constructor==Person); //输出 false console.log(Person.prototype.constructor);// 输出 function Object(){} //这里为何会输出function Object(){} //还记得以前说过constructor属性始终指向建立这个对象的构造函数吗? Person.prototype={ sayName:function(){ console.log(this.name); } } //这里其实是对原型对象的重写: Person.prototype=new Object(){ sayName:function(){ console.log(this.name); } } //看到了吧。如今Person.prototype.constructor属性其实是指向Object的。 //那么我如何能将constructor属性再次指向Person呢? Person.prototype.constructor=Person;
接下来解释为何,看下面的例子
function Person(name){ this.name = name; } var personOne=new Person("xl"); Person.prototype = { sayName: function(){ console.log(this.name); } }; var personTwo = new Person('XL'); console.log(personOne.constructor == Person); //输出true console.log(personTwo.constructor == Person); //输出false //你们可能会对这个地方产生疑惑?为什么会第二个会输出false,personTwo不也是由Person建立的吗?这个地方应该要输出true啊? //这里就涉及到了JS里面的原型继承 //这个地方是由于person实例继承了Person.prototype原型对象的全部的方法和属性,包括constructor属性。当Person.prototype的constructor发生变化的时候,相应的person实例上的constructor属性也会发生变化。因此第二个会输出false; //固然第一个是输出true,由于改变构造函数的prototype属性是在personOne被建立出来以后。
接下解释__proto__
和prototype
属性
一样拿上面的代码来解释:
function Person(name){ this.name=name; } Person.prototype.sayName=function(){ console.log(this.name); } var person=new Person("xl"); person.sayName(); //输出 "xl" //constructor : Person //instance : person //prototype : Person.prototype
首先给构造函数的原型对象Person.prototype
赋给sayName
方法,由构造函数Person
建立的实例person
会继承原型对象上的sayName
方法。
由于ECMAscript的发明者为了简化这门语言,同时又保持继承性,采用了链式继承的方法。
由constructor
建立的每一个instance
都有个__proto__
属性,它指向constructor.prototype
。那么constrcutor.prototype
上定义的属性和方法都会被instance
所继承.
function Person(name){ this.name=name; } Person.prototype.sayName=function(){ console.log(this.name); } var personOne=new Person("a"); var personTwo=new Person("b"); personOne.sayName(); // 输出 "a" personTwo.sayName(); //输出 "b" console.log(personOne.__proto__==Person.prototype); // true console.log(personTwo.__proto__==Person.prototype); // true console.log(personOne.constructor==Person); //true console.log(personTwo.constructor==Person); //true console.log(Person.prototype.constructor==Person); //true console.log(Person.constructor); //function Function(){} console.log(Person.__proto__.__proto__); // Object{}
参考文章: