1. 核心概念

原型链(Prototype Chain) 作用域链(Scope Chain)
作用 用于对象属性/方法的查找(继承机制) 用于变量/函数的查找(作用域机制)
适用场景 面向对象(JS 的继承) 函数作用域、闭包、变量查找
数据结构 由 __proto__ 或 prototype 构成的链 由 Lexical Environment(词法环境)构成的链

2. 详细对比

(1) 原型链(Prototype Chain)

  • 作用:当访问一个对象的属性/方法时,如果当前对象没有,JS 会沿着 __proto__ 向上查找,直到 Object.prototype(原型链顶端)。

  • 触发时机

    const obj = {};
    obj.toString(); // 调用 Object.prototype.toString()
  • 关键点

    • 基于 prototype(构造函数)和 __proto__(实例对象)。

    • 主要用于继承(如 classnew 的实现)。

    • 顶端是 Object.prototype.__proto__ === null

示例

function Person(name) {
  this.name = name;
}
Person.prototype.sayHello = function() {
  console.log(`Hello, ${this.name}`);
};

const p = new Person("Alice");
p.sayHello(); // 先在 p 上找 sayHello,找不到就去 Person.prototype 上找

(2) 作用域链(Scope Chain)

  • 作用:当访问一个变量时,JS 引擎会从当前作用域开始查找,如果找不到,就向外层作用域逐层查找,直到全局作用域(window/global)。

  • 触发时机

    function outer() {
      const a = 1;
      function inner() {
        console.log(a); // 先在 inner 作用域找 a,找不到就去 outer 作用域找
      }
      inner();
    }
    outer();
  • 关键点

    • 基于词法作用域(函数定义时的位置决定作用域)。

    • 主要用于变量查找(如闭包、let/const 的作用域)。

    • 顶端是全局作用域window/global)。

示例

let x = 10;
function foo() {
  let y = 20;
  function bar() {
    console.log(x + y); // 先在 bar 作用域找 x、y,找不到就去 foo、全局作用域找
  }
  bar();
}
foo(); // 30

3. 关键区别总结

原型链 作用域链
用途 对象属性/方法查找 变量/函数查找
构成方式 prototype / __proto__ 词法环境(函数嵌套)
顶端 Object.prototype.__proto__ === null window(浏览器) / global(Node.js)
典型应用 继承、classnew 闭包、变量作用域、let/const

4. 面试常见问题

Q1:如何手动修改原型链?

  • 通过 Object.setPrototypeOf(obj, prototype) 或直接修改 obj.__proto__(不推荐)。

    <!DOCTYPE html>

Q2:如何手动修改作用域链?

  • 无法直接修改,因为作用域链由词法环境决定(函数定义时确定)。

  • 但可以通过 evalwith(已废弃)间接影响(不推荐)。

Q3:this 的查找是原型链还是作用域链决定的?

  • this 由调用方式决定(如 obj.fn() 的 this 是 obj),与作用域链无关。

  • 但 this 访问的属性会走原型链查找。


总结

  • 原型链:用于对象继承,基于 prototype/__proto__

  • 作用域链:用于变量查找,基于函数嵌套的词法环境。

  • 关键区别

    • 原型链影响对象属性访问(如 obj.method())。

    • 作用域链影响变量访问(如 let x = 1; function foo() { console.log(x); })。

理解这两者的区别,能更好地掌握 JS 的继承机制作用域机制

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