从上下文,到作用域(彩蛋:理解闭包)

ROS学习 一、Debian10安装ROS Noetic,解决rosdep update失败问题(更新一个可修改位置) 目录前言ROS安装1.添加ROS的apt源和key(中科大源)2.apt安装ros-noetic核心组件3.配置ROS的bash环境4.安装其他常用ROS依赖项5.解决python3-rosdep安装中出现的rosdep update error问题尝试1.改hosts尝试2.改resolv.conf尝试3.改timeout最终的解决方法:结语 前言 装了挺多次ROS,每次安装都会卡在rosdep update这一步上,总要靠运气装好。最近发现一种很棒的ROS仓库连接不上的解决方案,因此重新记录一下在Deb 阅读详情

前言


近几天在编程群中的聊天,让我发现了很多人并不清楚什么是上下文(context)、什么是作用域(scope),而且纠结在其中。我当初对这两个概念也只有粗浅的理解,不过我从一开始就不怎么困惑,因为我清楚自己对这一问题的认识边界。现在,我对它们的认识也只加深了一点点。不过,群聊中小伙伴的热情鼓舞了我——很多最最初学的小伙伴,想到和思考的是很多我从没考虑过的问题,小伙伴们真是达到了“进一寸有一寸的欢喜”这一境界。见贤思齐,我决定把这一点点进步记录下来。


上下文与作用域的关系


很多人弄不清除,原因当然是既不了解上下文,也不了解作用域——我是说,几乎没有人明白上下文是什么而不明白作用域是什么,反之亦然。上下文(context)和作用域(scope)都是编译原理的知识,具体编程语言有具体的实现规则,本文关注 JavaScript 语言的实现。首先需要关注的是,这两个概念的关系非常密切,所以先了解它们的关系,有助于理解它们到底是什么。


上下文(context)和作用域(scope)的关系:


上下文是一段程序运行所需要的最小数据集合;作用域是当前上下文中,按照具体规则能够访问到的标识符(变量)的范围。


后文是对上下文和作用域更详细的解释,知道了上面指出的关系,往下阅读时就可以加深对这一关系的理解了。


上下文


上下文(context)是一段程序运行所需要的最小数据集合。我们可以从上下文交换(context switch)来理解上下文,在多进程或多线程环境中,任务切换时首先要中断当前的任务,将计算资源交给下一个任务。因为稍后还要恢复之前的任务,所以中断的时候要保存现场,即当前任务的上下文,也可以叫做环境。即上下文就是恢复现场所需的最小数据集合。容易把人弄晕的一点是,我们这里说的上下文、环境有时候也称作作用域(scope),即这两个概念有时候是混用的。不过,它们有不同的侧重点,下一节将会说明。


另外,JavaScript 中常见的情形是一个方法/函数的执行。从一段程序的角度看,这段程序运行所需的所有变量,就是它的上下文。


作用域


作用域(scope)是标识符(变量)在程序中的可见性范围。作用域规则是按照具体规则维护标识符的可见性,以确定当前执行的代码对这些标识符的访问权限。作用域(scope)是在具体的作用域规则之下确定的。


前面说过,有时候上下文、环境、作用域是同义词;不过,上下文(context)指代的是整体环境,作用域关注的是标识符(变量)的可访问性(可见性)。上下文确定了,根据具体编程语言的作用域规则,作用域也就确定了。这就是上下文与作用域的关系。


写 JavaScript 代码时,如果 Function 作为参数,可以指定它在具体对象上调用时,这个对象常常叫做 context:


function callWithContext(fn, context) {

  return fn.call(context);

}

 

const apple = {

  name: "Apple"

};

 

const orange = {

  name: "Orange"

};

 

function echo() {

  console.log(this.name);

}

 

callWithContext(echo, apple);  // Apple

callWithContext(echo, orange); // Orange


为什么将这个参数叫做 context?因为它关系到调用环境,指定了它,就指定了函数的调用上下文。再加上具体的作用域规则,作用域也确定了。


