-
2019-05-09 21:32:17
变量按作用域可分为“局部变量”,和“全局变量”。按照存储方式又可分为“自动变量”,“静态变量”,“寄存器变量”,“外部变量”。
注意,是“自动变量”不是“动态变量”。“动态变量”和“动态存储”比较复杂。
什么是“寄存器”?我们知道,内存条是用来存储数据的,硬盘也是存放数据的,而在CPU也有部分是用来存储数据的区域的,即寄存器。寄存器是CPU的组成部分,是CPU内部用来存放数据的一些小型存储区域,用来暂时存放参与运算的数据和运算结果。他同内存一样,只不过他只能存储的数据较少。
以上这些变量,需要重点掌握“局部变量”和“全局变量”,“自动变量”,“静态变量”,“寄存器变量”,和“外部变量”了解即可,在后面的编程中可用可不用,就算使用也很简单。
更多相关内容 -
JS变量查找的规则
2021-01-12 20:09:571、变量查找的规范 左查询(对等号左边的变量进行寻址) 如果整条作用域链 都没有对应变量的声明;则会在全局自动声明一份 /* var a = 3; b = a;*/ console.log(b) //全局自动声明一份,3 右查询(对等号非左边的变量...1、变量查找的规范
左查询(对等号左边的变量进行寻址)
如果整条作用域链 都没有对应变量的声明;则会在全局自动声明一份/* var a = 3; b = a;*/ console.log(b) //全局自动声明一份,3
右查询(对等号非左边的变量进行寻址)
如果整条作用域链 都没有对应变量的声明;则会报错console.log(c)
2、作用域
变量的查找!!!走作用域链!!!var x = 10; function fn() { console.log(x); } function show(f) { var x = 20; fn()//调用fn函数的时候会倒回第二行去执行,该作用域没有定义X,往上一层找,全局x=10 } show(fn);//10
3、经典闭包
//编译阶段就已经生成作用域了!!! function wrap() { var a = "a" return function () { console.log(a) } } var inner = wrap() inner()
4、js三座大山&两头神兽
三座大山 : 作用域&作用域链 ; 执行上下文&执行上下文栈 ; 原型&原型链 作用域&作用域链 : 决定了变量的查找规则;左查询 右查询 执行上下文&执行上下文栈: a.函数调用时 实参如何对应形参 b.给arguments赋值 c.给this赋值 d.闭包 原型&原型链: 决定了属性的查找规则 两头神兽 : 闭包 原型 闭包: 当函数可以记住并访问自己的作用域链时;就会产生闭包
个人理解:
编译阶段就已经有作用域了
一个作用域挂靠一个执行上下文
闭包市场说法 :内部函数使用了外部函数的变量
或者,当函数可以记住并访问自己的作用域链时,就会产生闭包。
记住:指的是->执行上下文的数据
闭包:就是某个函数要挂了,但是不能把变量带走,把数据放到一个容器里面给后面调用者。 -
三、函数高级(五)- 变量查找
2021-08-23 10:07:44三、变量查找机制 变量查找机制: 1) 沿着作用域链查找变量: 确定当前函数的作用域链, 首先在当前作用域中对应的执行上下文对象中查找变量, 如果找不到,就会到上一级作用域中对应的执行上...一、前提
1、原型与原型链 原型链的作用就是查找对象的属性。 2、执行上下文与执行上下文栈 执行上下文的作用就是保存当前作用域环境的初始化变量。 创建:在JS执行全局代码前或函数代码前,会设置执行上下文对象,并初始化环境。 死亡:函数执行完毕就会销毁。 3、作用域与作用域链 作用域链的作用就是查找变量。 作用域链的代码实现就是函数内部属性[[scopes]]属性。 4、闭包 闭包的作用就是延长函数变量的生命周期。 闭包本质上就是闭包作用域对象。
二、变量查找机制
+++ 基础 1) 沿着作用域链查找变量: 确定当前函数的作用域链, 首先在当前作用域中对应的执行上下文对象中查找变量, 如果找不到,就会到上一级作用域中对应的执行上下文对象中查找。直到全局作用域。 2) 沿着原型链查找对象属性 +++ 变量查找机制 1) 首先在自身作用域中对应的执行上下文对象中查找。 2) 如果找不到,就会到函数的作用域链属性中查找。 从索引值0开始依次向上查找。 3)查找到变量后,如果继续查找对象的属性,则会沿着原型链查找。
注意事项: 1) 作用域是在函数定义时确立的。而不是在函数调用时确立的。 2) 作用域只分为全局作用域和函数作用域 3) 在全局作用域中定义的变量会被当做window的属性来保存。 不使用var关键字定义的变量会被当作window的属性来保存。 4) 作用域链与原型链都是用于查找对象的属性。 在作用域链查找变量是沿着作用域链查找。 在对象中查找属性是沿着原型链查找。
3.1 变量查询机制
1)案例1
首先在自身作用域中对应的执行上下文对象中查找fn,
.
找不到就会到作用域链属性中查找,此时,作用域链属性中只有window对象,则会到window对象中查找fn。var fn=function(){ //首先在自身作用域中查找变量fn。 //然后到全局作用域查找变量fn。 console.log(fn) } fn();
2)案例2
首先在自身作用域中对应的执行上下文对象中查找this.
var obj={ fn2:function(){ //查找obj对象中的fn2 console.log(this.fn2); } } obj.fn2();
>>>>>> 作用域只分为全局作用域和函数作用域
作用域只分为全局作用域和函数作用域。
虽然fn2是obj的属性,但是作用域只分为全局作用域和函数作用域。所以fn2函数的所在的作用域链fn2函数作用域 > 全局作用域。
查找变量:首先在fn2作用域中查找fn2变量,找不到,然后到全局作用域查找,找不到后报错。var obj={ fn2:function(){ //首先在自身作用域中查找变量fn2. //然后到全局作用域中查找变量fn2,找不到,报错。 console.log(fn2); } } obj.fn2(); //报错
>>>>>> 作用域是在编码时就已经确立的,不会改变
虽然fn函数在show函数中调用,但是fn函数的作用域链是在定义时就已经确定了,而不是调用时确定。 fn函数作用域链:fn函数作用域 > 全局作用域。
var x=10; function fn(){ console.log(x) } function show(f){ var x=20; f(); } show(fn);
3)案例3
首先在getNameFun函数对应的执行上下文中查找this,此时this指向window。
然后会到window中查找name//案例一 var name='The Window' var obj={ name:'My Object', getNameFun:function(){ return function(){ return this.name; } } } console.log(obj.getNameFun()())
首先在匿名函数对应的执行上下文中查找that
找不到就会到函数中的作用域链属性中查找。此时作用域链属性从0开始依次是闭包作用域对象、window对象。
从索引值0开始查找,找到that。
然后沿着that的原型链查找name。//案例er var name='The Window' var obj={ name:'My Object', getNameFun:function(){ var that=this; return function(){ return that.name; } } } console.log(obj.getNameFun()())
3.3 作用域链、执行上下文与变量查询的内在联系
执行上下文与作用域的关系: 1、作用域的作用是隔离变量。 2、作用域链的作用是查询变量。 3、作用域、作用域链是在编码时就已经确定了,而执行上下文对象是在代码执行前或函数执行时确立的。 执行上下文对象从属于作用域。 函数在查找变量时, 1、首先会在当前作用域中对应的执行上下文对象查找变量, 这是由于在执行代码前,会初始化代码数据,此时会将变量或函数放入到执行上下文对象中。 2、如果找不到,就到上一级作用域对应的执行上下文对象中查找。
三、JS执行过程解析
3.1 执行上下文与作用域的直观展示
var s=12; function ff(){ //此时闭包已经产生了。(函数提升,内部函数对象已经创建了) var a=1; function f(){ a++; console.log(a) } return f; } var f=ff(); f(); //2 f();//3
4.2 JS代码执行全流程讲解
+++ 前提: 1、JS执行代码前首先会创建一个执行上下栈。 2、在创建执行上下文对象后会将执行上下对象放入到栈中。函数执行完毕,会将该对象从栈中移除。 3、执行上下文栈中最终存储window执行上下文。 +++ JS全流程讲解 1、JS代码执行时,首先会将Window设置为全局执行上下文。 2、然后初始化全局数据: 变量声明提前,并设置为window属性。 函数声明提前(函数声明实质上就是创建函数对象),并设置为window属性。 将this设置为window对象。 3、执行全局代码。 4、执行到某个函数时 1、创建函数执行上下文。 2、初始化函数数据 变量声明提前,并设置为window属性。 函数声明提前(函数声明实质上就是创建函数对象),并设置为window属性。 函数形参赋值,并设置为函数执行上下文的属性。 函数arguments赋值,并设置为函数执行上下文的属性。 函数中this设置为window对象。 3、执行函数代码 +++ JS查找变量 函数沿着作用域链查找变量时, 首先在当前作用域中对应的执行上下文对象中查找变量, 如果找不到,就会到上一级作用域中对应的执行上下文对象中查找。直到全局作用域。
-
数据集的 strfind:在 Matlab 数据集中搜索和查找条目(在指定的字符串变量中)-matlab开发
2021-06-01 16:34:24此函数允许在观察中查找子字符串 (str) 数据集 dset 的变量 (vars)。 vars 可以是变量名或要在数据集中搜索的列号。 % % % 例子: 姓名 = {'约翰'; '亨利';'恩里科'}; 年龄 = [26; 18; 35]; d1 = dataset({names,... -
《你不知道的JavaScript》读书笔记(一):JS是如何查找变量的
2022-04-13 00:54:01第一个问题:JavaScript是如何查找变量的? 第1部分 作用域和闭包 第1章 作用域是什么? 编译原理 这本讲解JavaScript的书首先讲的却是编译原理,一开始看起来让人费解,但实际上从后面内容我们可以发现,JavaScript...这本书之前囫囵地看了一遍,确实点明了很多以前不清不楚的点,但是仅仅看一遍是没什么用的,最近面试遇到不少原理相关的题感觉答得不理想,回头看下其实以前都理解过,但是没有记下来,正好结合实际的问题来再学习一下书上的内容。
第一个问题:JavaScript是如何查找变量的?
第1部分 作用域和闭包
第1章 作用域是什么?
编译原理
这本讲解JavaScript的书首先讲的却是编译原理,一开始看起来让人费解,但实际上从后面内容我们可以发现,JavaScript的很多特性都与编译原理有着极大的关系。我们通常称JavaScript是动态解释执行语言,因为它不是提前编译的,而是根据执行时的情况来对代码进行处理。
在传统编译语言的流程中,代码的执行通常分成三个步骤:
- 分词/词法分析(Tokenizing/Lexing)
将语句分解成词法单元(Token),例如
var a = 2;
会被分解成: var、a、=、2、;。需要注意的是分词和词法分析有少许的区别,如果词法单元生成器在判断a是一个独立的词法单元还是其他词法单元的一部分时,调用的是有状态的解析规则,那么这个过程就被称为词法分析。
理解不了这一句中的 有状态的解析规则
- 解析、语法分析(Parsing)
将词法单元流转换成树形结构的的过程。这个树被称为“抽象语法树”(Abstract Syntax Tree,AST).
- 代码生成
将AST转换成可执行代码的过程。简单来说就是把
var a = 2;
的AST转化为一组机器指令,用来创建一个叫做a的变量(包括分配内存),并将一个值储存在a中。与传统编译语言的编译器相比,JavaScript引擎要更复杂,最明显的区别就体现在编译时间上,JavaScript引擎没有时间进行优化,编译过程不是在构建之前,通常发生在代码执行前的几微秒内。在作用域的背后,JavaScript引擎使用了各种方法(比如JIT延迟编译甚至实施重编译)来保证性能。
理解作用域
在理解作用域之前还有一些前置的概念需要理解,在JavaScript执行的时候有三个重要组件:
- 引擎:负责整个JavaScript程序的编译及执行过程
- 编译器:负责语法分析和代码生成
- 作用域:负责收集维护由所有声明的标识符(也就是变量)组成的查询,并根据严格的规则确定执行的代码对变量的访问权限
还是上面的
var a = 2;
这个例子,编译器在处理时会分成两步:var a
,编译器先询问作用域同一个作用域中是否已经有这样一个名称的变量。如果是,编译器则忽略这个声明,继续编译;如果否,编译器则要求作用域在当前作用域的集合中声明一个新的变量,命名为a。a = 2
,编译器会为引擎生成运行所需要的的代码来执行这个赋值操作。引擎运行时同样先询问作用域,当前作用域集合中是否有一个叫做a的变量。如果是,引擎就会使用这个变量;如果否,引擎会继续查找该变量了(如何查我们在下一节说明,因为查找的是其他作用域的)。
如果再细致地说明引擎的查找过程可以把它分成LHS查询和RHS查询,“L”和“R”很好理解,就是左侧和右侧,具体来说就是一个赋值操作的左侧和右侧。
变量在赋值操作左侧时就进行LHS查询,出现在右侧时就进行RHS查询,但实际上会这么简单吗?肯定不是,LHS其实是找到变量的容器本身并对其赋值,RHS则相反,意思比较接近于“取到它的原值”或“得到某某的值”。看下面这个例子:
console.log(a);
这里对a的引用就是一个RHS引用,因为没有为a赋任何值,而是获取了a的值并传递给了console.log()。而相比
a = 2
,很明显就是把“= 2”交给了“a”。也就是说LHS和RHS并不是简单的左侧和右侧,而是“赋值操作的目标是谁”和“谁是操作的源头”。
理解了之后再看这个例子,除了一个RHS操作是否还能找出一个LHS操作呢?
function foo(a){ console.log(a); // 2 } foo(2);
这是一个很容易被忽略的细节,代码中存在一个隐式的
a = 2
操作,2倍当做参数传递给了foo()函数,这里要给参数a分配值,所以需要一次LHS查询。作用域嵌套
这个问题说起来很简单,就是当引擎需要变量时,会先在当前作用域寻找,如果没有这个变量就到上一级作用域查找,直到最外层,也就是全局作用域,到达这里以后即使没找到也会停下来。
function foo(a){ console.log(a + b); // 2 } var b = 2; foo(2); // 4
异常
上面我们费了半天劲来理解LHS和RHS有什么意义呢?看下面这段代码:
function foo(a){ console.log(a + b); b = a; } foo(2);
显而易见这段代码会报异常,因为对b的RHS查询无法找到该变量,b是未声明的变量,但如果是进行LHS查询则不同,上面说了,引擎在当前作用域未能查找到对象就会向上一级,直到全局作用域还未能找到时,全局作用域就会创建一个具有该名称的变量,并将其交给引擎(前提是在非“严格模式”下)。偶尔会看到一些可以印证这一例子的不规范代码——未声明的变量被使用,如果是在ES5的“严格模式”下,会和RHS一样报ReferenceError的异常。
-
java笔记之变量的存储方式
2021-02-28 12:41:561.java变量存储域java变量的存储区域主要放在以下几个地方:(1)寄存器:可以说是最快的存储区,在C/C++中可以声明寄存器变量,但是在java中不能声明寄存器变量,只是编译器在编译时确定。(2)栈:存放关于基本类型... -
php获取一个变量的名字的方法
2021-01-21 15:55:27PHP中,所有的变量都存储在”符号表”的HastTable结构中,符号的作用域是与活动符号表相关联的。因此,同一时间,只有一个活动符号表。 我们要获取到当前活动符号表可以通过 get_defined_vars 方法来获取。 get_... -
R语言开发之变量的数据类型&赋值&查找&删除
2018-09-13 15:38:34R语言中的变量提供了程序可以操作的命名存储,这个变量可以存储原子向量,而原子向量组或许多R对象的组合。所以,有效的变量名称应该是由字母,数字和点或下划线字符组成,并且变量名称以字母开头,或者点后面不带... -
JQuery - 将ajax响应存储到全局变量中
2021-08-06 05:28:46JQuery - 将ajax响应存储到全局变量中我仍然是jQuery和ajax场景的新手,但我有一个$ .ajax请求执行GET来检索一些XML...因此,我有一个全局变量,我将响应数据存储到其中,并且对此数据的任何后续查找都在此变量上... -
JavaScript基础:栈堆,以及JS中的变量存储
2021-01-25 16:04:46栈是内存中一块用于存储局部变量和函数参数的线性结构,遵循着先进后出的原则。数据只能顺序的入栈,顺序的出栈。当然,栈只是内存中一片连续区域一种形式化的描述,数据入栈和出栈的操作仅仅是栈指针在内存地址上的... -
oracle存储过程----变量的介绍及使用(PL/SQL)
2018-08-17 08:16:00oracle存储过程—-变量的介绍及使用 学习一门语言,既然学会了hello word 的输出,那就要关注下基础,首先要熟悉存储过程 中的变量类型。 关于存储过程变量有哪些 ,这样的问题,我在百度上搜索,却发现很... -
Linux系统中的环境变量该如何设置与查看
2021-05-12 05:17:16环境变量是在程序及其子程序中全局可用的,常常用来储存像默认的文本编辑器或者浏览器,以及可执行文件的路径等等这样的信息。而 Shell 变量仅在当前Shell 中可用,可以用来存储当前用户的 ID 等信息。那么什么是... -
C++:对象及成员变量在内存中的存储分析
2021-05-19 17:30:42类的成员变量并不能决定自身的存储空间位置。决定存储位置的是对象的创建方式。 即: 如果对象是函数内的非静态局部变量,则对象,对象的成员变量保存在栈区。 如果对象是全局变量,则对象,对象的成员变量保存在... -
基本类型变量、引用类型变量的在java中的存放位置
2021-03-21 09:22:48一、局部变量存储在方法栈中在方法中声明的变量,即该变量是局部变量,每当程序调用方法时,系统都会为该方法建立一个方法栈,其所在方法中声明的变量就放在方法栈中,当方法结束系统会释放方法栈,其对应在该方法中... -
批处理DOS命令findstr查找信息赋值给变量
2015-03-05 09:03:35文件名:test.txt 文件内容: aaa str1=c:\aaa str2=d:\bbb str3=e\ccc bbb str1=aaa str2=bbb ...批处理脚本,查找文件中aaa下的str1的值,赋值给变量并在此目录下创建文件,文件内容为bbb中的str1. -
以太坊存储类型(memory,storage)及变量存储详解
2021-08-16 21:14:15在 Solidity 中,有两个地方可以存储变量 :存储(storage)以及内存(memory)。 Storage变量是指永久存储在区块链中的变量。 Memory 变量则是临时的,当外部函数对某合约调用完成时,内存型变量即被移除。 ... -
【C】C语言函数中的变量(包括:作用域、存储类型)
2018-05-05 10:11:15局部变量和全局变量 C语言中变量按其作用域分,可分为局部变量和全局变量,具体的解释为: 局部变量(内部变量):在定义它的函数内有效,但是函数返回后失效; 全局变量(外部变量):在所有源文件内均有效。在... -
深入理解Python变量的数据类型和存储
2021-02-01 09:53:16知道数据类型就要知道变量数据类型怎么存储,可是为什么python的变量不需要声明数据类型就可以直接赋值?变量如果有数据类型,那变量不是可以为任意数据类型?那真正的数据类型如int在内存存储的字节大小应该为多少... -
MySQL变量,存储过程,函数,流程控制详解(小白都能懂哦)
2020-05-18 08:59:07存储过程 4.函数 5.流程控制结构 1.系统变量 1.1系统变量的分类 系统变量:分为全局变量和会话变量 1.2系统变量的介绍 系统变量由系统提供,不是用户定义,属于服务器层面 1.3系统变量的相关操作 (1).查看... -
Python自学笔记(三)深入理解Python变量的数据类型和存储
2021-01-30 11:19:25知道类型就要知道变量类型怎么存储,可是为什么python的变量不需要声明类型就可以直接赋值?变量如果有类型,那变量类型如int在内存存储的字节大小应该为多少?等等诸如一系列的问题,我希望可以在此总结清楚。 ... -
21天学会Java之(Java SE第八篇):数组、冒泡排序法、二分法查找
2021-01-20 02:10:54数组 数组的定义 数组是相同类型数据的有序集合,数组描述的是相同类型...数组本身就是对象,Java中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中存储的。 数组声明 在声明数组变量 -
mysql实例 日期变量的二个例子
2021-01-18 21:28:271,mysql日期变量的实例代码。mysql>mysql> delimiter $$mysql>mysql> CREATE PROCEDURE myProc() //创建日期存储过程-> BEGIN-> DECLARE my_dob DATE-> DEFAULT '1982-06-21'; /* My Bir... -
C语言 常量,变量及数据详细介绍
2021-05-20 18:20:52一、数据图片文字等都是数据,在计算机中以0和1存储。(一)分类数据分为静态数据和动态数据。①. 静态数据:一些永久性的的数据,一般存储在硬盘中,只要硬盘没坏数据都是存在的。一般以文件的形式存储在硬盘上,电脑... -
C++之变量及数据存储
2017-11-09 15:51:27如图所示:计算机内存可以看作是一系列小文件柜,每个文件柜由许许多多排成一列的小格子组成,每一个格子都编了号,这些编号就是内存地址,变量一般放置在一个或者多个格子里,每个格子都可存储一个值。变量名(例如... -
JVM 变量存储位置
2018-03-18 22:20:121.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制.2. 栈:方法执行时创建方法栈帧,存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量... -
Matlab 查看内存中的变量,清空屏幕等命令
2021-04-18 13:17:20Matlab 查看内存中的变量,清空屏幕等命令该文章讲述了Matlab 查看内存中的变量,清空屏幕等命令.1。 查看内存中的变量 who whos2. clc 清空屏幕3. clf 清空当前的figure4. clear 清空内存变量5. figure 设定图像显示... -
shell中文件路径用变量定义_环境变量
2020-11-21 09:13:57环境变量可以使得 bash shell 存储有关 shell 会话和工作环境的信息,允许在内存中存储数据。在 bash shell 中,环境变量分为:全局变量局部变量全局变量对 shell 会话和所有生成的子 shell 都可见。局部变量只对... -
oracle 中execute immediate以及如何用变量作为表名查询
2021-05-08 12:11:58简单来说 就是你一个存储过程当中 创建了一个表 table_a 然后要用insert into将其他的数据插入到这个table_a当中,但是因为你在创建过程的时候 table_a还不存在,过程就会显示有编译错误,因为table_a不存在必然导致... -
mysql存储过程中用变量做表名
2021-01-30 02:26:02mysql存储过程中用变量做表名1.用变量做表名:简单的用set或者declare语句定义变量,然后直接作为sql的表名是不行的,mysql会把变量名当作表名。在其他的sql数据库中也是如此,mssql的解决方法是将整条sql语句作为... -
CCS 如何指定函数或变量在FLASH的存储地址
2021-03-17 17:06:21对于函数: 首先修改.c文件如下: #pragma CODE_SECTION (r_data2A, “.MY_FUNC_ADDR”) Void r_data2A(void) { } 然后修改.cmd文件 MEMORY { ...对于变量,如数组,只需要将上面的CODE_SECTION 改