this指针/闭包及作用域

news2024/11/20 4:18:19

一.作用域链

1.通过一个例子

        let a='global'
        console.log(a);//'global'

        function course(){
            let b='js'
            console.log(b);//'js'
            session()
            function session(){
                let c=this
                console.log(c);//Window
                teacher()//函数提升
                function teacher(){
                    let d='steven'
                    console.log(d);//'steven'

                    console.log('test1',b);//'js'
                }
            }
        }
        course()

2.改造一下这个例子

        let a='global'
        console.log(a);//'global'

        function course(){
            let b='js'
            console.log(b);//'js'
            session()
            teacher()//报错
            function session(){
                let c=this
                console.log(c);//Window
                // teacher()
                //函数提升--在作用域内提升(超出了当前作用域,所以报错)
                function teacher(){
                    let d='steven'
                    console.log(d);

                    console.log('test1',b);
                }
            }
        }
        course()

3.继续改造这个例子(let 和var能否提升变量)

        let a='global'
        console.log(a);//'global'

        function course(){
            let b='js'
            console.log(b);//'js'
            session()
            function session(){
                let c=this
                console.log(c);//Window
                teacher()
                //2.函数提升-作用域之内
                function teacher(){
                    //2.1 let不支持提升
                    //2.2 变量通过var支持提升,变量的声明可以提升
                    //相当于执行了这样一个操作: var e=underfined(提升)
                    console.log('e',e);//undefined
                    let d='steven'
                    console.log(d);
                    //e='tom'
                    var e='tom'
                    console.log('test1',b);//'js' //3.作用域向上查找,向下传递
                }
            }
        }
        course()

 4.提升优先级

        //提升优先级
        console.log('yunyin',yunyin);
        function yunyin(){
            this.course='js'
        }
        yunyin='course'
        //变量优先,函数需要变量,所以变量最终会覆盖函数

        //块级作用域
        if(true){
         let e=11
         var f=222
        }
        console.log(f);
     // console.log(e);
       //1.对于作用域链我们可以直接通过创建态来定位作用域链 --静态创建
       //2.手动取消全局

5.函数提升-作用域之内

        let a='global'
        console.log(a);//'global'

        function course(){
            let b='js'
            console.log(b);//'js'
            session()
            function session(){
                let c=this
                console.log(c);//Window
                teacher()
                //函数提升-作用域之内
                function teacher(){
                    console.log(d);//报错
                    let d='steven'
                    console.log(d);

                    console.log('test1',b);
                }
            }
        }
        course()

 

6.this/上下文context

例子:我家门有条河,门前的河上有座桥,门前的河里有群鸭.

我家门前有条河,这河上有座桥,这河里有群鸭.

这指的就是我家门前那条河,也就是上下文context.

结论:this是在执行时动态读取上下文决定的,而不是创建时.

7.考察重点--各使用态的指针指向

(1)函数直接调用中,this指向的是window

==>全局上执行的环境=>函数表达式/匿名函数/嵌套函数

为什么呢?因为它是通过调用它的调用方的执行环境来决定的.

function foo(){
console.log(this)
}
foo() //window.foo()

(2)隐式绑定--this指带的是调用堆栈的上一级=>对象/数组等引用关系逻辑

        function fn(){
            console.log('隐式绑定',this.a);//1
        }
        let obj={
            a:1,
            fn
        }
        obj.fn=fn
        obj.fn()

面试题:

       const foo={
            bar:10,
            fn:function(){
                console.log(this.bar);//undefined
                console.log(this);//Window
            }
        }
        //取出
        let fn1=foo.fn
        //独立执行
        fn1()

追问1:如何改变this指向?

       const o1={
            text:'o1',
            fn:function(){
                //直接使用上下文--传统派活
                console.log('o1fn',this);
                return this.text
            }
        }

        const o2={
            text:'o2',
            fn:function(){
                //呼叫领导执行,部门协作
                return o1.fn()//o1的执行态
            }
        }

        const o3={
            text:'o3',
            fn:function(){
                //直接内部构造,公共人
                let fn=o1.fn
                return fn()//挂载在全局公共的一个方法
            }
        }
        console.log('o1fn',o1.fn());
        console.log('o2fn',o2.fn());
        console.log('o3fn',o3.fn());

追问2:现在我要将concole.log('o2fn',o2,fn())的结果是o2.

(1)人为干涉,改变this--bind/apply/call

o2.fn().call(o2)

(2)不需人为改变

 const o1={
            text:'o1',
            fn:function(){
                //直接使用上下文--传统派活
                console.log('o1fn',this);
                return this.text
            }
        }

        const o2={
            text:'o2',
            fn:o1.fn
        }
 console.log('o2fn',o2.fn());

