原型与原型链

五零二二

创建:2022-02-21 19:04      更新:2022-02-21 19:21

在JavaScript中是使用构造函数来新建一个对象的,每一个构造函数的内部都有一个 prototype属性,它的属性值是一个对象,这个对象包含了可以由该构造函数的所有实例共享的属性和方法。当使用构造函数新建一个对象后,在这个对象的内部将包含一个指针,这个指针指向构造函数的prototype属性对应的值,在ES5 中这个指针被称为对象的原型。一般来说不应该能够获取到这个值的,但是现在浏览器中都实现了__proto__属性来访问这个属性,但是最好不要使用这个属性,因为它不是规范中规定的。ES5 中新增了一个Object.getPrototypeOf()方法,可以通过这个方法来获取对象的原型。

当访问一个对象的属性时,如果这个对象内部不存在这个属性,那么它就会去它的原型对象里找这个属性,这个原型对象又会有自己的原型,于是就这样一直找下去,也就是原型链的概念。原型链的尽头一般来说都是Object.prototype所以这就是新建的对象为什么能够使用toString()等方法的原因。

函数的prototype属性包含了可以由该构造函数的所有实例共享的属性和方法,原型的constructor属性则是其对应的构造函数;将函数创建为实例后,实例没有prototype属性,其__proto__属性指向了其原型,constructor指向了其对应的构造函数;原型链的重点是Object.prototype.__proto__,其值为null,原型链上的所有原型都是对象,所有对象最终都是由Object构造的;

函数的原型,即其__proto__属性,指向的是Function.prototype

//构造函数Person
function Person(name) {
    this.name = name
}
//创建实例p
var p = new Person('hello')

//重写原型
Person.prototype = {getName: function(){console.log(this.name)}}
//重写后,实例的构造函数指向了Object,将实例p的constructor重新指向Person
p.constructor = Person
p.getName()//输出hello
console.log(p.__proto__ === Person.prototype)// true
console.log(p.__proto__ === p.constructor.prototype)// true

p.__proto__  //实例的原型Person.prototype
Person.prototype.__proto__  //构造函数Person的原型的原型 Object.prototype
p.__proto__.__proto__ //同上 Object.prototype
p.__proto__.constructor.prototype.__proto__ //实例的原型的构造函数的原型的原型 Object.prototype
Person.prototype.constructor.prototype.__proto__ //Person的原型的构造函数的原型的原型 Object.prototype
p.__proto__.constructor //实例的原型的构造函数 Person
Person.prototype.constructor  //Person的原型的构造函数 Person