原型

97 阅读3分钟

原型对象prototype

为什么会有原型对象

js在设计之初,并不打算像java一样作为面向对象的编程语言,他想更简单更轻量一些,只要能满足当时简单的需求就可以了,所以js最初没有‘类’,‘继承’等概念,一个实例对象通过函数来new出来。但是对于同一类的实例对象来说,共性的属性不应该是每次创建的时候都去创建一次。所以引入了原型对象prototype,并将这些共性的属性放在原型对象prototype上。举个例子:

function Dog(name){
    this.name = name;
    this.species = "犬"
}

let dog1 = new Dog("小黑")
let dog2 = new Dog("小黄")
dog1.species = "大型犬"
console.log(dog2.species) // 犬
function Dog(name){
    this.name = name;
}
DOG.prototype.species = '犬';

let dog1 = new Dog("小黑")
let dog2 = new Dog("小黄")
dog1.species = "大型犬"
console.log(dog2.species) // 大型犬

在上面的第一个例子中species是每个实力对象维护的,并不是一个Dog实例公用的属性,修改其中一个不会影响到另一个。而使用prototype后更符合“共性属性”的概念

引用 阮一峰_Javascript继承机制的设计思想

介绍原型对象prototype

他是构成函数存放共性属性的地方,是一个对象,通过函数创建的对象也将拥有这个原型对象 有以下这些特点:

  • 如果对象本身不存在属性或方法将到原型上查找
   function Person(){}
   Person.prototype.name = "yangchen"
   let p = new Person()
   console.log(p.name) // yangchen
  • 所有函数的原型默认是 Object的实例,所以可以使用toString 等方法的原因
    let obj = {
        name: "yangchen"
    }
    console.log(obj.toString) // '[object Object]'
    console.log(Object.prototype.toString === obj.toString) // true 同一个函数
  • 原型包含 constructor 属性,指向构造函数
    function Person(){}
    console.log(Person.prototype) // {constructor: ƒ}
    console.log(Person.prototype.constructor === Person) // true 构成函数详细说
  • 实例对象的 __proto__ 指向他的原型对象
    function Person(){}
    Person.prototype.name = "yangchen"
    let p = new Person()
    console.log(p.__proto__) // {name: 'yangchen', constructor: ƒ}
    console.log(p.__proto__ === Person.prototype) // true 

介绍原型链__proto__(两个_)

原型链:就是实例对象和原型对象之间的链接,每一个对象都有原型,原型本身又是对象,原型又有原型,以此类推形成一个链式结构.称为原型链

属性__proto__存在实例对象上,指向构成函数的原型对象prototype,构成函数是没有__proto__属性

查找实例对象的某个属性,会先实例对象是否拥有,如果不存在,则通过__proto__找到它的原型对象并判断是否拥有,如果还是不存在,继续通过__proto__往上层原型对象找。

    function Person(){}
    Person.prototype.name = "yangchen"
    let p = new Person()
    console.log(p.name) // yangchen
    console.log(p.__proto__) // {name: 'yangchen', constructor: ƒ}
    console.log(p.__proto__ === Person.prototype) // true 

原型关系分析

构成函数,实例对象,原型对象prototype,属性__proto__之间关系

    function Person(){}
    Person.prototype.name = "yangchen"
    let p = new Person()
    // 实例对象p的__proto__指向构成函数Person的原型对象prototype
    console.log(p.__proto__ === Person.prototype) // true 
    // 构成函数也是对象(因为函数也是对象),它也具有__proto__,指向他的父级prototype,这里的Person.__proto__指向的Function.prototype
    console.log(Person.__proto__ === Function.prototype)
    // 最顶级的父级原型是Object.prototype,且Object.__proto__为null,也就是查找属性的时候查找到这里结束了
    console.log(Object.prototype.__proto__) // null
    // 原型对象prototype的constructor属性指向构成函数自身
    console.log(Person.prototype.constructor === Person) // true

1683993648908.png 构造函数通过prototype指向原型对象,原型对象通过constructor指向构成函数

image.png

相关的api

  • instanceof
object instanceof constructor

检测构造函数的 prototype 属性是否出现在某个实例对象的原型链

function Person() {}
let p = new Person()
console.log(p instanceof Person)  // true
  • setPrototypeOf
Object.setPrototypeOf(obj, prototype)

设置一个指定的对象的原型

let a = {age: 18}
let b = {}
Object.setPrototypeOf(b, a)
console.log(b instanceof a)  // true
  • getPrototypeOf
Object.getPrototypeOf(object)

返回其原型的对象

let a = {age: 18}
let b = {}
Object.setPrototypeOf(b, a)
console.log(Object.getPrototypeOf(b) === a)  // true
  • Object.create
Object.create()

使用现有的对象来作为原型来创建新对象

let a = {age: 18}
let b = Object.create(a)
console.log(Object.getPrototypeOf(b) === a)  // true