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

news2024/12/27 13:00:36

目录

一、执行上下文

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博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1912787.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

20_Inception V3深度学习图像分类算法

回顾GoogleNet:传送门 1.1 介绍 InceptionV3是Google开发的一种深度卷积神经网络架构&#xff0c;它是Inception系列网络中的第三代模型&#xff0c;由Christian Szegedy等人在论文《Rethinking the Inception Architecture for Computer Vision》中提出&#xff0c;该论文发…

【计算机网络仿真】b站湖科大教书匠思科Packet Tracer——实验17 开放最短路径优先OSPF

一、实验目的 1.验证OSPF协议的作用&#xff1b; 二、实验要求 1.使用Cisco Packet Tracer仿真平台&#xff1b; 2.观看B站湖科大教书匠仿真实验视频&#xff0c;完成对应实验。 三、实验内容 1.构建网络拓扑&#xff1b; 2.验证OSPF协议的作用。 四、实验步骤 1.构建网…

文件操作和IO流

前言&#x1f440;~ 上一章我们介绍了多线程进阶的相关内容&#xff0c;今天来介绍使用java代码对文件的一些操作 文件&#xff08;file&#xff09; 文件路径&#xff08;Path&#xff09; 文件类型 文件操作 文件系统操作&#xff08;File类&#xff09; 文件内容的读…

C语言-预处理详解

文章目录 &#x1f3af;引言&#x1f453;预处理详解1.预定义符号1.1 __FILE__1.2 __LINE__1.3 __DATE__1.4 __TIME__1.5 __STDC__ 2.#define定义常量2.1 定义数值常量2.2 定义字符串常量 3.#define中使用参数3.1**使用示例**3.2注意事项 4.宏替换的规则5.宏函数和函数的对比5.…

基于Netty的自研流系统缓存实现挑战: 内存碎片与OOM困境

01 前言 Kafka 作为流处理平台&#xff0c;在实时流计算和在线业务场景&#xff0c;追尾读追求端到端低延迟。在离线批处理和削峰填谷场景&#xff0c;数据冷读追求高吞吐。两个场景都需要很好的数据缓存设计来支撑&#xff0c;Apache Kafka 的数据存储在本地文件&#xff0c…

从零开始学习嵌入式----C语言框架梳理与后期规划

目录 一、环境搭建. 二、见解 三、C语言框架梳理 四、嵌入式学习规划流程图&#xff08;学习顺序可能有变&#xff09; 一、环境搭建. C语言是一门编程语言&#xff0c;在学习的时候要准备好环境。我个人比较喜欢用VS,具体怎么安装请百度。学习C语言的时候&#xff0c;切忌…

Qt:12.输入类控件(QSpinBox-整数值输入的小部件、QDateEdit、QTimeEdit、QDateTimeEdit- 日期和时间输入的控件)

目录 一、QSpinBox-整数值输入的小部件&#xff1a; 1.1QSpinBox介绍&#xff1a; 1.2属性介绍&#xff1a; 1.3通用属性介绍&#xff1a; 1.4信号介绍&#xff1a; 二、QDateEdit、QTimeEdit、QDateTimeEdit- 日期和时间输入的控件&#xff1a; 2.1QDateEdit、QTimeEdit…

一、YOLO V10安装、使用、训练大全

YOLO V10安装、使用、训练大全 一、下载官方源码二、配置conda环境三、安装YOLOV10依赖四、使用官方YOLO V10模型1.下载模型2.使用模型2.1 图片案例 五、制作数据集1.数据集目录结构2.标注工具2.1 安装标注工具2.2 运行标注工具2.3 设置自动保存2.4 切换yolo模式2.5 开始标注2.…

【C++ | 继承】C++的继承详解 及 例子源码演示

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a; 本文未经允许…

C++视觉开发 七.模板匹配

模板匹配是一种基于图像处理的技术&#xff0c;用于在目标图像中寻找与给定模板图像最相似的部分。通过设定的模板&#xff0c;将目标图像与模板图像比较&#xff0c;计算其相似度&#xff0c;实现对目标图像的判断。 目录 一.手写数字识别 重要函数&#xff1a; 1.cv::glob…

