原型对象跟构造函数的关系
- 在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更大?
下面请大家看一张图,记住这张图哦,超级关键!
在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自己“生了”自己?
小结
捋清楚这个经典的问题,原型链就了解了大半,下一篇文章我们来看一下如何判断数据属于何种类型,以及通过手写这些判断方法加强对原型链的理解!