在 JavaScript 中,这个具体的作用域规则就是词法作用域(lexical scope),也就是 JavaScript 中的作用域链的规则。词法作用域是的变量在编译时(词法阶段)就是确定的,所以词法作用域又叫静态作用域(static scope),与之相对的是动态作用域(dynamic scope)。


You Don’t Know JS: Scope & Closures 用简单例子解释过动态作用域,下面用一个类似的例子说明一下:


function foo() {

  console.log(a);

}

 

function bar() {

  let a = 3;

  foo();

}

 

let a = 2;

 

bar(); // 2


有一定 JavaScript 编程经验的人都能看出,这段程序会输出 2,但如果在动态作用域的规则下,应该输出 3,即 a 的引用不再是编译时确定,而是调用时确定的。这有点像 JavaScript 中的 this,所以 MDN 中,function.bind 的方法签名中第一个形参名称用的是 thisArg 这一更科学的名字:


fun.bind(thisArg[, arg1[, arg2[, …]]])


同样情况的还可见于 Lodash 的文档:


_.bind(func, thisArg, [partials])


彩蛋:理解闭包


上一节中的代码中,之所以输出 2,是因为 foo 是一个闭包函数。如果从本文中理解了上下文和作用域的概念,对于闭包是什么这一问题是不是感到豁然开朗?


前面说过,词法作用域也叫静态作用域,变量在词法阶段确定,也就是定义时确定。虽然在 bar 内调用,但由于 foo 是闭包函数,即使它在自己定义的词法作用域以外的地方执行,它也一直保持着自己的作用域。所谓闭包函数,即这个函数封闭了它自己的定义时的环境,形成了一个闭包,所以 foo 并不会从 bar 中寻找变量,这就是静态作用域的特点。


一个更加典型的例子是:


function fn() {

  let a = 0;

  function func() {

    console.log(a);

  }

  return func;

}

 

let a = 1;

let sub = fn();

 

sub(); // 0;


sub 就是 func 这一返回值,func 定义在 fn 内部并且被传递出来了,所以 fn 执行之后垃圾回收器依然没有回收它的内部作用域,因为 func/sub 在使用。sub 依然持有 func 定义时的作用域的引用,而这个引用就叫作闭包。调用 sub 时,它可以访问 func 定义时的词法作用域,因此找到的 a 是 fn 内部的变量 a,它的值是 0。


参考资料


  • You Don’t Know JS: Scope & Closures

  • Context (computing)

  • Scope (computer science)

  • Function.prototype.bind()

  • Function _.bind()

记录一个因spark不是纯净版导致hive跑spark的insert,update语句报类找不到的问题 其实就是我spark的包弄错了,应该是用纯净版的spark包。因为我是yarn跑的,所以去yarn看报错日志。它说是这个类找不到? 阅读详情

相关推荐

Android设置多个定时器时只有最后一个有效的问题解决

先看这段API: 我们会用到PendingIntent 来获取一个实例它有四个参数: PendingIntent  pi = PendingIntent.getBroadcast(context, requestCode, intent, flags) content 和 intent 比较熟悉,不必多说 主要是flag,它有以下参数: FLAG_CANCEL_CURRE

期待 1804

你知道的requestAnimationFrame【从0到0.1】

随着技术与设备的发展,用户的终端对动画的表现能力越来越强,更多的场景开始大量使用动画。在 Web 应用中,实现动画效果的方法比较多,JavaScript 中可以通过定时器 setTimeout 来实现,css3 可以使用 transition 和animation 来实现,html5 中的 canvas 也可以实现。除此之外,html5 还提供一个专门用于请求动画的 API,即 requestAn...

weixin_33694620的博客 318

Mycat select for update 未锁定记录解决方案

