1 构造函数存在的问题
如以下代码通过构造函数和new创建出了实例对象person1和person2。
function Person() {
this.age = age;
this.say = function () {
console.log('我想飞');
};
}
var person1 = new Person();
var person2 = new Person();
复制代码
构造函数中存在方法say()属于复杂数据类型,如下图所示每次调用时都会在开辟一个新的空间。虽然实例对象person1和person2调用的方法是同一方法,却要开辟两个相同的say()空间,如果有大量的实例对象将会造成大量的内存浪费。
2 原型对象prototype的作用
原型是什么?是对象。
原型的作用是什么?共享方法。
prototype原型对象解决了构造函数的问题,将构造函数中的方法存入构造函数的prototype原型对象中,不同的实例对象使用say()方法时,都是使用原型对象中的say(),如下图所示,大大节省了内存。
3 对象原型__proto__和构造函数constructor
3.1 __ proty __
每个实例对象都会有一个__proto__指向构造函数的 prototype 原型对象,所以我们可以通过实例对象的__proto__使用构造函数原型对象的属性和方法。如下列代码中__proto__对象原型和原型对象 prototype 是等价的。
function Person() {}
var person1 = new Person();
console.log(Person.prototype === person1.__proto__);//返回 true
复制代码
3.2 constructor
对象原型__proto__和构造函数prototype原型对象里面都有一个属性 constructor 属性 ,constructor 我们称为构造函数,因为它指回构造函数本身。
constructor 主要用于记录该对象引用于哪个构造函数,它可以让原型对象重新指向原来的构造函数。
注意:是可以修改的,不可靠。
4 构造函数、实例对象、原型对象三者的关系。
- 通过构造函数Person和new创建了对象实例person1。
- person1.__ptoto__指向构造函数Person.prototype原型对象
- Person.prototype的constructor指向了构造函数Person
5 JS查找机制
- 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。
- 如果没有就查找它的原型(也就是 __proto__指向的 prototype 原型对象)。
- 如果还没有就查找原型对象的原型(Object的原型对象)。
- 依此类推一直找到 Object 为止(null)。
- __proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线。
6 原型链
根据查找机制可以很轻松的搞清楚原型链,需要注意的是:
- 在JS里,函数就是Function函数的实例对象,所有函数都是Function构造的。
- Object.prototype是所有对象(直接或间接)的原型。
7 Function和Object的特殊性。
-
首先Function的构造函数是自身,即
Function.__proto__ === Function.prototype
。 -
Function也是Object的构造函数,所以
Function.prototype === Object.__proto__
。 -
同时Function的prototype原型对象也是Object的实例对象
Function.prototype.__proto__ === Object.prototype
但是Object又是Function的实例对象。Object.__proto__ === Function.prototype
即你是我的对象,我是你的对象。 -
最终的prototype原型对象属于Object
Object.prototype.__proto__ === null