(3)显式绑定(bind | apply | call)

        function foo() {
            console.log('函数内部', this);
        }
        foo()
        foo.call({
            a: 1
        })
        foo.apply({
            a: 1
        })
        const bindFoo = foo.bind({
            a: 1
        })
        bindFoo()

 

面试题:call/apply/bind的区别

1.call vs apply 传参不同 依次传入/数组传入

2.bind直接返回不同,需要再调用一次

###bind的原理/手写一个bind

        //1.需求:手写bind=>bind挂载位置(挂载在哪里)=>Function.prototype
        Function.prototype.newBind = function () {
            //2.bind是什么?
            //改变this
            const _this = this
            //接收参数args,第一项参数是新的this,第二项到最后一项是函数传参
            const args = Array.prototype.slice.call(arguments)
            console.log('args', args);
            const newThis = args.shift()
            console.log('newThis', newThis);
            //3.返回值
            return function () {
                return _this.newApply(newThis, args)
            }
        }

        Function.prototype.newApply = function (context) {
            context = context || window
            //挂载执行函数
            context.fn=this
            let result=arguments[1]
            ? context.fn(...arguments)
            :context.fn()
            delete context.fn
            return result

        }

###闭包:一个函数和它周围状态的引用捆绑在一起的组合

1.函数作为返回值的场景

    //函数作为返回值的场景
    function mail(){
        let content='信'
        return function(){
            console.log(content);//信
        }
    }
    const envelop=mail()
    envelop()

2.函数作为参数的时候

        let content=0
        function envelop(fn) {
            content = 1
            fn()
        }
        
        function mail(){
            console.log(content);//1
        }
        envelop(mail)//把mail函数嵌入到了envelop函数中

3.函数的嵌套

        let counter = 0
        function outerFn() {
            function innerFn() {
                counter++
                console.log(counter);//1
            }
            return innerFn
        }
        outerFn()()

延伸:1.立即执行函数=>js模块化的基石

        let count=0
        (function immediate(args){
            if(count===0){
                let count=1
                console.log(count);
            }
        })(args) 

2.实现私有变量

       function createStack() {
            return {
                items: [],
                push(item) {
                    this.item.push(item)
                }
            }
        }

        const stack={
             items:[],
             push:function(){}
        }

        function createStack(){
            const items=[]
            return {
                push(item){
                    items.push(item)
                }
            }
        }

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

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

相关文章

【unity之IMGUI实践】单例模式管理数据存储【二】

👨‍💻个人主页:元宇宙-秩沅 👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍💻 本文由 秩沅 原创 👨‍💻 收录于专栏:uni…

FocusState, SubmitTextField 的使用

1. FocusState 输入文本添加焦点状态 1.1 实现 /// 输入文本焦点状态 struct FocusStateBootcamp: View {// 使用枚举enum OnboardingFields: Hashable{case usernamecase password}//FocusState private var usernameInFocus: BoolState private var username: String "…

两分钟python发个邮件

python简单发个邮件 直接上代码测试 之前spring boot简单发送发送个邮件大约5min,ennn这个python发个邮件两三分钟吧 直接上代码 import smtplib from email.mime.multipart import MIMEMultipart from email.mime.text import MIMETextclass MailTest(object):def…

Flink 在新能源场站运维的应用

摘要:本文整理自中南电力设计院工程师、注册测绘师姚远,在 Flink Forward Asia 2022 行业案例专场的分享。本篇内容主要分为四个部分: 1. 建设背景 2. 技术架构 3. 应用落地 4. 后续及其他 Tips:点击「阅读原文」免费领取 5000CU*…

Vue localhost 从 http 307 到 https

Vue localhost 从 http 307 到 https HTTP 307 与 HSTS HTTP 307中间人攻击HSTS - HTTP Strict Transport Security 如何解决问题 Vue localhost 从 http 307 到 https 一个 Vue2 项目之前本地都是通过 HTTP 的 localhost 访问(如下) 后来突然无法访问了, 提示的错误内容是 E…

静电接地桩的设计和施工

静电接地桩是用于将静电荷引导到地下的装置,以确保工作环境。以下是一般静电接地桩设计的一些建议和步骤: 1. 选择合适的位置:静电接地桩应该位于静电产生源附近,并接近地面。可以选择在室内或室外,但要确保容易维护和…

web中引入live2d的moc3模型

文章目录 前言下载官方sdk文件使用ide编译项目(vsCode)项目初始化使用vsCode项目树介绍使用live server运行index页面 演示导入自己的模型并显示modelDir文件resources文件夾案例模型修改modelDir然後重新打包項目運行 前言 先跟着官方sdk调试一遍&…

14.live555mediaserver-play请求与响应