1、升级Mycat 到新的版本,见地址:1.4-1.6 select for update 未锁定链接 · Issue #1261 · MyCATApache/Mycat-Server · GitHub 2、开启事务后,将select for update 操作跟在别的不相关的增删改操作之后即可,如图, 事务一:开启事务,执行 update、select 后先不提交,然后执行事务二 事务二:开启事务,执行select 操作,此时事务被挂起,说明事务一的se...

poor_charlie的博客 690

ROS- 解决 rosdep update 出现的错误

安装ROS时,反复出现下面的错误, 1.执行sudo rosdep init 出现错误 sudo rosdep init 错误如下: ERROR: cannot download default sources list from: https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/sources.list.d/20-de...

ゃ﹏淸凨ゞ 2万+

hive 模拟update 操作

在使用hive构建数据仓库的时候,经常会遇到从mysql或者oracle数据导入到hive中。 一般情况下,每天导一次数据,有些数据需要更新操作,最典型的例子就是订单数据,比如: 订单创建时间 订单导入hive时间 订单更新时间 2015-07-01 12:09:11 2015-07-02 00:30:00 2015-07-02 20:07:12

baiyangfu的专栏 5364

Ubuntu每次登录都提示有新的更新,apt更新却0个软件需要升级:清空MOTD消息 安装update-notifier-common组件 运行强制更新脚本

Ubuntu每次登录都提示有新的更新,apt更新却0个软件需要升级:清空MOTD消息 安装update-notifier-common组件 运行强制更新脚本​ 每登录ubuntu,都会显示有更新需要注意。 80更新可以立即应用。 这些更新中有 1 个是标准安全更新。 要查看这些附加更新,请运行:apt list --upgradable 然而使用更新命令却提示0可更新查询了一下,这似乎是MOTD的错误,并非apt更新源的问题安装update-notifier-common组件,运行强制更新脚本 ​

低温热源的博客 1139

解决ubuntu上apt-get update失败的问题

写作原因 这两天一直被apt-get update报错(404 not found)所困扰,因为我在安装pycharm的时候,需要有JAVA JDK环境。而最常用的解决方法是1: 1:多数博客介绍解决pycharm安装问题,都会建议下载oracle jdk来解决"jdk not found"的问题,然而这个方案完全不可行,会提示“no valid license found" 2、apt-get ...

RAFA_CHANG的博客 5176

真正解决Jenkins安装插件总是报错的问题(二)

一、前言 上次在安装Jenkins时遇到插件下载不下来的问题,就算换成镜像也不行,因为镜像的update-center.json 文件里面的下载地址还是官方的地址,详细请点这里看上篇文章的解决方法。 二、再次发现问题 最近再次使用的时候发现下载插件又不行了,发现上次替换的update-center.json文件不见了。于是乎再次下载下来替换地址,然后替换掉原来的文件,重启后发现又没了。...

KID5945的博客 5659

高并发业务代码中一个事务中同时使用select和update的场景深度剖析

1.秒杀代码(最low实现): //开启事务 @Transactional(rollbackFor = Exception.class) public BaseResponse<?> startSeckillWithLock(Long id, Long userId) { try { return seckill(id, userId); } catch (Exception e) { throw

GAVIN12365的博客 3306

关于android桌面小组件分开更新的的一些问题

