看下面代码配合图片可以理解的更加清晰
// 定义构造函数
function Person() {
...
}
// 创建一个实例对象
const p1 = new Person()
// 实例对象的原型链
p1.__proto__ === Person.prototype
p1.__proto__.__proto__ === Object.prototype
Person.prototype.__proto__ === Object.prototype
// 构造函数的原型链
Person.__proto__ === Function.prototype
Person.__proto__.__proto__ === Object.prototype
Function.prototype.__proto__ === Object.prototype
Object.prototype.__proto__ === null
再写个例子可以理解的更透彻
function Person() {}
const p1 = new Person()
Object.prototype.a = 'a'
Function.prototype.b = 'b'
console.log(p1.a) // a
console.log(p1.b) // undefined
console.log(Person.a) // a
console.log(Person.b) // b
下面案例1中,在Person的原型对象中定义了a属性的值为1,然后在下面又重新改变了a的值。此时p1和p2实例中原型链始终指向的都是同一个Person的原型对象,所以后面p1.a输出的值是改变后的值。这个应该很好理解。
// 案例1
function Person() {}
Person.prototype.a = 1
var p1 = new Person()
console.log(p1.a) // 1
Person.prototype.a = 2
var p2 = new Person()
console.log(p2.a) // 2
console.log(p1.a) // 2
p1.__proto__ === p2.__proto__ // true
在案例2中,重新给Person的原型对象定义了一个新值,这时候已经改变了这个原型对象指向的地址,所以p1和p2实例中原型链上指向的原型对象不是同一个。
// 案例2
function Person() {}
Person.prototype.a = 1
var p1 = new Person()
console.log(p1.a) // 1
// 此处Person的原型对象已经不是原来的那个原型对象了
Person.prototype = { a: 2 }
var p2 = new Person()
console.log(p2.a) // 2
console.log(p1.a) // 1
p1.__proto__ === p2.__proto__ // false