# 深入理解原型与原型链
- 原型的出现,就是为了解决 构造函数的缺点
- 给我们提供了一个给对象添加函数的方法。
构造函数的缺点👱♀️
缺点是每次实例化一个对象,都会把属性和方法复制一遍。浪费内存
# 构造函数
用来初始化新创建的对象的函数是构造函数。构造函数详解
function Foo(){};
var f1 = new Foo; // 构造函数无参可省略扩号
# 实例对象
通过构造函数的new
操作创建的对象是实例对象。
可以用一个构造函数,构造多个实例对象。
function Foo(){};
var f1 = new Foo;
var f2 = new Foo;
console.log(f1 === f2); // false
# prototype
- 构造函数有一个prototype属性,指向实例对象的原型对象。
- 通过同一个构造函数实例化的多个对象具有相同的原型对象。
- 经常使用原型对象来实现继承
function Foo(){};
Foo.prototype.xxx = '原型对象上的属性'; // 原型对象上添加属性
var f1 = new Foo;
var f2 = new Foo;
console.log(Foo.prototype.xxx); // 原型对象上的属性
console.log(f1.xxx); // 继承自原型对象上的属性
console.log(f2.xxx); // 继承自原型对象上的属性
# constructor
- 对象的
__proto__
里面也有一个成员叫做constructor
- 这个属性就是指向当前这个对象所属的构造函数
function Foo(){};
const f1 = new Foo;
console.log(f1.__proto__.constructor === Foo); // true
console.log(Foo.prototype.constructor === Foo); // true
console.log(f1.__proto__.constructor === Foo.prototype.constructor); // true
- 实例对象可以继承原型对象的属性,所以实例对象也拥有constructor属性,同样指向原型对象对应的构造函数
console.log(f1.constructor === Foo); // true
# proto
实例对象有一个__proto__
属性,指向该实例对象对应的原型对象。
console.log(f1.__proto__ === Foo.prototype); // true
# 详细说明
- 1、
__proto__
和constructor
属性是对象所独有的;prototype
属性是函数所独有的,因为函数也是一种对象,所以函数也拥有__proto__
和constructor
属性。 - 2、
__proto__
属性的作用就是当访问一个对象的属性时,如果该对象内部不存在这个属性,那么就会去它的__proto__
属性所指向的那个对象(父对象)里找,一直找,直到__proto__
属性的终点null
,再往上找就相当于在null
上取值,会报错。通过__proto__属性将对象连接起来的这条链路即我们所谓的原型链。 - 3、
prototype
属性的作用就是让该函数所实例化的对象们都可以找到公用的属性和方法,即f1.__proto__ === Foo.prototype
。 - 4、
constructor
属性的含义就是指向该对象的构造函数,所有函数(此时看成对象了)最终的构造函数都指向Function。
# 函数和对象的关系
var fn = function() {};
console.log(fn instanceof Function); // true
console.log(fn instanceof Object); // true
function Person()
console.log(Person.constructor) // Function() { [native code] }
console.log(Function.constructor) // Function() { [native code] }
console.log(Object.constructor) // Function() { [native code] }