你不知道的js系列-引擎怎么查找变量(代码片段)

Zina Zina     2022-12-24     754

关键词:

对代码进行处理的三个角色
引擎:从头到尾负责整个 JavaScript 程序的编译和执行过程
编译器:负责语法分析及代码生成等
作用域:负责收集并维护所有变量的查询

 

var a = 2;
编译器首先会将这段程序分解成词法单元,然后将词法单元流解析成一个树结构。然后将树结构转换成可执行代码,也就是计算机懂的指令。为一个变量分配内存,将其命名为 a,然后将值 2 保存进这个变量。这符合编译原理

 

然而并不完全正确

 

事实上编译器会进行如下处理
1、在词法分析中,遇到 var a,编译器会询问当前作用域是否有该变量。是,忽略该变量继续编译。否,要求作用域声明一个新的变量
2、在生成代码中,编译器对 a = 2 进行赋值操作。首先询问作用域,在当前作用域是否存在该变量。是,使用该变量。否,引擎继续查找该变量

如果引擎找到了 a ,就将 2 赋值给它。否则抛出异常

变量赋值操作会执行两个动作,一个是编译器在当前作用域声明该变量,然后引擎在作用域中查找该变量,进行赋值

 

查找的过程由作用域进行协助,但是引擎执行怎么样的查找,会影响最终的查找结果。引擎会为变量 a 进行 LHS 查询。另外一个查找的类型叫做 RHS 。它们代表赋值操作的左侧和右侧。更准确的说,LHS 查询是试图找到变量的容器本身。

 

LHS 和 RHS 的含义是 “赋值操作的左侧或右侧”,并不一定意味着就是 “ = 赋值操作符的左侧或右侧”。赋值操作还有其他几种形式,因此在概念上最好将其理解为 “赋值操作的目标是谁(LHS)” 以及 “谁是赋值操作的源头(RHS)”。

 

比如
function foo(a) 
  console.log(a) //2

foo(2);
对 foo 进行 RHS 引用。对 a 进行 LHS 引用。对 console 进行 RHS 引用

 

function foo(a)
  var b = a;
  return a + b;

var c = foo(2);
这里 LHS 有 3 处,RHS 有 4 处
 
这里每一次查找,都需要跟作用域配合一次
 

 

《你不知道的js》提升(代码片段)

四、提升:一)、声明与赋值:? 在JS引擎中,我们一般认为的变量或函数声明,实际上分为两个部分。声明赋值//变量提升a=2;vara;console.log(a);//函数提升foo();functionfoo() console.log(1);? vara=2;? 这句声明实际上会被看为vara;a=2;两个部分... 查看详情

lhs和rhs----你所不知道的javascript系列(代码片段)

...查找该变量,如果能够找到就会对它赋值。----《你所不知道的JavaScript(上)》 P7而要讲的LHS和RHS就是上面说的对变量的两种查找操作,查找的过程是由作用域(词法作用域)进行协助,但是引擎执行怎样的查找,会影响最... 查看详情

你不知道的js系列(5)-词法作用域(代码片段)

作用域分为两种,一种是词法作用域,一种是动态作用域,我们先看第一种,词法作用域 词法作用域就是定义在词法阶段的作用域(编译器的第一个工作阶段叫做词法化,词法化的过程会对源代码中的字符进行检查)。换句... 查看详情

你不知道的js系列(33)-对象复制(代码片段)

JS初学者最常见的问题之一就是如何复制一个对象。看起来应该有一个内置的copy()方法,实际上比想象中的更复杂,我们无法选择一个默认的复制算法functionanotherFunction()/**...*/;varanotherObject=c:true;varanotherArray=[];varmyObject=  a:2, ... 查看详情

你不知道的javascript(作用域和闭包)

作用域和闭包 ?作用域  引擎:从头到尾负责整个JavaScript的编译及执行过程。  编译器:负责语法分析及代码生成等。  作用域:负责收集并维护由所有声明的标识符(变量)组成的一系列查询,并实施一套非常严格... 查看详情

你不知道的js系列上(45)-隐式混入(代码片段)

varSomething=  cool:function()    this.greeting=‘HelloWorld‘;    this.count=this.count?this.count+1:1;  Something.cool();Something.greeting;//‘HelloWorld‘Something.count;//1varAnother=  cool:func 查看详情

