JavaScript原型和原型链

101 阅读3分钟

原型

向实例对象内添加方法 在构造函数体内 直接向实例对象添加方法,这个行为不好会产生问题,

function Person(name, age) {
    this.name = name
    this.age = age
    
    this.sayHi = function () { console.log('hello') }
}
var p1 = new Person('aa', 18)
var p2 = new Person('bb', 20)

问题: 把方法书写在构造函数体内。每次创建实例的时候,都会创建一个函数数据类型,多个函数方法,一模一样,但是占据了多个存储空间 20220801.png

解决问题1:用到原型

  • 概念:每一个构造函数天生自带一个prototype属性,是一个对象数据类型, 原型对象

  • 概念:每一个对象天生自带一个属性__proto__,指向所属构造函数的prototype。

function Person() {}

Proson.prototype.a = 100
Proson.prototype.b = 200

//p1所属的构造函数就是 Person
//p1.__proto__ 指向 Person.prototype
var p1 = new Person()
console.log(p1.__proto__ === Person.prototype) //true

20220802.png

  • 概念:当访问对象成员的时候,首先在自己身上查找,如果没有,自动去到 __proto__ 上查找

对象的__proto__属性,指向所属构造函数的prototype

function Person() {}

Proson.prototype.a = 100
Proson.prototype.b = 200

var p1 = new Person()

//当访问p1.a的时候
//p1自己没有a, 会自动去找 __protp__ 上查找
//又因为 p1 自己的 __protp__ 就是 Person.prototype
//所以,其实是去Person.prototype上查找, 即:Person.prototype.a
console.log(p1.a)

如何解决问题: 把需要添加给实例的方法,放在构造函数的原型(prototype)上,就可以有实例进行访问使用。

应用:

function Person(name, age) {
    this.name = name
    this.age = age
}

Person.prototype.sayHi = function () { console.log('hello') }

var p1 = new Person('Jack', 18)
var p2 = new Person('Rose', 20)

//p1.__proto__ 和 p2.__proto__是一个对象空间,指向Person的prototype
//p1.sayHi 和 p2.sayHi 是一个

console.log(p1.sayHi === p2.sayHi) //true

20220803.png

总结:

  • 什么是原型:构造函数天生自带一个prototype
  • 作用:有构造函数添加方法,专门给实例对象使用

原型链

function Person() {}
var p1 = new Person()

问题1:实例对象身上的 __proto__ 指向谁

  1. 指向所属构造函数的 prototype
  2. p1.__proto__ 指向 Person.prototype

问题2:Person.prototype 的__proto__ 指向谁

  1. Person.prototype 所属构造函数是谁?
  2. 因为Person.prototype是一个对象数据类型(Object),在 JS 内所有的 Object 数据类型都是属于 Object 这个内置构造函数
  3. 所以 Person.prototype 是属于 Object 这个内置构造函数,Person.prototype.__proto__ 指向 Object.prototype

问题3:Person(函数/对象)的 __proto__ 指向谁

  1. Person 是一个函数, 函数本身也是一个对象,就会有 __proto__,在 JS 内所有的函数都是内置构造函数 Function 的实例
  2. Person.__proto__ 指向 Function.prototype

问题4:Object.prototype 的__proto__ 指向谁

  1. Object.prototype 是一个对象数据类型,属于 Object 这个内置构造函数
  2. 注意:Object.prototype 在 JS 内叫做顶级原型,不在有 __proto__
  3. 所以,Object.prototype__proto__ 指向 null

问题5:Object 的__proto__ 指向谁

  1. Object 是内置构造函数(函数对象),属于内置构造函数 Function 的实例
  2. 所以,Object.__proto__ 指向 Function.prototype

问题6:Function.prototype 的__proto__ 指向谁

  1. Function.prototype 也是一个对象,属于 Object 这个内置构造函数
  2. Function.prototype.__proto__ 指向 Object.prototype

问题7:Function 的__proto__ 指向谁

  1. Function 也是一个内置构造函数,也是一个函数
  2. 在 JS 内,所有的函数都是属于内置构造函数 Function 的实例
  3. Function 自己是自己的构造函数,自己是自己的实例对象

20220901.png

原型链定义:

__proto__串联起来的对象链状结构

每一个对象数据类型,都有一个属于自己的原型链

作用:为了访问对象成员

20220902.png

20220903.png

对象访问机制: 当需要访问对象成员的时候,

  1. 首先在自身查找,如有有直接使用
    • 如果没有,自动去 __proto__ 上查找
    • 如果还没有,再去 __proto__ 上查找
  2. 直到 Object.prototype 都没有,那么返回 undefined