# 原型与原型链
# 原型
在JavaScript中,数组,对象和函数被称为引用类型,他们都有一个__proto__属性,该属性是一个对象(我们称之为隐式原型)
JS中所有函数都会有prototype属性(我们暂时称之为显式原型),这个属性只有函数才有,其所有的属性和方法都能被构造函数的实例对象共享访问原型链
# 原型链
function Fn(){}
const fn = new Fn();
fn.__proto__ === Fn.prototype //true
// __proto__ 隐式原型
// prototype 显式原型
1
2
3
4
5
6
7
2
3
4
5
6
7
- 每个实例对象( object )都有一个私有属性(称之为 proto )指向它的构造函数的原型对象(prototype )。该原型对象也有一个自己的原型对象( proto ) ,层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节。
- 只有函数才有 prototype 属性
当你创建函数时,JS会为这个函数自动添加prototype
属性,其值是一个有 constructor
属性的对象,不是空对象。而一旦你把这个函数当作构造函数(constructor)调用(即通过new关键字调用),那么JS就会帮你创建该构造函数的实例,实例继承构造函数prototype
的所有属性和方法
(实例通过设置自己的__proto__
指向承构造函数的prototype
来实现这种继承)。
# new
new做了什么?
- 创建一个空对象,这个对象将会作为执行 new 构造函数 () 之后,返回的对象实例。
- 将上面创建的空对象的原型(proto),指向构造函数的 prototype 属性。
- 将这个空对象赋值给构造函数内部的 this,并执行构造函数逻辑。
- 根据构造函数执行逻辑,返回第一步创建的对象或者构造函数的显式返回值。
function Person(name) {
this.name = name
}
// 使用
const person = new newFunc(Person, 'lucas')
1
2
3
4
5
6
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
2
3
4
5
6
7
8
9
10
11
12
13
# Object和Function
Object instanceof Function // true
Function instanceof Object // true
1
2
2
- 所有对象均从
Object.prototype
继承属性 Function.prototype
和Function.__proto__
为同一对象。Function.prototype
继承于Object.prototype
Object
本身是个(构造)函数,是Function
的实例(对象)
先有Object.prototype
(原型链顶端),Function.prototype
继承Object.prototype
而产生,最后,Function
和Object
和其它构造函数继承Function.prototype
而产生。
# 理解
- prototype是构造函数的属性,指向属于该构造函数的原型对象
- proto是任何对象的属性,指向该对象的构造函数的原型对象
- prototype和__proto__之间的唯一区别就在于前者是构造函数的属性,而后者是对象的属性
- 构造函数也是对象,也有__proto__属性,所有构造函数的__proto__的属性指向构造函数Function()的原型对象
- 原型对象是单纯的对象,其_ 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
2
3
4
5
6
7