首页 > 编程语言 >JavaScript中的执行上下文和原型链

JavaScript中的执行上下文和原型链

时间:2024-07-09 15:54:54浏览次数:26  
标签:function 执行 console 函数 JavaScript 原型 上下文

目录

一、执行上下文

1.执行上下文

2.执行上下文栈

3.闭包

1)定义

2)形成条件

3)例子

(1)例子1:简单闭包

(2)例子2:闭包与循环

(3)例子3:使用闭包模拟私有变量

二、原型链

1.定义

2.原型(Prototype)与构造函数(Constructor)

3.原型链使用

1)工作原理

2)使用

(1)设置原型对象

(2)原型链的继承


一、执行上下文

在JavaScript中,每当代码执行时,都会创建一个执行上下文(Execution Context)。执行上下文是JavaScript代码执行时的环境,它决定了代码如何被解析和执行。执行上下文是JavaScript引擎的基础,用于管理代码执行期间的变量、函数等。

1.执行上下文

1)全局执行上下文:在全局作用域中定义的代码会在全局执行上下文中执行。在浏览器中,全局执行上下文是window对象。

2)函数执行上下文:每当调用函数时,都会创建一个新的函数执行上下文,这个上下文包含了函数的局部变量、参数等信息。

2.执行上下文栈

JavaScript引擎使用执行上下文栈(也称调用栈)来管理执行上下文。

当代码执行时,新的执行上下文会被推入栈中;当执行完成后,该上下文会从栈中弹出。

函数调用时会创建一个新的执行上下文,并将其推入栈中,当函数执行完毕后,其执行上下文就会从栈中弹出,继续之前的执行上下文。

例子1:

        function foo() {
            let x = 1;
            console.log(x);
        }

        let y = 2;
        foo(); // 输出: 1
        console.log(y); // 输出: 2

在这个例子中,首先会创建全局执行上下文,并在其中定义变量y,接着foo()函数调用,创建新的执行上下文,并定义变量x,当函数执行完毕后,其执行上下文会从栈中弹出,继续全局执行上下文,进行后续代码。

例子2:

let globalVar = 'I am global';
        function testGlobalContext() {
            let localVar = 'I am local';
            console.log(globalVar); // 访问全局变量
            console.log(localVar);  // 访问局部变量
        }

        testGlobalContext(); // 输出: I am global, I am local
        console.log(globalVar); // 输出: I am global

例子3:

var outerVar = 'I am outside';  
  
function outerFunction() {  
    var innerVar = 'I am inside';  
  
    function innerFunction() {  
        console.log(outerVar); // 访问外部函数作用域的变量  
        console.log(innerVar);  // 访问自身作用域的变量  
    }  
  
    innerFunction(); // 调用内部函数  
}  
  
outerFunction(); // 输出: I am outside, I am inside

这个例子中,outerVar是在全局作用域中定义的,而innerVar 是在outerFunction的函数作用域中定义的。innerFunction能够访问到 outerVar,是因为它位于outerFunction的作用域之内(即 outerFunction的执行上下文在 innerFunction执行时仍然存在于调用栈上)。

例子4:

function first() {  
    second();  
    console.log('First function');  
}  
  
function second() {  
    third();  
    console.log('Second function');  
}  
  
function third() {  
    console.log('Third function');  
}  
  
first(); // 调用顺序:first -> second -> third -> second -> first

结果:

3.闭包

1)定义

闭包(Closure)是一个函数值,它引用了其外部的作用域(词法作用域)中的变量。即使函数是在其外部作用域之外执行,它仍然可以访问那些变量。

  • 封装私有变量,变量只能通过特定的函数接口进行访问和修改,有助于保护数据不被外部随意访问。

  • 创建模块:闭包可以模拟模块的概念,实现模块的封装和隐藏实现细节。通过这种方式,可以将相关的函数和数据组织在一起,只暴露必要的接口给外部使用。

  • 回调函数和异步编程:在JavaScript中,闭包常用于处理回调函数和异步编程。

通俗解释:

现在有一个大房间(外部函数),里面有一个小盒子(局部变量),小盒子里放了一些东西(变量的值),还有一个能够进入这个大房间的门(外部函数的调用),但是这个房间里面的东西(包括小盒子)我们不能直接从房间外面看到或拿到。

这时,在房间里设置一个窗口(内部函数),通过这个窗口,可以把小盒子里的东西展示给房间外面的人看,或者允许修改小盒子里的东西。这个窗口加上它能看到的小盒子里的东西,以及它所在的房间,就构成了一个闭包。

2)形成条件

(1)函数嵌套

(2)内部函数引用了外部函数的变量

(3)内部函数被执行

