本文深入解析JavaScript原型链核心概念,详细区分constructor、prototype与__proto__三个关键属性的作用。通过构造函数重写前后的代码示例,阐明原型对象创建、实例继承以及constructor指向变化的原理,帮助开发者彻底理解JS面向对象编程中的继承机制。
导读
__proto__(实际原型)与prototype(原型属性)是两个完全不同的概念,务必加以区分。
constructor属性存在于原型对象中,同时也会被实例对象所继承。
prototype属性指的是由构造函数指向的原型对象。
__proto__属性则是实例对象指向其原型对象的指针。
首先明确几个基础概念:
什么是对象?
对象是若干属性的集合。
什么是原型?
原型是一个对象,其他对象可以通过它来实现继承。
哪些对象拥有原型?
默认情况下,所有对象都拥有一个原型。由于原型本身也是对象,因此每个原型自身也包含一个原型(唯一的例外是位于原型链顶端的那个默认对象原型)。
任何对象都可以充当原型。
接下来进入核心内容:
constructor属性
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属性
请注意:prototype是每个函数对象都具有的属性,被称为原型对象;而__proto__属性才是每个普通对象才拥有的属性。一旦为原型对象赋予属性和方法,由相应构造函数创建的实例便会继承prototype上的属性和方法。
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属性的关系
每个函数都拥有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
//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{}以上就是Js原型链constructor prototype __proto__属性实例详解的详细内容,更多关于Js 原型链属性的资料请关注本站其它相关文章!