this指针/闭包及作用域(进阶)

news2024/12/28 18:03:02

一.作用域链

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/777037.html

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

相关文章

Ae 效果:CC Kaleida

风格化/CC Kaleida Stylize/CC Kaleida 万花筒是一种装置或玩具,通过多次反射和镜像,将图像分割成多个对称和重复的图案。CC Kaleida(CC 万花筒) 效果通过类似的方式在图像上创建镜像和对称的视觉效果。 提示: 由于 CC…

SpringBoot项目中WEB页面放哪里--【JSB系列之008】

SpringBoot系列文章目录 SpringBoot知识范围-学习步骤【JSB系列之000】 文章目录 SpringBoot系列文章目录Resources目录Resources子目录实操一个helloworld!总结作业(难度★✰✰✰✰ )配套资源题外话 本系列环境 环境win11工具idea 2017jdk1.8数据库my…

AD导入封装以及器件(立创)

这里我们以立创商城为例 https://www.szlcsc.com/?cBD&sdclkidA5f6152zxrDiArD6A52&bd_vid12150450211089112893 1)先搜索,然后点击数据手册; ​ 2)出现如下界面,点击立即打开; ​ 3&#xff…

前端学习记录~2023.7.17~CSS杂记 Day9 浮动float 定位position 多列布局 响应式设计

前言一、浮动1、使盒子浮动起来2、清除浮动3、清除浮动元素周围的盒子(1)clearfix 小技巧(2)使用 overflow(3)display: flow-root 二、定位1、定位有哪些2、top、bottom、left 和 right3、定位上下文4、介绍…

宏下开展的#,##

宏下开展的#&#xff0c;## #表示字符串化 ##表示链接符号 #include <stdio.h>#define ABC(x) #x int main() {printf(ABC(abc));return 0; }#include <stdio.h>#define ABC(x) #x #define DAY(x) myday##x int main() {int myday1 10;int myday2 20;printf(AB…

Redis持久化(5)

⭐ 作者简介&#xff1a;码上言 ⭐ 代表教程&#xff1a;Spring Boot vue-element 开发个人博客项目实战教程 ⭐专栏内容&#xff1a;个人博客系统 ⭐我的文档网站&#xff1a;http://xyhwh-nav.cn/ 文章目录 Redis持久化1、持久化流程2、RDB2.1、优点2.2、缺点2.3、快照规…

VMware 安装 Centos7(超详细教程)

文章目录 &#x1f9d1;‍&#x1f393;前言&#x1f943;安装前准备&#x1f349;安装&#x1f91d; 总结 &#x1f9d1;‍&#x1f393;前言 大家好&#xff0c;本篇为本人在学习linux过程中所需要的软件以及安装过程&#xff0c;随手记录一下&#xff0c;写得不是很好&#…

JAVA多线程,为什么并发环境需要用到它?

目录 一、什么是并发环境 二、什么是多线程 三、如何在并发环境使用多线程 一、什么是并发环境 并发环境是指多个任务在同一时间段内同时执行的环境。在计算机领域中&#xff0c;指的是在同一个时间段内有多个线程或进程在执行。在并发环境下&#xff0c;多个任务可以同时进…

win11“你的internet安全设置阻止打开一个或多个文件”问题

“你的internet安全设置阻止打开一个或多个文件”问题解决记录 问题描述&#xff1a;部分程序出现无法下载或者无法打开的情况。 解决方法参考&#xff1a; 1.更改Internet安全设置&#xff08;仅限于由Internet安全设置出现的问题&#xff09;。 打开&#xff1a;控制表面&…

opencv实战--环境配置和文字识别

文章目录 前言一、环境配置二、文字识别2.1 文字单个识别2.2 文字单个带边框 总结 前言 一、环境配置 cmd输入python的时候跳转应用商店的解决方法。https://blog.csdn.net/qq_62294840/article/details/120623501 anaconda官方下载地址&#xff1a;https://www.anaconda.com…

Matplotlib grid()设置网格格式

通过 Matplotlib axes 对象提供的 grid() 方法可以开启或者关闭画布中的网格&#xff08;即是否显示网格&#xff09;以及网格的主/次刻度。除此之外&#xff0c;grid() 函数还可以设置网格的颜色、线型以及线宽等属性。 grid() 的函数使用格式如下&#xff1a; grid(colorb,…

C\C++ 使用exception类,抛出自定义异常并捕获

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan 简介&#xff1a; 抛出异常&#xff0c;并捕获 exception 效果&#xff1a; 代码&#xff1a; #include <iostream> #include <exception> #include <stdexcept&g…

学堂在线数据结构(上)(2023春)邓俊辉 课后题

The reverse number of a sequence is defined as the total number of reversed pairs in the sequence, and the total number of element comparisons performed by the insertion sort in the list of size n is: 一个序列的逆序数定义为该序列中的逆序对总数&#xff0c;…

Lesson3-4:OpenCV图像处理---直方图

直方图 学习目标 掌握图像的直方图计算和显示 了解掩膜的应用 熟悉直方图均衡化&#xff0c;了解自适应均衡化 1 灰度直方图 1.1 原理 直方图是对数据进行统计的一种方法&#xff0c;并且将统计值组织到一系列实现定义好的 bin 当中。其中&#xff0c; bin 为直方图中经常…

【C语言】结构体还不会?这一篇就够了

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前正在回炉重造C语言&#xff08;2023暑假&#xff09; ✈️专栏&#xff1a;【C语言航路】 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你…

pytorch深度学习 线性回归

import torch import matplotlib.pyplot as pltx_data torch.tensor([[1.0], [2.0], [3.0]]) # x_data是一个张量 y_data torch.tensor([[2.0], [4.0], [6.0]]) # y_data是一个张量# 定义一个线性回归模型 class LinearModel(torch.nn.Module): # 继承torch.nn.Moduledef …

SpringBoot项目中MVC使用--【JSB系列之010】

SpringBoot系列文章目录 SpringBoot知识范围-学习步骤【JSB系列之000】 文章目录 SpringBoot系列文章目录Http协议是马冬梅Cookie机制Session机制Token MVC模型本章的专注内容UserController代码 ThymeleafLets GO!总结作业配套资源题外话 Http协议是马冬梅 HTTP简介 1. HTTP…

软件测试如何实现月薪2万?

其实我一直在强调&#xff0c;钱的多少和技能是息息相关的&#xff0c;所以你要赚更多钱&#xff0c;就得付出更多努力&#xff0c;去不断提升自己的技能和见识。 因为最近在群里有一些同学&#xff0c;之前没做过自动化测试&#xff0c;但是限于领导要求&#xff0c;或者自己…

剑指offer21.调整数组顺序使得奇数位于偶数前面 57.和为s的两个数字 58.反转单词顺序

暴力二次遍历&#xff08;时间复杂度空间复杂度都是n&#xff09; class Solution { public:vector<int> exchange(vector<int>& nums) {vector<int> result(nums.size());int left0;for(int i0;i<nums.size();i){if(nums[i]%21) result[left]nums[i…

深拷贝浅拷贝有什么区别?怎么实现深拷贝?

目录 一、浅拷贝二、深拷贝三、两者区别&#xff1f; 一、浅拷贝 浅拷贝&#xff0c;指的是创建新的数据&#xff0c;这个数据有着原始数据属性值的一份精确拷贝。 如果属性是基本类型&#xff0c;拷贝的就是基本类型的值。如果属性是引用类型&#xff0c;拷贝的就是内存地址 …