3)例子

(1)例子1:简单闭包
// 外部函数,大房间
        function outerFunction() {
            var secret = "我是房间里的小盒子放的东西";
            // 内部函数,窗口
            function innerFunction() {
                // 通过内部函数(窗口)可以获取到小盒子里的东西
                console.log(secret);
            }
            return innerFunction; // 返回内部函数,形成闭包
        }

        var myClosure = outerFunction(); // 调用外部函数,此时不执行内部函数
        myClosure(); // 通过闭包访问外部函数的局部变量,输出: 我是房间里的小盒子放的东西

(2)例子2:闭包与循环
// 使用闭包来捕获每次循环的i值
        function createFunctionsFixed() {
            let result = [];
            for (let i = 0; i < 5; i++) {
                result.push((function(x) {
                    return function() {
                        return x; // 使用闭包捕获的x值
                    };
                })(i)); // 立即执行函数表达式,将当前的i值作为参数x传递给内部函数
            }
            return result;
        }

        let functionsFixed = createFunctionsFixed();
        for (let k = 0; k < functionsFixed.length; k++) {
            console.log(functionsFixed[k]()); // 输出0, 1, 2, 3, 4
        }

解析:

(function(x) {  
    return function() {  
        return x; // 使用闭包捕获的x值  
    };  
})(i)

这个函数是一个立即执行函数表达式(IIFE)。

(立即执行函数表达式,具体参考:

JavaScript之深入理解立即调用函数表达式(IIFE),你对它的理解,决定了它的出镜率(系列六)-CSDN博客

它的作用是立即执行并传递当前循环的 i 值作为参数 x 给内部函数,它创建了一个新的作用域,其中 x 是作为参数传入的 i 值的副本。

内部函数function使用闭包捕获x的值(即 i 值),使得可以在作用域外访问到 i 的值。

结果:

(3)例子3:使用闭包模拟私有变量
function Counter() {
            let privateCount = 0; // 私有变量
            function changeCount(value) {
                privateCount += value; // 修改私有变量的值
            }
            return {
                increment: function() {
                    changeCount(1); // 增加计数
                    return privateCount;
                },
                decrement: function() {
                    changeCount(-1); // 减少计数
                    return privateCount;
                },
                getCount: function() {
                    return privateCount; // 获取当前计数值
                }
            };
        }

        let myCounter = Counter(); // 创建一个计数器实例
        console.log(myCounter.getCount()); // 输出: 0
        myCounter.increment(); // 增加计数
        console.log(myCounter.getCount()); // 输出: 1
        myCounter.decrement(); // 减少计数
        console.log(myCounter.getCount()); // 输出: 0

这个例子中,Counter函数创建了一个包含私有变量privateCount的作用域,它返回了一个对象,该对象包含三个方法:increment,decrement,getCount,这些方法都可以被访问和修改。

二、原型链

1.定义

原型链是由多个原型对象通过__proto__属性连接起来形成的一种链式结构,它描述了对象之间或函数之间的原型继承关系,实现了继承和共享属性,使得对象能够继承其父对象或更上层父对象的属性和方法。

2.原型(Prototype)与构造函数(Constructor)

  • 每个函数都有一个prototype属性,这个属性是一个普通的对象,即函数的原型对象。
  • 通过new关键字创建的实例对象,会包含一个指向其构造函数原型对象的内部链接(通常通过__proto__属性访问,但__proto__不是标准属性,应使用Object.getPrototypeOf()方法)。

3.原型链使用

1)工作原理

(1)查找属性:当访问一个属性或方法时,js会首先在对象本身中查找,如果对象本身没有该属性,则会沿着原型链向上查找,直到找到原型链的顶端(通常是0bject.prototype,它的__proto__属性为null)。

(2)继承属性:原型链允许对象继承另一个对象的属性和方法,这是通过将对象的__proto__属性指向另一个对象的prototype属性来实现的。当访问对象的属性时,如果对象本身没有该属性,则会到原型对象中查找。

2)使用

(1)设置原型对象

在构造函数中,可以通过设置其prototype属性来定义实例对象可以继承的属性和方法。

例子:

function Person(name) {
            this.name = name;
        }

        Person.prototype.greet = function() {
            console.log('Hello, my name is ' + this.name);
        };

        let person1 = new Person('Alice'); // 继承属性

        // person1 的 __proto__ 指向 Person.prototype
        // 因此在person1中本身没有这个方法,但通过原型链向上查找,可以访问 Person.prototype 上的 greet 方法
        person1.greet(); // 输出: Hello, my name is Alice

该例子中的原型链是:person1 -> Person.prototype -> Object.prototype -> null

(2)原型链的继承