Mac平台虚拟机 Parallels Desktop v19.4.1,支持M1/M2/M3芯片组

Parallels Desktop for Mac是功能强大灵活度高的虚拟化方案&#xff0c;无需重启即可在同一台电脑上随时访问Windows和Mac两个系统上的众多应用程序。从仅限于PC的游戏到生产力软件&#xff0c;Parallels Desktop都能帮您实现便捷使用。Parallels Desktop 是一款专业的Mac虚拟机…

虚拟机因断电进入./#状态解决办法

现象&#xff1a; 解决&#xff1a;先查看错误日志&#xff1a;journalctl -p err -b查看自己虚拟机中标黄部分的名字 之后运行&#xff1a;xfs_repair -v -L /dev/sda #这里sda用你自己标黄的 最后重启 reboot 即可。

ArcGIS的智慧与情怀

初识ArcGIS 在这个信息化的时代&#xff0c;ArcGIS如同一位智者&#xff0c;静静地伫立在地理信息系统的巅峰。初识它时&#xff0c;我仿佛走进了一片未知的领域&#xff0c;心中充满了好奇与期待。ArcGIS&#xff0c;这款专业的地理信息系统软件&#xff0c;凭借其强大的功能…

【k8s中安装rabbitmq】k8s中安装rabbitmq并搭建镜像集群-hostpath版

文章目录 简介一.条件及环境说明二.需求说明三.实现原理及说明四.详细步骤4.1.规划节点标签4.2.创建configmap配置4.3.创建三个statefulset和service headless配置4.4.创建service配置 五.安装完后的配置六.安装说明 简介 k8s集群中搭建rabbitmq集群服务一般都会用到pvc&#x…

传知代码-图神经网络长对话理解(论文复现)

代码以及视频讲解 本文所涉及所有资源均在传知代码平台可获取 概述 情感识别是人类对话理解的关键任务。随着多模态数据的概念&#xff0c;如语言、声音和面部表情&#xff0c;任务变得更加具有挑战性。作为典型解决方案&#xff0c;利用全局和局部上下文信息来预测对话中每…

2024世界人工智能大会:AI产品技术与未来趋势的深度解析

随着2024年世界人工智能大会&#xff08;WAIC 2024&#xff09;在上海的圆满落幕&#xff0c;我们见证了人工智能技术的又一次飞跃。本次大会以“以共商促共享&#xff0c;以善治促善智”为主题&#xff0c;汇聚了全球顶尖的智慧&#xff0c;共同探讨了AI技术的未来趋势和应用前…

妙笔生词智能写歌词软件:创新助力还是艺术之殇?

在音乐创作日益普及和多样化的当下&#xff0c;各种辅助工具层出不穷&#xff0c;妙笔生词智能写歌词软件便是其中之一。那么&#xff0c;它到底表现如何呢&#xff1f; 妙笔生词智能写歌词软件&#xff08;veve522&#xff09;的突出优点在于其便捷性和高效性。对于那些灵感稍…

JVM内存泄露的ThreadLocal详解

目录 一、为什么要有ThreadLocal 二、ThreadLocal的使用 三、实现解析 实现分析 具体实现 Hash冲突的解决 开放定址法 链地址法 再哈希法 建立公共溢出区 四、引发的内存泄漏分析 内存泄漏的现象 分析 总结 错误使用ThreadLocal导致线程不安全 一、为什么要有Thr…

Test-Time Adaptation via Conjugate Pseudo-labels--论文笔记

论文笔记 资料 1.代码地址 https://github.com/locuslab/tta_conjugate 2.论文地址 https://arxiv.org/abs/2207.09640 3.数据集地址 论文摘要的翻译 测试时间适应(TTA)指的是使神经网络适应分布变化&#xff0c;在测试时间仅访问来自新领域的未标记测试样本。以前的TT…

【pytorch24】Visdom可视化

TensorboardX pytorch有一个工具借鉴了tensorboard pip install tensorboardX 有查看变量的数值、监听曲线等功能 如何使用 新建SummaryWriter()实例 要把监听的数据&#xff0c;比如说要监听dummy_s1[0]&#xff08;y 坐标&#xff09;存放到data/scalar1中&#xff0c;…