很长一段时间对JS的原型与原型链理解的很模糊,而想学好JS,原型与原型链倒是绕不开的话题,因此只好进行对其进行一个梳理。javascript
理解原型和原型链,需理解三个重要的属性: prototype、__proto__、constructorjava
prototype函数
JavaScript函数中,每个函数都有一个prototype属性,叫原型对象。spa
代码示例:prototype
function Person(){
}
Person.prototype.name = 'zhangsan'
let person = new Person()
console.log(person.name) // zhangsan
上面的代码中,建立了一个构造函数Person,并在它的原型上添加一个属性name为zhangsan, 而后再建立了实例对象person,那么这个实例对象上也有name属性,打印输出“zhangsan”3d
能够看出:code
Person这个函数的prototype属性指向了一个对象,即:Person.prototype 也是一个对象,这个对象正是调用该构造函数而建立的实例的原型,即person的原型。对象
方便理解,咱们进行拆解:blog
1.建立了构造函数Person 2.使用new关键字进行调用 3.调用获得了实例person 4.实例和原型的关系:person的原型就是Person.prototype
那什么是原型呢?能够这样理解:每个JavaScript对象(null除外)在建立的时候就会与之关联另一个对象,这个对象就是咱们所说的原型,而每个对象都会从原型"继承"属性。继承
咱们用一张图表示构造函数和原型之间的关系:
构造函数和实例原型之间的关系咱们已经梳理清楚了,那怎么表示实例与原型,也就是person和Person.prototype之间的关系呢?
__proto__
其实每个JavaScript对象(除了null)都有一个属性,叫__proto__,这个属性会指向该对象的原型。
代码示例:
function Person(){ } let person = new Person() console.log(person.__proto__ === Person.prototype) // true
构造函数Person的实例对象person,有个属性叫__proto__,这个属性指向原型,即Person.prototype。
补全上面的关系图:
Q:原型是否有属性指向构造函数或者实例对象呢?
constructor
代码示例:
function Person() { } let person = new Person() console.log(Person === Person.prototype.constructor); // true
继续完善关系图:
原型的constructor指向构造函数,但没有属性指向实例,由于可能有多个实例。
其实 person 中并无constructor 属性,当不能读取到constructor属性时,会从 person 的原型也就是 Person.prototype中读取
console.log(person.constructor === Person) // true
console.log(person.constructor === Person.prototype.constructor) // true
实例与原型
当读取实例的属性时,若是找不到,就会查找与对象关联的原型中的属性,若是还查不到,就去找原型的原型,一直找到最顶层为止。
代码示例:
function Person() { } Person.prototype.name = 'zhangsan'; let person = new Person(); person.name = 'lisi'; console.log(person.name) // lisi delete person.name; console.log(person.name) // zhangsan
new建立了一个实例对象person,有个属性name值为“lisi”,当咱们把删除了这个name属性后,依然可以打印出“zhangsan”,实际状况是从 person 实例对象中找不到 name 属性,就会从 person 的原型也就是 person.__proto__
,也就是 Person.prototype
中查找,幸运的是咱们找到了 name 属性,结果为 zhangsan
原型的原型
代码示例:
Object.prototype.name = 'wangwu' function Person(){ } let person = new Person() console.log(person.name) // wangwu
Person 的实例对象person,自己没有name属性值,全部会去原型上找,Person.prototype上也没有,就去原型的原型上找,即:Object.prototype,有一个name为“wangwu”的属性,全部输出“wangwu”
其实原型对象就是经过Object构造函数生成的,结合以前咱们所说的,实例的__proto__指向构造函数的 prototype 因此咱们再丰富一下咱们的关系图:
原型链
那Object.prototype 的原型呢?Object是根节点的对象,再往上查找就是null,咱们能够打印:
console.log(Object.prototype.__proto__ === null) // true
咱们将null也加入关系图,就比较完整了:
上面的person实例对象到null的这条线即为原型链。
咱们还能够把大Function加上
console.log(Person.constructor === Function) // true
console.log(obj.__proto__ === Object.prototype) // true
console.log(obj.__proto__.constructor === Object) /// true
console.log(obj.__proto__.constructor.__proto__ === Function.prototype) // true
console.log(obj.__proto__.constructor.__proto__.constructor === Function) // true
console.log(Person.__proto__ === Function.prototype) // true console.log(Object.__proto__ === Function.prototype) // true
从网上找了张图,如今再去理解原型与原型链,就好理解了吧