原型链

原型链知识点总结

prototype(显式原型) 和 __proto__(隐式原型)的关系

构造函数的prototype和其实例proto是指向同一个地方的,这个地方就叫做原型对象

构造函数就是可以用了来new的函数,箭头函数不可用来做构造函数

1
2
3
4
5
6
7
8
function Person(name,age){
this.name = name
this.age = age
}

// 这是实例
const person1 = new Person('小明', 20)
const person2 = new Person('小红', 30)

构造函数的prototype和其实例proto指向同一地方,验证如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.sayName = function() {
console.log(this.name)
}
console.log(Person.prototype) // { sayName: [Function] }

const person1 = new Person('小明', 20)
console.log(person1.__proto__) // { sayName: [Function] }

const person2 = new Person('小红', 30)
console.log(person2.__proto__) // { sayName: [Function] }

console.log(Person.prototype === person1.__proto__) // true
console.log(Person.prototype === person2.__proto__) // true

构造函数的prototype和其实例的__proto__指向同一地方

函数

上面提到了构造函数,说到底也是个函数,平时定义函数,无非有一下几种方式

1
2
3
4
5
6
7
8
9
10
11
12
13
function fn1(name, age) {
console.log(`我是${name}, 我今年${age}岁`)
}


const fn2 = function(name, age){
console.log(`我是${name}, 我今年${age}岁`)
}


const arrowFn = (name, age) => {
console.log(`我是${name}, 我今年${age}岁`)
}

其实这几种的本质是一样的(只考虑函数的声明),都可以用 new Function 来声明, 所以 Function 也是一个构造函数,上面的写法等同于

1
2
3
4
5
const fn1 = new Function('name','age','console.log(`我是${name}, 我今年${age}岁`)')

const fn2 = new Function('name','age','console.log(`我是${name}, 我今年${age}岁`)')

const arrowFn = new Function('name','age','console.log(`我是${name}, 我今年${age}岁`)')

构造函数的prototype 和其实例的 proto是指向同一个地方的,这里的fn1,fn2,arrowFn其实就是Function构造函数的实例 ,验证如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function fn1(name, age) {
console.log(`我是${name}, 我今年${age}岁`)
}

const fn2 = function(name, age){
console.log(`我是${name}, 我今年${age}岁`)
}

const arrowFn = (name, age) => {
console.log(`我是${name}, 我今年${age}岁`)
}

console.log(Function.prototype === fn1.__proto__) // true
console.log(Function.prototype === fn2.__proto__) // true
console.log(Function.prototype === arrowFn.__proto__) // true

构造函数其实也是Function类的实例

Person函数也可以看成 const Person = new Function() 这样生成的,所以Person也就是Function构造函数的实例,所以Person就会有__proto__指向Function.prototype

对象

平常开发中,创建一个对象,通常会有一下几种方式

  • 构造函数创建对象,他创建出来的对象都是此Function构造函数的实例,所以这里先不讨论
  • 字面量创建
  • new Object()
  • Object.create()创建对象,创建出来的是一个空原型的对象,这里先不讨论
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 第一种:构造函数创建对象
function Person(name, age) {
this.name = name
this.age = age
}
const person1 = new Person('张三', 10)
console.log(person1) // Person { name: '张三', age: 10 }

// 第二种:字面量创建对象
const person2 = {name: '张三', age: 10}
console.log(person2) // { name: '张三', age: 10 }

// 第三种:new Object创建对象
const person3 = new Object()
person3.name = '张三'
person3.age = 10
console.log(person3) // { name: '张三', age: 10 }

// 第四种:Object.create创建对象
const person4 = Object.create({})
person4.name = '张三'
person4.age = 10
console.log(person4) // { name: '张三', age: 10 }

字面量创建对象本质就是new Object创建对象

1
2
3
4
5
6
7
8
9
10
11
// 字面量创建对象
const person2 = {name: '张三', age: 10}
console.log(person2) // { name: '张三', age: 10 }

本质是

// new Object创建对象
const person2 = new Object()
person2.name = '张三'
person2.age = 10
console.log(person2) // { name: '张三', age: 10 }

我们之前说过,构造函数的prototype和其实例的__proto__是指向同一个地方的,这里的person2,person3其实也都是Object构造函数的实例。验证如下

1
2
3
4
5
6
7
8
const person2 = {name: '张三', age: 10}

const person3 = new Object()
person3.name = '张三'
person3.age = 10

console.log(Object.prototype === person2.__proto__) // true
console.log(Object.prototype === person3.__proto__) // true

对象是Object类的实例

Function和Object

上面证明

  • 函数Function构造函数的实例
  • 对象Object构造函数的实例

Function构造函数Object构造函数他们两个又是谁的实例?

  • function Object()其实也是个函数,所以他是Function构造函数的实例
  • function Function()其实也是个函数,所以他也是Function构造函数的实例,没错,他是他自己本身的实例
1
2
console.log(Function.prototype === Object.__proto__) // true
console.log(Function.prototype === Function.__proto__) // true

Object类和Function类也是Function构造函数的实例

constructor

constructor和prototype是成对的,你指向我,我指向你。举个例子,如果你是我老婆,那我肯定是你的老公。

1
2
3
4
function fn() {}

console.log(fn.prototype) // {constructor: fn}
console.log(fn.prototype.constructor === fn) // true

constructor和prototype是成对的,你指向我,我指向你

原型链

person.prototype 和 Function.prototype

  • Person.prototype, 他是构造函数Person的原型对象
  • Function.prototype,他是构造函数Function的原型对象

可知其本质都是对象

所以肯定是通过new Object()来创建的。既然是通过new Object()创建的,那就说明Person.prototype和Function.prototype都是构造函数Object的实例 。 也就说明了Person.prototypeFunction.prototype他们两的__proto__都指向Object.prototype

1
2
3
4
function Person(){}

console.log(Person.prototype.__proto__ === Object.prototype) // true
console.log(Function.prototype.__proto__ === Object.prototype) // true

原型对象其实都是Object类的实例

什么是原型链?

__proto__的路径就叫原型链

__proto__的查找路径就叫原型链

原型链终点

上面咱们看到,三条原型链结尾都是Object.prototype,那是不是说明了Object.prototype就是原型链的终点呢?其实不是的,Object.prototype其实也有__proto__,指向null,那才是原型链的终点
至此,整个原型示意图就画完啦!!!

null是原型链终点

原型继承

说到原型,就不得不说补充一下原型继承这个知识点了,原型继承就是,实例可以使用构造函数上的prototype中的方法

1
2
3
4
5
6
7
8
9
10
11
12
function Person(name) { // 构造函数
this.name = name
}
Person.prototype.sayName = function() { // 往原型对象添加方法
console.log(this.name)
}


const person = new Person('张三') // 实例
// 使用构造函数的prototype中的方法
person.sayName() // 张三

原型继承就是实例可以使用构造函数上的方法

instanceof

使用方法

1
A instance B

作用:判断B的prototype是否在A的原型链上

1
2
3
4
5
6
7
8
9
10
11
function Person(name) { // 构造函数
this.name = name
}

const person = new Person('张三') // 实例

console.log(Person instanceof Function) // true
console.log(Person instanceof Object) // true
console.log(person instanceof Person) // true
console.log(person instanceof Object) // true