本文为了解决以下问题:
__proto__(实际原型)和prototype(原型属性)不一样!!!
constructor属性(原型对象中包含这个属性,实例当中也同样会继承这个属性)
prototype属性(constructor.prototype原型对象)
__proto__属性(实例指向原型对象的指针)
<br/>
首先弄清楚几个概念: <br/>
什么是对象? 若干属性的集合 <br/>
什么是原型? 原型是一个对象,其他对象可以通过它实现继承。 <br/>
哪些对象有原型? 所有的对象在默认情况下都有一个原型,因为原型本身也是对象,所以每个原型自身又有一个原型(只有一种例外,默认的对象原型在原型链的顶端) 任何一个对象都可以成为原型 <br/>
接下来就是最核心的内容: <br/>
constructor 属性
constructor属性始终指向创建当前对象的构造函数。
1 var arr=[1,2,3]; 2 console.log(arr.constructor); //输出 function Array(){} 3 var a={}; 4 console.log(arr.constructor);//输出 function Object(){} 5 var bool=false; 6 console.log(bool.constructor);//输出 function Boolean(){} 7 var name="hello"; 8 console.log(name.constructor);//输出 function String(){} 9 var sayName=function(){} 10 console.log(sayName.constrctor)// 输出 function Function(){} 11 12 //接下来通过构造函数创建instance 13 function A(){} 14 var a=new A(); 15 console.log(a.constructor); //输出 function A(){}
以上部分即解释了任何一个对象都有constructor属性,指向创建这个对象的构造函数.
<br/>
prototype属性
注意:prototype是每个函数对象都具有的属性,被称为原型对象,而__proto__属性才是每个对象才有的属性。一旦原型对象被赋予属性和方法,那么由相应的构造函数创建的实例会继承prototype上的属性和方法。
<br/>1 //constructor : A 2 //instance : a 3 function A(){} 4 var a=new A(); 5 6 A.prototype.name="xl"; 7 A.prototype.sayName=function(){ 8 console.log(this.name); 9 } 10 11 console.log(a.name);// "xl" 12 a.sayName();// "xl" 13 14 //那么由constructor创建的instance会继承prototype上的属性和方法
constructor属性和prototype属性
每个函数都有prototype属性,而这个prototype的constructor属性会指向这个函数。
1 function Person(name){ 2 this.name=name; 3 } 4 Person.prototype.sayName=function(){ 5 console.log(this.name); 6 } 7 8 var person=new Person("xl"); 9 10 console.log(person.constructor); //输出 function Person(){} 11 console.log(Person.prototype.constructor);//输出 function Person(){} 12 console.log(Person.constructor); //输出 function Function(){}
如果我们重写(重新定义)这个Person.prototype属性,那么constructor属性的指向就会发生改变了。
1 Person.prototype={ 2 sayName:function(){ 3 console.log(this.name); 4 } 5 } 6 7 console.log(person.constructor==Person); //输出 false (这里为什么会输出false后面会讲) 8 console.log(Person.constructor==Person); //输出 false 9 10 console.log(Person.prototype.constructor);// 输出 function Object(){} 11 //这里为什么会输出function Object(){} 12 //还记得之前说过constructor属性始终指向创建这个对象的构造函数吗? 13 14 Person.prototype={ 15 sayName:function(){ 16 console.log(this.name); 17 } 18 } 19 //这里实际上是对原型对象的重写: 20 Person.prototype=new Object(){ 21 sayName:function(){ 22 console.log(this.name); 23 } 24 } 25 //看到了吧。现在Person.prototype.constructor属性实际上是指向Object的。 26 27 //那么我如何能将constructor属性再次指向Person呢? 28 Person.prototype.constructor=Person;
接下来解释为什么,看下面的例子。
<br/>1 function Person(name){ 2 this.name = name; 3 } 4 var personOne=new Person("xl"); 5 Person.prototype = { 6 sayName: function(){ 7 console.log(this.name); 8 } 9 }; 10 var personTwo = new Person('XL'); 11 console.log(personOne.constructor == Person); //输出true 12 console.log(personTwo.constructor == Person); //输出false 13 //大家可能会对这个地方产生疑惑?为何会第二个会输出false,personTwo不也是由Person创建的吗?这个地方应该要输出true啊? 14 //这里就涉及到了js里面的原型继承 15 //这个地方是因为person实例继承了Person.prototype原型对象的所有的方法和属性,包括constructor属性。当Person.prototype的constructor发生变化的时候,相应的person实例上的constructor属性也会发生变化。所以第二个会输出false; 16 //当然第一个是输出true,因为改变构造函数的prototype属性是在personOne被创建出来之后。
__proto__和prototype属性
1 function Person(name){ 2 this.name=name; 3 } 4 Person.prototype.sayName=function(){ 5 console.log(this.name); 6 } 7 var person=new Person("xl"); 8 person.sayName(); //输出 "xl" 9 10 //constructor : Person 11 //instance : person
首先给构造函数的原型对象Person.prototype赋给sayName方法,由构造函数Person创建的实例person会继承原型对象上的sayName方法。
<br/>
为什么会继承原型对象的方法?
因为ECMAscript的发明者为了简化这门语言,同时又保持继承性,采用了链式继承的方法。
由constructor创建的每个instance都有个__proto__属性,它指向constructor.prototype。那么constrcutor.prototype上定义的属性和方法都会被instance所继承。
1 function Person(name){ 2 this.name=name; 3 } 4 Person.prototype.sayName=function(){ 5 console.log(this.name); 6 } 7 8 var personOne=new Person("a"); 9 var personTwo=new Person("b"); 10 11 personOne.sayName(); // 输出 "a" 12 personTwo.sayName(); //输出 "b" 13 14 console.log(personOne.__proto__==Person.prototype); // true 15 console.log(personTwo.__proto__==Person.prototype); // true 16 17 console.log(personOne.constructor==Person); //true 18 console.log(personTwo.constructor==Person); //true 19 console.log(Person.prototype.constructor==Person); //true 20 21 console.log(Person.constructor); //function Function(){} 22 console.log(Person.__proto__.__proto__);
