说到继承 ,先要弄明白 :构造函数、原型对象、实例之间的关系。
先来了解几个简单的概念:
构造函数:通过 关键字 new 来调用的 函数,var p = new Person();Person就称为构造函数。普通函数直接调用 Person() 。一个构造函数可以实例化多个对象,这些个对象并具有相同的原型对象
实例对象:通过new操作构造函数所创建的对象是实例对象,一个构造函数可以实例化多个对象,但各个实例对象并不相等
原型对象:原型对象的constructor属性 用于 返回 创建该对象的函数 ,也就是常说的构造函数。所以原型对象的constructor属性指向的是构造函数。
prototype 和 __proto__的区别
prototype:每个函数都有一个prototype属性,该属相指向的便是原型对象,值是一个对象。只有函数才有,实例对象没有 prototype
__proto__:实例对象,都有一个__proto__ 属性,该属性指向 创建该实例对象 的 构造函数的原型。
直接上图吧,看的更清楚
三者的关系,一看图就很清晰了吧:
1、函数对象 Student 的 prototype 指向原型对象,
2、原型对象的 constructor 指向函数对象 Student。
3、实例对象 new Student() 的 __proto__属性 指向原型对象( Student.prototype ),这个属性的作用是:允许 实例通过该属性 访问 原型对象中的属性和方法。
所有的实例都有一个内部指针指向他的原型对象,并且可以访问到原型对象上的所有属性和方法
原型链:
在js中万物皆对象,由于__proto__是任何对象都有的属性,所以会形成一条__proto__连起来的链条,一直向上找 __proto__直到最终到头,并且值是null。如上图中,最终找到 Object.prototype,并且值是null 了,就结束。
三者关系 我们来看几行代码:
console.log(s1.__proto__ === Student.prototype);//ture;
console.log('123'.__proto__ === String.prototype);//ture;
console.log([].__proto__ === Array.prototype);//ture;
console.log(s1.__proto__.__proto__ === Object.prototype);//true
console.log(Object.prototype.__proto__)//null Object.prototype是原型链的终点
//所有的实例都是通过Function创建出来的
console.log(Object.__proto__ === Function.prototype)//true
console.log(Function.__proto__ === Function.prototype)//true
查找对象的属性时,先查找对象本身是否存在该属性,如果不存在,会在原型链中查找,逐层向上查找,直到找到为止,
总结一下:
-
每个函数都有一个属性prototype,值是一个对象。只有函数才有,实例对象没有prototype属性。
-
所有的实例对象中,都有一个__proto__ 属性,该属性指向创建该实例对象的构造函数的原型
-
所有的原型对象都有constructor属性,该属性指向创建该实例的构造函数。
-
函数对象和原型对象通过prototype和constructor属性进行相互关联。
-
所有的函数都是Function的实例。
-
Function也是自己的实例。
好啦 这一篇先到这里。我的文章都是学习过程中的总结,如果发现错误,欢迎留言指出,我及时更正