讲原型和原型链前,先介绍下构造函数这个前置知识。
1、 构造函数
前面讲过创建对象的几种方法,其中一种方式是通过 new
一个函数来创建对象。这个函数其实就是构造函数。注意,只有当该函数与new
关键字一起使用,才能被叫做构造函数,否则也只能称之为普通函数。对于构造函数,通常我们会将函数名首字母大写。
function Person(){
}
let person = new Person() // 调用构造函数,返回实例对象
console.log(person) // //Person {}
在javascript中,每个构造函数都有一个属性叫prototype(原型),那么 prototype 到底是什么呢?
function Person(){
}
console.log(Person.prototype)
2、原型是什么
每个实例对象有一个原型对象,对象以其原型为模板、从原型继承方法和属性。原型对象也可能拥有原型,并从中继承方法和属性,一层一层构成一个原型链 (prototype chain),它解释了为何一个对象会拥有定义在其他对象中的属性和方法。
看例子
function Person(){
}
Person.prototype.name = 'zhang' //
let p1 = new Person()
let p2 = new Person()
console.log(p1.name) //zhang
console.log(p2.name) //zhang
console.log(p2.age) //undefined
Person.prototype 就是实例p1和p2的原型,实例对象会继承原型的属性和方法。所以你会看到即使两个实例p1和p2没有自有属性name,但还是有值。
3、原型链
当访问实例p1属性name时,首选看该实例有没有自己的属性,如果没有,则往下查找实例的原型Person.prototype
是否有name属性,这时候刚好找到name属性的值为zhang。如果还没找到,继续往下找原型的原型是否有该属性,直到Object.prototype是否有该属性,如果最终还没是没找到就返回undefined,这就构成了一个原型链。
4、__proto__属性
看上图, person是实例对象, Person.prototype 是这个实例的原型, person 通过 __proto__
属性来引用它的原型, 不过这个属性是一个非标准的方式,被一些游览器弃用,可通过Object.getPrototypeOf(obj)
这种标准方式获取对象的原型。
console.log(person.__proto__===Person.prototype) //true
console.log(person.__proto__===Object.getPrototypeOf(person)) //true
5、constructor属性
构造函数Person通过prototype
属性引用实例的原型, 返过来原型通过constructor
属性引用构造函数,原型和构造函数通过属性互相引用对方。
可通过如下代码检验Person.prototype.constructor是不是指向构造函数
console.log(Person.prototype.constructor===Person) //true
参考链接:
https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Objects/Object_prototypes
https://github.com/mqyqingfeng/Blog/issues/2
https://github.com/jawil/blog/issues/13
关注公众号「Python之禅」,回复「1024」免费获取Python资源