# 原型与原型链

面向对象编程 (opens new window)

# 原型

在JavaScript中,数组,对象和函数被称为引用类型,他们都有一个__proto__属性,该属性是一个对象(我们称之为隐式原型)

JS中所有函数都会有prototype属性(我们暂时称之为显式原型),这个属性只有函数才有,其所有的属性和方法都能被构造函数的实例对象共享访问原型链

# 原型链

function Fn(){}
const fn = new Fn();

fn.__proto__ === Fn.prototype  //true

// __proto__ 隐式原型
// prototype 显式原型
1
2
3
4
5
6
7
  • 每个实例对象( object )都有一个私有属性(称之为 proto )指向它的构造函数的原型对象(prototype )。该原型对象也有一个自己的原型对象( proto ) ,层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节。
  • 只有函数才有 prototype 属性

当你创建函数时,JS会为这个函数自动添加prototype属性,其值是一个有 constructor属性的对象,不是空对象。而一旦你把这个函数当作构造函数(constructor)调用(即通过new关键字调用),那么JS就会帮你创建该构造函数的实例,实例继承构造函数prototype的所有属性和方法

(实例通过设置自己的__proto__指向承构造函数的prototype来实现这种继承)。

img

# new

new做了什么?

  • 创建一个空对象,这个对象将会作为执行 new 构造函数 () 之后,返回的对象实例。
  • 将上面创建的空对象的原型(proto),指向构造函数的 prototype 属性。
  • 将这个空对象赋值给构造函数内部的 this,并执行构造函数逻辑。
  • 根据构造函数执行逻辑,返回第一步创建的对象或者构造函数的显式返回值。
function Person(name) {
	this.name = name
}

// 使用
const person = new newFunc(Person, 'lucas')
1
2
3
4
5
6

new实现:

function newFunc(Fn, ...args) {
	const obj = {};
  obj.__proto__ = Fn.prototype;
	const result = Fn.apply(obj, args)
	return (typeof result === 'object' && result != null) ? result : obj
}
//构造函数如果有显式返回值,且返回值为对象类型,那么构造函数返回结果不再是目标实例。
function Person(name) {
	this.name = name
	return {1: 1}
}
const person = new Person(Person, 'lucas')
console.log(person)
1
2
3
4
5
6
7
8
9
10
11
12
13

# Object和Function

Object instanceof Function // true
Function instanceof Object // true
1
2
  • 所有对象均从Object.prototype继承属性
  • Function.prototypeFunction.__proto__为同一对象。
  • Function.prototype继承于Object.prototype
  • Object本身是个(构造)函数,是Function的实例(对象)

先有Object.prototype(原型链顶端),Function.prototype继承Object.prototype而产生,最后,FunctionObject和其它构造函数继承Function.prototype而产生。

img

# 理解

  1. prototype是构造函数的属性,指向属于该构造函数原型对象
  2. proto是任何对象的属性,指向该对象的构造函数原型对象
  3. prototype和__proto__之间的唯一区别就在于前者是构造函数的属性,而后者是对象的属性
  4. 构造函数也是对象,也有__proto__属性,所有构造函数的__proto__的属性指向构造函数Function()原型对象
  5. 原型对象是单纯的对象,其_ proto_ 属性指向构造函数 Obejct() 的原型对象
Object.__proto__ === Function.prototype  // true

Function.__proto__ === Function.prototype  // true

Function.prototype.__proto__ === Object.prototype  // true

Object.prototype.__proto__  === null
1
2
3
4
5
6
7