原型链,实例原型与实例对象

原型链,实例原型与实例对象

构造函数与实例原型

什么是构造函数?

构造函数与普通函数的区别:

1. 构造函数通常以大写字母开头命名,普通函数则常采用驼峰式命名或纯小写;
2. 调用方式不同:构造函数常用new关键字调用,普通函数直接调用函数名。
3. 意义不同:构造函数代表生成一个类,和关联一个原型实例,其类名就是它的函数名;普通函数只是调用函数并执行函数体。
4. 构造函数通过this来构造类的属性和方法。

new一个对象的过程中发生了什么?

  1. 创建一个新对象;
  2. 将构造函数的作用域赋给新对象(因此this就指向了这个新对象);
  3. 执行构造函数中的代码(为这个新对象添加属性);
  4. 返回新对象。

那么构造函数和原型对象,也就是实例原型的关系是什么?

每一个构造函数被创建后,都会与实例原型相关联,其关联方式就
是通过prototype指针,指向原型对象(实例原型)。

构造函数又称为对象构造器,而每个实例原型与构造器之间通过constructor进行关联,也就是说实例原型有一个指针指向构造函数,这个指针就是constructor。

举个栗子~

1
2
3
4
5
6
7
8
9
10
11
12
13
function Person(){
this.type="human";
}
// 构造函数===Person对象的构造器

Person.prototype
// 实例原型

Person.prototype.constructor
// 实例原型的构造器==> Person函数

Person.prototype.constructor===Person
// true

实例对象

通过 new 关键词调用构造器函数可以创建相同类型的对象:这个对象就叫做实例对象,而构造器函数又可以称为这个对象的类。

通过instanceof可以判断这个对象是否继承自该类。

1
2
3
4

var person=new Person()
person instanceof Person
//true

对于每一个对象,都会有一个内部指针,指向原型对象。该指针为proto

1
2
person.__proto__===Person.prototype
// true

那么如果我找到person的构造器是谁,这时候应该怎么办?

这就是原型链的核心,通过原型链向上寻找一些属性。

person.constructor本来在person实例对象中是没有constructor的,但是其原型对象是有constructor属性,当我们在控制台输入person.constructor时,是可以获取到其构造器Person。
这个过程就是person到其原型对象,也就是通过proto向上寻找,看每个原型对象是否有该属性,如果有,则停止寻找并返回结果。

所以,实际上,就是通过person.proto.constructor找到的Person。

验证一下

1
2
person.constructor===Person.prototype.constructor
// true

原型链

如果原型对象找不到,那么则去找原型对象的原型对象。
最上层的原型对象是谁呢?

答案是,Object。

因为实际上JavaScript中只有一种复杂结构,就是Object,所以所有对象都是位于原型链顶层Object的实例。

当谈到继承时,JavaScript 只有一种结构:对象。每个实例对象( object )都有一个私有属性(称之为 proto )指向它的构造函数的原型对象(prototype )。该原型对象也有一个自己的原型对象( proto ) ,层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节。几乎所有 JavaScript 中的对象都是位于原型链顶端的 Object 的实例。

继承与原型链 - JavaScript | MDN

所以可以这么理解,Person的原型对象其实是Object原型对象的实例对象,所以通过内部指针proto可以访问到Object的原型对象,为什么说是Object的原型对象呢,因为Object本身是一个对象构造器。

1
2
Person.prototype.__proto__==Object.prototype
//true