搞懂 JS 原型与原型链,不再面试吃瘪

57 阅读2分钟

在 JavaScript 中,对象的属性和方法并不都存在于自身,有一部分存放在 原型对象(prototype) 中。理解“原型”与“原型链”,是掌握 JS 面向对象编程的关键。


对象的存储区域

对象的属性和方法主要有两个存储位置:

  1. 对象自身

    • 通过 this.xxx = ... 或者 实例字段 定义的属性
    • 每个实例对象都会有独立的副本
    class Person {
      name = 'linxi'          // 实例字段(存在于对象自身)
      fn = () => console.log('haha') // 箭头函数也存在于对象自身
      sayHello = '自身对象'   // 普通属性
      
      sayHello() {
        console.log('原型对象') // 方法存在于原型对象中
      }
    }
    
    const d1 = new Person()
    console.log(d1.sayHello) // 优先访问自身对象属性 → '自身对象'
    

    注意:方法 sayHello(){} 存放在 原型对象 上,而 sayHello = '自身对象' 存在 对象自身。访问时,自身优先级高于原型


访问原型对象

每个对象都有一个内部指针,指向它的原型对象。
常见访问方式有两种:

  1. obj.__proto__(不推荐,非标准,已废弃)
  2. Object.getPrototypeOf(obj)(推荐,标准方法)

示例:

class Person {
  sayHello() {
    console.log('我在原型对象')
  }
}

const p = new Person()
const obj = { name: 'obj' }

console.log(Object.getPrototypeOf(p))   // Person.prototype
console.log(p.__proto__)                // 等价,但不推荐
console.log(p.__proto__.__proto__)      // Object.prototype
console.log(p.__proto__.__proto__.__proto__) // null

如果在自身找不到属性,JS 会自动沿着 原型链 向上查找,直到 Object.prototype,再到 null


原型链结构

来看一个继承的例子:

class God {
  name = 'god'
  sayHello() {
    console.log('我便是自己的神')
  }
}

class Person extends God {
  name = 'person'
}

const GodInstance = new God()
const PersonInstance = new Person()

console.log('Person 原型链:')
console.log(PersonInstance.__proto__)                   // Person.prototype
console.log(PersonInstance.__proto__.__proto__)         // God.prototype
console.log(PersonInstance.__proto__.__proto__.__proto__) // Object.prototype
console.log(PersonInstance.__proto__.__proto__.__proto__.__proto__) // null

// 验证
console.log(Person.prototype === PersonInstance.__proto__)        // true
console.log(God.prototype === PersonInstance.__proto__.__proto__) // true

总结原型链:

PersonInstancePerson.prototypeGod.prototypeObject.prototypenull

小结

  1. 自身属性优先级 > 原型属性

    • 实例字段 / this.xxx 定义 → 自身
    • class 方法 → 原型
  2. 访问原型

    • Object.getPrototypeOf(obj)
    • obj.__proto__ (非标准)
  3. 原型链查询规则

    • 先查对象自身
    • 再查对象的原型
    • 一直向上,直到 Object.prototype
    • 若没找到 → 返回 undefined
  4. 继承的本质

    • 子类的原型对象指向父类的实例
    • 所以子类可以访问父类的属性和方法

适合面试的总结话术

JavaScript 的继承机制基于原型链:对象有一个 [[Prototype]] 指针(可通过 __proto__ 访问),它指向构造函数的 prototype。访问属性时,JS 会先在对象自身查找,如果没有,则沿着原型链向上查找,直到 Object.prototypenull。这也是 JS 实现继承、多态和代码复用的基础。