每个JavaScript的函数都有一个原型对象, 可以通过prototype属性来指向原型对象
function Person(age) {
this.age = age
}
Person.prototype.name = 'kavin'
var person1 = new Person()
var person2 = new Person()
console.log(person1.name) //kavin
console.log(person2.name) //kavin
上述例子中,函数的prototype指向了一个对象,而这个对象正是调用构造函数时创建的实例的原型,也就是fun1和fun2的原型。
每一个javascript对象(除null外)创建的时候,就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型中“继承”属性。
除了prototype属性之外,还有__proto__(提个醒,这个是双下划线),这个属性会指向该对象的原型,这是每个对象(除null外)都会有的属性
function Person(age) {
this.age = age
}
var person = new Person()
console.log(Person.prototype === person.__proto__)//true
__proto__和原型的关系如下:
在控制台输出一下console.log(person.__proto__)
,得到下图
看到了一个constructor属性,我们在试着console.log(Person.prototype.constructor)
,我们可以得到Person的构造函数,所以constructor 属性可以返回对创建此对象的数组函数的引用,关系图如下
不仅Person.prototype.constructor
可以输出Person函数,用对象实例person.constructor
同样也是显示的Person函数,当获取 person.constructor 时,其实 person 中并没有 constructor 属性,所以当不能读取到constructor 属性时,会从 person 的原型也就是 Person.prototype 中读取,正好原型中有该属性,所以person.constructor
和Person.prototype.constructor
输出的结果是一样的
每个构造函数都有原型对象,每个构造函数实例都包含一个指向原型对象的内部指针(proto),如果我们让第一个构造函数的原型对象等于第二个构造函数的实例,结果第一个构造函数的原型对象将包含一个指向第二个原型对象的指针,再然第三个原型对象等于第一个构造函数的实例,这样第三个原型对象也将包含指向第一个原型对象的指针,以此类推,就够成了实例于原型的链条,这就是原型链的基本概念
来个代码理解一下:
function One(){
}
function Two(){
}
function Three(){
}
Two.prototype=new One();
Three.prototype=new Two();
var three=new Three();
console.log(three);
console.log(three.__proto__===Three.prototype) //true
console.log(three.__proto__.__proto__===Two.prototype) //true
console.log(three.__proto__.__proto__.__proto__===One.prototype) //true
console.log(three.__proto__.__proto__.__proto__.__proto__===Object.prototype) //true
好像看的有点脑阔痛,我就按自己理解解释一下这串代码,有三个构造函数,本来没有任何关系,不是父子也没有调用,但是当Two函数使用prototype创建一个对象的时候,那么One函数就是他的实例原型了,console.log(Two.prototype)
可以看到输出的是One函数,然后Three函数再用prototype属性创建Two函数的对象,但是Two函数是One的对象,所以如果我们console.log(Three.prototype)
会看到输出的也是One函数,所以会有three.__proto__.__proto__===Two.prototype
和three.__proto__.__proto__.__proto__===One.prototype
但是因为js有一个‘万物皆对象的概念’(暂时不探讨这句话究竟是对是错,至少函数确实是一个对象)所以three.__proto__.__proto__.__proto__.__proto__===Object.prototype
,所以在当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还查不到,就去找原型的原型,一直找到最顶层为止
所以可以有个关系图:
所以我们可以看到最顶层的原型就是Object.prototype,那么他的原型是什么呢,再测试一下console.log(Object.prototype.__proto__ );
然后控制台输出的是null,
值 null 是一个字面量,不像 undefined,它不是全局对象的一个属性。null 是表示缺少的标识,指示变量未指向任何对象。把null 作为尚未创建的对象
就可以理解成Object.prototype 没有原型,所以查找属性的时候查到 Object.prototype 就可以停止查找了
所以最后的关系图如下:
图中由相互关联的原型组成的链状结构就是原型链,也就是蓝色的这条线
写这篇文章借鉴了两位大佬的博客:
https://www.cnblogs.com/loveyaxin/p/11151586.html
https://blog.csdn.net/qq_42019025/article/details/80708446