原型与原型链

114 阅读2分钟

原型对象跟构造函数的关系

  • 在JS中,每当定义一个函数数据类型(普通函数,构造函数)的时候,它都会天生自带一个prototype属性,这个属性指向的是它的原型对象
  • 当函数经过new进行调用的时候,此时实例化后的对象会有一个__proto__属性指向它的构造函数的原型对象

原型链

  • 每一个实例对象都会有一个内部的私有属性(在大多数的实现是__proto__属性),当需要读取实例属性的时候,如果在当前实例对象中找不到,它就会通过__proto__去查找和与该对象关联的原型对象上有没有相关属性,如果还查不到就去找原型的原型。这样层层向上,直到找到一个对象的原型对象为null,像这样的链状结构被称为“原型链”。
  • 历史约定,null没有原型,它是原型链中的最后一个环节。

Constructor

function Person() {


}
var person = new Person();
console.log(person.constructor === Person); // true

当获取 person.constructor 时,其实 person 中并没有 constructor 属性,当不能读取到constructor 属性时,会从 person 的原型也就是 Person.prototype 中读取,正好原型中有该属性,所以:

person.constructor === Person.prototype.constructor

一个经典的问题

Function instanceof Object // ->true
Object instanceof Function // ->true

是不是看到这心生疑问了?我们知道,在JS语法中,所有对象都继承自Object,也就是说Object按着原型链继续向上查找就是null了,但是在上面的代码块中,Object却通过原型链往上找到了Function,难道Function比Object更大?

下面请大家看一张图,记住这张图哦,超级关键!

image.png

在JS语法中,Object确实是所有对象的“爹”,但这是因为他们的构造函数的原型对象是Object.prototype,而Object.prototype.constructor指向Object(这里涉及到instanceof的原理,在下一篇文章中有介绍)。

这里进入一段小插曲,通常我们在ES5中创建构造函数的时候都是用的function关键字,很明显,通过构造函数创建(new)出来的实例对象的__proto__属性都是指向构造函数.prototype,最重要的,构造函数.__proto__是指向Function.prototype。

在JS中,内置对象Object与Function大多以构造函数的身份出现,所以很显然,Object.proto===Function.prototype,Function.proto === Function.prototype;同时,JS中万事万物皆为对象,原型对象亦是如此,故而就有Function.prototype.__proto__是指向Object.prototype,XXX.prototype.__proto__指向Object.prototype;

Function instanceof Object
// Function.__proto__ -> Function.prototype
// Function.prototype.__proto__ -> Object.prototype
// Object.prototype.constructor -> Object
// ->true
Object instanceof Function 
// Object.__proto__ -> Function.prototype
// Function.prototype.constructor -> Function
// ->true
Function instanceof Function 
// Function.__proto__ -> Function.prototype
// Function.prototype.constructor -> Function
// ->true
Object instanceof Object
//  Object.__proto__ -> Function.prototype
// Function.prototype.__proto__ -> Object.prototype
// Object.prototype.constructor -> Object
// ->true
Number instanceof Number
// Number.__proto__ -> Function.prototype
// Function.prototype.__proto__ -> Object.prototype
// Object.prototype.constructor -> Object
// -> false
//或者
// Number.__proto__ -> Function.prototype
// Function.prototype.constructor -> Function
// ->false

最关键的地方就是那张图最下方的Function.proto === Function.prototype,这样看起来就像是,Function自己“生了”自己?

小结

捋清楚这个经典的问题,原型链就了解了大半,下一篇文章我们来看一下如何判断数据属于何种类型,以及通过手写这些判断方法加强对原型链的理解!