如果一个对象A的原型(prototype )是另一个对象B,那么A就能继承B的属性和方法。

可以通过将子类的prototype 设置为父类的一个实例来实现继承。

例子:

// B
        function Parent() {
            this.parentProperty = true;
        }

        // B的原型prototype设置
        Parent.prototype.getValue = function() {
            return this.parentProperty;
        };

        // A
        function Child() {
            this.childProperty = false;
        }

        // 继承SuperType,A的原型是B对象(子类的原型prototype是父类的一个实例),A可以访问B的方法
        Child.prototype = new Parent();

        let instance = new Child();
        console.log(instance.getValue()); // true

补充:

原型链条的使用以及使用原型链条操作数组的方法_原型链使用-CSDN博客

标签:function,执行,console,函数,JavaScript,原型,上下文
From: https://blog.csdn.net/m0_65985318/article/details/140293128

相关文章

  • JavaScript基础笔记
    前言在JavaScript诞生的前几年,有人说:JavaScript是一门四不像的语言;JavaScript是一门没有规范的语言;JavaScript是一门兼容糟糕的语言;JavaScript是一门不精准的语言;JavaScript是一个半成品语言;JavaScript是一门糟糕的语言;JavaScript只是一个玩具胶水语言;这些声音从......
  • JavaScript介绍、初识(注释语法、书写位置、书写规范)、常量和变量、数据类型Number、
    【一】JavaScript介绍【1】什么是jsjs也是一门编程语言,他可以写后端代码【2】什么是node.js前端由于非常受制于后端,所以有一些人异想天开想要通过js来编写后端代码一统江湖由此开发了一个叫nodejs的工具(支持js跑在后端服务器上)但是并不能完美的实现【3】JavaScript......
  • 【Javascript】微信小程序项目结构目录详解
    我白天是个搞笑废物表演不在乎夜晚变成忧伤怪物撕扯着孤独我曾经是个感性动物小心地感触现在变成无关人物                     ......
  • 【js面试题】深入理解尾递归及其在JavaScript中的应用
    面试题:举例说明尾递归的理解,以及应用场景引言:在编程中,递归是一种常见的解决问题的方法,它允许函数调用自身来解决问题。然而,递归如果不当使用,可能会导致栈溢出错误,特别是在处理大量数据时。尾递归是一种特殊的递归形式,它能够优化递归调用,避免栈溢出的问题。本文将深入探......
  • JavaScript总结2
    概述JavaScript是世界上最流行的脚本语言。JavaScript是一种轻量级的编程语言,可以插入HTML页面的编程代码。JavaScript插入HTML页面后,可由浏览器执行。特点语法简单,易学易用;解释性语言;跨平台,基于对象和事件驱动,可用于客户端。作用可以动态改变网页内容,网页外观;验证表......
  • 长上下文模型(扩展位置编码、调整上下文窗口、长文本数据、)
    文章目录扩展位置编码调整上下文窗口长文本数据    在实际应用中,大语言模型对于长文本数据的处理需求日益凸显,尤其在长文档分析、多轮对话、故事创作等场景下。在这些情况下,模型需要处理的文本的长度常常超出预定义上下文窗口大小。例如,LLaMA-2的上下文......
  • [javascript]如何优雅的实现网页自动滚动
    在设计一些网站的时候,考虑到用户腾不开手,不想动的情况,就需要设计一个自动滚动的功能,我不提供gui界面的设计,只提供一个丝滑滚动的源码letscrollPercentage=0.02;//这个变量就是一秒滚动这个滚动节点的视窗的百分之几letscrollState=false;//true为正在滚动letscrollE......
  • Javascript中Object、Array、String
    Object在JavaScript中,Object 类型是一种复杂的数据类型,用于存储键值对集合。它提供了多种方法来操作这些键值对,以及执行其他常见的操作。这里,我列出了一些 Object 类型的常见方法或特性,它们在日常编程中非常有用:属性访问点符号(.):如果属性名是一个有效的标识符(例如,没有空格......
  • LLM大模型: RAG的上下文语义聚类retrieval — GraphaRAG
     截至目前,RAG最大的缺陷就是无法回答总结性的问题了。上篇文章(https://www.cnblogs.com/theseventhson/p/18281227)介绍了RAPTOR方法(利用GMM高斯混合模型对chunk聚类,然后再用LLM对每个cluster概括总结摘要)提取cluster的语义,借此来回答概括、总结性的问题,最核心的步骤就是聚......
  • 大学生HTML期末大作业——HTML+CSS+JavaScript学校网站(成都大学)
    HTML+CSS+JS【学校网站】网页设计期末课程大作业web前端开发技术web课程设计网页规划与设计......