JavaScript 中的作用域链(Scope chain)是一种用于查找变量和函数的机制,它是由嵌套的作用域环境组成的链式结构。
当在 JavaScript 中访问一个变量或函数时,解析器会首先在当前作用域中查找该标识符。如果找不到,则会沿着作用域链向上查找,直到全局作用域为止。作用域链的顶端是全局作用域,也就是全局环境。
在函数被定义时,它会捕获自己创建时的作用域环境,并将其保存在一个内部属性中,称为 [[Scope]]。当函数被调用时,会创建一个新的执行上下文,并且该执行上下文的作用域链会包含函数自身的作用域以及函数定义时所处的作用域。
这种嵌套的作用域链机制使得内部函数可以访问其外部函数的变量和函数,即使外部函数已经执行完毕。这种特性称为闭包(Closure)。
下面是一个简单的例子来说明作用域链的工作方式:
- function outer() {
- var outerVar = "Hello";
-
- function inner() {
- var innerVar = "World";
- console.log(outerVar + " " + innerVar);
- }
-
- inner();
- }
-
- outer(); // 输出 "Hello World"
在上述代码中,inner
函数可以访问到 outer
函数的 outerVar
变量,因为 inner
函数的作用域链包含了 outer
函数的作用域。
需要注意的是,当在作用域链上查找标识符时,解析器会在找到第一个匹配的标识符后停止搜索,因此如果在当前作用域和外部作用域都存在同名的变量或函数,则会使用最近的那个。
原型链(Prototype chain)是 JavaScript 中实现对象之间继承的一种机制。每个对象都有一个指向其原型(prototype)的内部链接,通过这个链接可以访问父对象的属性和方法。
在 JavaScript 中,对象可以通过原型继承属性和方法。当访问一个对象的属性或方法时,如果对象自身没有该属性或方法,引擎会沿着原型链向上查找,直到找到匹配的属性或方法或者到达原型链的末端(通常是 Object.prototype
)。
利用原型链实现继承的方式是创建一个对象作为另一个对象的原型。这样,子对象就可以继承父对象的属性和方法。
下面是几种常见的利用原型链实现继承的方式:
通过创建一个对象并将其设置为另一个对象的原型来实现继承。
- // 父对象构造函数
- function Parent(name) {
- this.name = name;
- }
-
- // 子对象构造函数
- function Child() {}
-
- // 将父对象的实例设置为子对象的原型
- Child.prototype = new Parent('John');
-
- var child = new Child();
- console.log(child.name); // 输出 "John"
通过在子对象的构造函数中调用父对象的构造函数来继承属性。
- // 父对象构造函数
- function Parent(name) {
- this.name = name;
- }
-
- // 子对象构造函数
- function Child(name) {
- Parent.call(this, name);
- }
-
- var child = new Child('John');
- console.log(child.name); // 输出 "John"
-
结合原型继承和构造函数继承的方式来实现继承。
- // 父对象构造函数
- function Parent(name) {
- this.name = name;
- }
-
- // 子对象构造函数
- function Child(name) {
- Parent.call(this, name);
- }
-
- // 设置父对象的实例为子对象的原型
- Child.prototype = Object.create(Parent.prototype);
- Child.prototype.constructor = Child;
-
- var child = new Child('John');
- console.log(child.name); // 输出 "John"
通过利用原型链实现继承,可以避免属性和方法的重复定义,实现代码的复用和组织。子对象可以共享父对象的属性和方法,并可以在自身上添加新的属性和方法。这种继承方式是 JavaScript 中常见的面向对象编程的基础。