你不知道的sring(系列三)(代码片段)

AbstractStringBuilderStringBuffer和StringBuilder都继承了AbstractStringBuilder,很多方法都是直接super的父类AbstractStringBuilder的方法,所以我们分析下AbstractStringBuilder的源码.1.成员变量AbstractStringBuilder和String一样,在其内部都是以字符数组的形... 查看详情

你不知道的js系列(39)-对象遍历(代码片段)

for循环可以遍历数组varmyArray=[1,2,3];for(vari=0;i<myArray.length;i++)  console.log(myArray[i])//123ES5增加了数组的辅助迭代器,包括forEach(...)、every(...)、some(...)forEach(...)会遍历数组中的所有值并忽略回调函数的返回值every(...)会一直运行直... 查看详情

你不知道的js系列(13)-什么是闭包(代码片段)

当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行functionfoo()  vara=2;  functionbar()    console.log(a);    returnbarvarbaz=foo();baz();//2——朋友,这就是闭包的效果在foo... 查看详情

你不知道的js系列上(45)-显式混入(代码片段)

JS的对象机制并不会自动执行复制行为,由于其他语言中表现出来的复制行为,因此JS开发者也想出了一个方式来模拟类的复制行为,这个方法就是混入。我们先看第一种,显式混入。//非常简单的mixin()例子functionmixin(sourceObj,targe... 查看详情

你不知道的js系列(14)-闭包无处不在(代码片段)

上一节的闭包是为了解释如何使用闭包而人为地在结构上进行修饰,在昨天的闭包基础上,我们可以更加灵活的使用闭包functionwait(message)  setTimeout(functiontimer()    console.log(message)  ,1000)wait(‘hello,consure‘);内部函数timer... 查看详情

你不知道的js系列(29)-对象属性(代码片段)

存储在对象容器内部的是这些属性的名称,它们就像指针(从技术角度来说是引用)一样,指向这些值真正的存储位置。 varmyObject=  a:2myObject.a;//2myObject[‘a‘];//2.语法通常被称为‘属性访问’,[]语法通常被称为&lsqu... 查看详情

你不知道的js系列(12)-声明提升(代码片段)

我们直觉上会认为JavaScript代码在执行时是由上到下一行一行执行的。但实际这并不完全正确 a=2;vara;console.log(a);这里可能会认为是undefined,因为vara声明在a=2之后。实际输出了2。 console.log(a);vara=2;鉴于上面的代码可能会是2... 查看详情

你不知道的js系列(22)-thisnew绑定(代码片段)

在传统的面向类的语言中,“构造函数“是类中的一些特殊方法,使用new初始化类时会调用类中的构造函数。通常的形式是这样的something=newMyClass(..);然而JavaScript中new的机制实际上和面向类的语言不同。它们只是被new操作... 查看详情

你不知道的js系列(7)-欺骗词法作用域(代码片段)

如果词法作用域完全由写代码期间函数所声明的位置来定义,怎样才能在运行时来“修改”词法作用域呢?有些人喜欢特殊的办法来解决遇到的问题。我们规定词法作用域是代码写在哪里决定的,一旦决定了无法更改,因... 查看详情

你不知道的js系列(30)-对象属性(可计算属性名)(代码片段)

如果你需要通过表达式来计算属性名,[]操作符就派上用场了。ES6中使用[]包裹一个表达式来当作属性名varprefix=‘foo‘;varmyObject=  [prefix+‘bar‘]:‘hello‘,  [prefix+‘baz‘]:‘world‘,myObject[‘foobar‘];//hellomyObject[‘foobaz‘];//world... 查看详情

你不知道的js系列(19)-this调用位置(代码片段)

我们排除了一些对于this对错误理解并且明白了每个函数的this是在调用时被绑定的,完全取决于函数的调用位置。寻找调用位置就是寻找“函数被调用的位置”,但是做起来并没有这么简单,因为某些编程模式可能会隐藏... 查看详情

你不知道的javascript学习笔记1——作用域

处理程序三要素:引擎:编译与执行过程。编译器:语法分析与代码生成等。作用域:收集并维护由所有声明的标识符(变量)组成的一系列查询,并实施一套非常严格的规则,确定当前执行的代码对这些标识符的访问权限。&nb... 查看详情