live555工程代码路径 live555工程在我的gitee下(doc下有思维导图、drawio图): live555 https://gitee.com/lure_ai/live555/tree/master 章节目录链接 0.前言——章节目录链接与为何要写这个? https://blog.csdn.net/yhb1206/art…

基于C/S架构工作原理序号工作步骤和理论的区别

基于C/S架构工作原理序号工作步骤和理论的区别 SSH 概念 对称加密linux 系统加密,就是加密和揭秘都是使用同一套密钥。 非对称加密有两个密钥:“私钥”和“公钥”。私钥加密后的密文,只能通过对应的公钥进行揭秘。而通过私钥推理出公钥的…

深入解析浏览器Cookie(图文码教学)

深入解析浏览器Cookie 前言一、什么是 Cookie?二、Cookie的特点二、如何创建 Cookie?三、服务器如何获取 Cookie四、Cookie 值的修改4.1 方案一4.2 方案二 五、浏览器查看 Cookie六、Cookie 生命控制七、Cookie 有效路径 Path 的设置八、案例:Cookie 练…

183_Power BI 折线图之平滑线性类型

183_Power BI 折线图之平滑线性类型 一、背景 曾几何时,为了在 Power BI 让折线图显示出平滑曲线,各路大佬是尽显神通。如今时间来到 2023 年 7 月,刚刚更新的 Power BI 已经支持折线图的平滑曲线。让我们来看看最终效果。 同时&#xff0c…

【SpringBoot3】--04.核心原理

文章目录 SpringBoot3-核心原理1.事件和监听器1.1生命周期监听1.1.1 监听器-SpringApplicationRunListener1.1.2生命周期全过程 1.2事件触发时机1.2.1各种回调监听器1.2.2完整触发流程 1.3SpringBoot事件驱动开发 2.自动配置原理2.1入门理解2.1.1自动配置流程2.1.2SPI机制2.1.3…

apache ranger

简介: ranger 是一个用于启用、监控和管理跨hadoop平台的全面的数据安全框架。 ranger的愿景是在hadoop系统中提供全面的安全管理。随着yarn的出现,hadoop 平台能够支持真正的数据糊架构。企业能够在多租户环境中运行多个任务负载。hadoop 数据安全需要…

面向对象编程/原型及原型链

一.面向对象 (1)对象是什么?为什么要面向对象? 通过对代码的抽象,进而描述单个种类物体的方式. (2)特点:面向对象-逻辑上迁移更加灵活,代码的复用性更高,高度的模块化. (3)对象的理解 1.对象是对于单个物体的简单抽象; 2.对象是容器,封装了属性和方法 **属性:对象状态…

Python官方文档中Availability: not Emscripten, not WASI是什么意思?

在我们阅读Python官方文档中,当某个模块或特性的文档中写着 "Availability: not Emscripten, not WASI" 时,它表示该模块或特性在 Emscripten 和 WASI 环境中不可用。 Emscripten 是一个工具链,用于将C和C代码编译为WebAssembly&am…

【Python从入门到进阶】28、xpath的安装以及使用

接上篇《27、Handler处理器使用及代理和Cookie登录实现》 上一篇我们讲解了urllib中Handler处理器的基本使用,以及实现代理访问和Cookie的登录。本篇我们来讲解HTML文档解析中的核心插件xpath的安装及使用。 一、xpath介绍 XPath是由W3C(World Wide We…

kotlin中使用Room数据库(包含升降级崩溃处理)

目录 1.导入依赖库 2.数据实体类 3.数据访问对象 (DAO) 4.数据库类 5.调用DAO里面的“增、删、改、查”方法 6.数据库升降级处理 升级(保存数据库历史数据): 升级(不保存数据库历史数据): 降级&…

剑指 offer 数学算法题:数值的整数次方

题目描述: 实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,xn)。不得使用库函数,同时不需要考虑大数问题。 分析: 直接计算法,通过判断 n 的正负,若为负数, x 即…

无法加载文件\venv\Scripts\Activate.ps1,因为在此系统上禁止运行脚本

一、问题发生 运行环境Windows 10、python 3.11.1、IDE VScode 当然你可能使用了其他IDE,例如pycharm等,不过没有关系解决问题的方法都是一致的。 报错信息如下图所示: actvivate.ps1这个脚本文件是用来激活python虚拟环境的。 其实&…

LabVIEW开发图像采集和图像处理程序

LabVIEW开发图像采集和图像处理程序 扫描电子显微镜(SEM)是一种功能强大的工具,广泛用于高分辨率的生物和半导体样品检测。然而,对于大面积或3D成像,SEM成像是一个耗时的过程。MBSEM旨在通过同时扫描多个像素来减少采…