原型链(Prototype Chain) vs 作用域链(Scope Chain)的区别
JavaScript核心机制对比:原型链与作用域链 原型链用于对象属性/方法的继承查找,基于__proto__和prototype构成,顶端为Object.prototype。典型应用包括类继承和new的实现。 作用域链用于变量/函数的查找,基于词法环境(函数嵌套结构),顶端为全局作用域。主要应用于闭包和变量作用域管理。 关键区别: 构成:原型链通过对象关联,作用域链通过函数嵌套 用途:原型链处理
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__
(实例对象)。 -
主要用于继承(如
class
、new
的实现)。 -
顶端是
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) |
典型应用 | 继承、class 、new |
闭包、变量作用域、let/const |
4. 面试常见问题
Q1:如何手动修改原型链?
-
通过
Object.setPrototypeOf(obj, prototype)
或直接修改obj.__proto__
(不推荐)。<!DOCTYPE html>
Q2:如何手动修改作用域链?
-
无法直接修改,因为作用域链由词法环境决定(函数定义时确定)。
-
但可以通过
eval
、with
(已废弃)间接影响(不推荐)。
Q3:this
的查找是原型链还是作用域链决定的?
-
this
由调用方式决定(如obj.fn()
的this
是obj
),与作用域链无关。 -
但
this
访问的属性会走原型链查找。
总结
-
原型链:用于对象继承,基于
prototype
/__proto__
。 -
作用域链:用于变量查找,基于函数嵌套的词法环境。
-
关键区别:
-
原型链影响对象属性访问(如
obj.method()
)。 -
作用域链影响变量访问(如
let x = 1; function foo() { console.log(x); }
)。
-
理解这两者的区别,能更好地掌握 JS 的继承机制和作用域机制。
更多推荐
所有评论(0)