重点讨论:继承同一个AppWidgetProvider的组件,如何不让他们同步更新,实现分开更新  AppWidgetProvider 的onupdate中: public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { //再widget被创建时调用

F_L_C的Android开发经验 1307

C#连接Access数据库,Update更新数据时出现“不能打开数据库,应用程序可能无法识别该数据库。。。”错误

在使用C#的oledb连接Access数据库时,使用事务来对数据库进行数据增加和修改,前面的insert语句都可以正常执行,而到Update更新表格数据时,程序出现了“不能打开数据库,应用程序可能无法识别该数据库。。。”的错误。 由于之前使用update更新数据库数据时没有出现这个错误,所以从以下几个方面对程序和数据库进行了检查: 1.检查update语句是否出现了错误,通过调试将update

xinbadar的博客 9245

【StarRocks系列】Update语句

解析 -> 定位主键 -> 分发 -> (BE)读原始数据 -> 改内存数据 -> 排序去重 -> 写新文件 -> 提交元数据 -> 异步回收旧文件。基于主键批量处理,读-改-写模式,写时复制(创建新文件),利用主键索引和排序去重保证效率与主键唯一性。单条 UPDATE 语句具有原子性和持久性,通过 MVCC 提供快照隔离级别的读一致性。社区版不支持多语句事务,企业版提供有限的多语句事务支持。

技术改变世界 1824

[已解决]如何修复另一个更新正在进行中WordPress升级错误

如何修复另一个更新正在进行中WordPress升级错误   在使用WordPress建站时,是否遇到过 WordPress 网站当前正在进行另一个更新的错误?此错误会阻止您更新 WordPress 版本,没有正在进行的核心、主题或插件的更新,重新启动更新过程也会导致出现相同的通知,显然是有某种 WordPress 更新锁阻止更新初始化。在本文中,我们晓得博客将向您展示如何修复另一个更新正在进行中WordPress升级错误。   错误提示如下: 中文:另一个更新正在进行 ...

晓得博客 599

瞬间解决sudo rosdep init 和 rosdep update网络问题(最新)

作为一个ROS小白,ROS已经安装过n多次了,就不去细数具体有多少次了(包括把系统搞崩的几次)。 每一次安装ROS都会发现经典rosdep两个问题。 每一次解决问题都翻遍了许多rosdep解决办法。然而每回都会花大量的时间查找各种都不好用。 在试过无数次rosdep以后,很有可能也没什么办法。不过参考了2021最新解决办法 (姑且这么简称)之后恍然大悟。 关于rosdep init 大家想必已经驾轻就熟,就是下载一个文件到/etc/ros/rosdep/sources.list.d下,名字叫做20-

kodori的博客 3237

【MySQL】ON DUPLICATE KEY UPDATE 解决重复插入问题

ON DUPLICATE KEY UPDATE 开发过程中,可能会遇到这样的需求,先判断某一记录是否存在,如果不存在,添加记录,如果存在,则修改数据。在INSERT语句末尾指定ON DUPLICATE KEY UPDATE可以解决这类问题。 其用法如下:如果在INSERT语句末尾指定了ON DUPLICATE KEY UPDATE,并且插入行后会导致在一个UNIQUE索引或PRIMARY KEY中...

寒泉 3万+

OpenSIPS 通话中 UPDATE 请求导致没有声音问题

使用硬话机时,在 SDP 协商完成 SIP 会话已经建立的情况下,使用 FreeSWITCH 的 bridge 命令接通坐席和用户时 FreeSWITCH 发出了一个 UPDATE 请求给到 OpenSIPS。问题的切入点显而易见,硬话机的行为肯定和软电话存在不一致,从而导致问题的发生。在 SIP 应用的开发中,通话一端听不到声音是比较常见的问题。一般来说,没有声音意味着 RTP 传输存在障碍,至此问题原因已经清晰,一个简单快速的解决方案是。追根究底就是网络不通或者端口未开放等原因。,经修改后问题不复现。

谈谈1974 1776

Oracle执行update时卡死问题的解决方法

问题: 在执行delete或for update语句时,PLSQL一直执行,不出结果。 原因: 执行update或者insert语句后需要commit,如果因网络或其他原因没有commit而强制关闭连接,Oracle就会将该条提交的记录锁住。 解决方法: 1、查询锁定记录 select object_name, machine, s.sid, s.serial# f...

itmyhome的专栏 1万+

AI与Agent赋能下的软件测试变革:面向未来测试工程师的工作方法论

AI Agent 软件测试 测试 software testing test

测试技师的自我修养 1239
上一篇: HTTP请求的几种类型
下一篇: ES6模块与CommonJS模块的差异
aaa333qwe
博客等级 码龄12年 207粉丝 96原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值