摘要:编译器遇到,会检查当前的作用域中是否有的声明。引擎运行时会查找当前的作用域中是否有一个名字为的变量。与作用域判别失败相关,则代表了作用域判别成功,但对结果的操作是非法或不合理的。对象里的属性会变成作用域里变量。
JavaScript的编译
通常来说JavaScript是一门“动态”或者“解释执行”语言,但事实上它是一门编译语言,晦涩的编译原理咱就不说了(我也不懂),直接说一下JavaScript的编译情况。对于JavaScript来说,大部分情况下编译发生在代码执行前几微秒的时间内。
最简单的一段JavaScript的代码:
var a = 2;
编译器对于这行代码会进行两个步骤的处理:
//变量声明 var a; //赋值操作 a = 2;
这个过程中会涉及到变量提升的问题。
编译器遇到var a,会检查当前的作用域中是否有a的声明。如果有,那么就会忽略掉a的声明,如果没有就会在当前的作用域中声明一个新的变量,并命名为a。
接下来编译器就把a = 2这条语句翻译成机器代码等待运行。引擎运行时会查找当前的作用域中是否有一个名字为a的变量。如果有就使用;如果没有,引擎会到上层的作用域中查找,直到全局作用域中。
区分RHS和LHSvar a = 2; //这里是一个LHS引用 console.log(a); //这里是一个RHS引用
乍一看LHS就是‘=’的左边,RHS就是‘=’的右边。但我对LHS的理解是我把值放到哪里,RHS是我去哪里找我要的值。为什么要区分RHS和LHS,因为在变量还没有声明的时候,这两种查询的行为是不一样的。
function foo(a){ console.log(a+b); b = a; } foo(2);
运行时,第一次对b进行的是RHS的查询,引擎在所有作用域中都找不到,最后会抛出一个ReferenceError的错误。而对于b=a而言,b进行的是LHS查询,如果在全局作用域中都找不到,那么就会在全局作用域中创建一个变量b。(前提是代码运行在非严格模式)。
接下来,如果RHS查询到了一个变量,但你尝试对这个变量的值进行不合理的操作。比如,对一个非函数类型的值进行函数调用,那么引擎会抛出TypeError。
ReferenceError与作用域判别失败相关,TypeError则代表了作用域判别成功,但对结果的操作是非法或不合理的。
词法作用域就是定义在词法阶段的作用域。更通俗的说法是词法作用域是你书写代码的顺序决定的。例如如下代码:
function foo(a){ var b = a*2; function bar(c){ console.log(a,b,c); } bar(b*3); } foo(2);
在全局作用域中只有一个变量foo;在foo的作用域中有变量a,b和函数bar;在bar的作用域中有变量c。这种层层嵌套的关系是在书写时就已经决定了。
动态作用域就是在程序运行的时候才能确定的作用域。JavaScript中有两种实现方式eval和with。但这两种方式都会导致性能的下降,所以还是少用。
JavaScript中的eval函数可以接受一个字符串的参数,并将其中的内容视为好像在书写的时候就存在于程序中这个位置一样。例如如下代码:
function foo(str,a){ eval(str); console.log(a,b); } var b = 2; foo("var b = 3;",1);//1,3
eval函数的参数是“var b = 3;”,这段代码就会被当做本来就在那里一样。也就是会遮蔽全局作用域中的b变量。
withwith表面上是一种引用同一个对象不同属性的快捷方式,但更重要的是它会创建一个新的作用域,例如如下代码:
//with体现了访问对象的快捷 var obj = { a:1, b:2, c:3 }; //不使用with obj.a = 2; obj.b = 3; obj.c = 4; //使用with with(obj){ a = 2; b = 3; c = 4; }
创建新的作用域可以看如下代码:
function foo(obj){ with(obj){ a = 2; } } var o1 = { a:3 }; var o2 = { b:3 }; foo(o1); console.log(o1.a);//2 foo(o2); console.log(o2.a);//undefined console.log(a);//2,a暴露在全局作用域中
a为什么会暴露在全局作用域中?
当执行foo(o1)时,因为使用了with,所以会创建一个全新的作用域,命名为o1。o1对象里的属性会变成o1作用域里变量。当执行a=2时,可以在o1的作用域中找到a,所以就修改了a的值。
当执行foo(o2)时,o2的作用域中没有a变量,所以会执行LHS的查询,最终会在全局作用局中声明一个变量a,所以就导致了a暴露在全局作用域中。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/79841.html
摘要:作用域作用域是指程序源代码中定义变量的区域。采用词法作用域,也就是静态作用域。而与词法作用域相对的是动态作用域,函数的作用域是在函数调用的时候才决定的。前面我们已经说了,采用的是静态作用域,所以这个例子的结果是。 JavaScript深入系列的第二篇,JavaScript采用词法作用域,什么语言采用了动态作用域?两者的区别又是什么?还有一个略难的思考题,快来看看吧。 作用域 作用域是指...
摘要:也毫不例外,但在中作用域的特性与其他高级语言稍有不同,这是很多学习者久久难以理清的一个核心知识点。主要使用的是函数作用域。 关于作用域:About Scope 作用域是程序设计里的基础特性,是作用域使得程序运行时可以使用变量存储值、记录和改变程序的状态。JavaScript 也毫不例外,但在 JavaScript 中作用域的特性与其他高级语言稍有不同,这是很多学习者久久难以理清的一个核...
摘要:讲作用域链首先要从作用域讲起,下面是百度百科里对作用域的定义作用域在许多程序设计语言中非常重要。原文出处谈谈语法里一些难点问题二 3) 作用域链相关的问题 作用域链是javascript语言里非常红的概念,很多学习和使用javascript语言的程序员都知道作用域链是理解javascript里很重要的一些概念的关键,这些概念包括this指针,闭包等等,它非常红的另一个重要原因就...
摘要:全局作用域局部作用域局部作用域全局作用域局部作用域块语句没有块级作用域块级声明包括和,以及和循环,和函数不同,它们不会创建新的作用域。局部作用域只在该函数调用执行期间存在。 一、什么是作用域? 作用域是你的代码在运行时,各个变量、函数和对象的可访问性。(可产生作用的区域) 二、JavaScript中的作用域 在 JavaScript 中有两种作用域 全局作用域 局部作用域 当变量定...
摘要:在中的应用采用词法作用域,也就是静态作用域。那什么又是词法作用域或者静态作用域呢请继续往下看静态作用域与动态作用域因为采用的是词法作用域函数的作用域在函数定义的时候就决定了。 开篇 当我们在开始学习任何一门语言的时候,都会接触到变量的概念,变量的出现其实是为了解决一个问题,为的是存储某些值,进而,存储某些值的目的是为了在之后对这个值进行访问或者修改,正是这种存储和访问变量的能力将状态给...
摘要:依然持有对该作用域的引用,而这个引用就叫作闭包。循环和闭包正常情况下,我们对这段代码行为的预期是分别输出数字,每秒一次,每次一个。 一、作用域 作用域共有两种主要的工作模型:第一种是最为普遍的,被大多数编程语言所采用的词法作用域,另外一种叫作动态作用域; JavaScript所采用的作用域模式是词法作用域。 1.词法作用域 词法作用域意味着作用域是由书写代码时函数声明的位置来决定...
阅读 2222·2021-09-24 10:31
阅读 3875·2021-09-22 15:16
阅读 3395·2021-09-22 10:02
阅读 1010·2021-09-22 10:02
阅读 1822·2021-09-08 09:36
阅读 1974·2019-08-30 14:18
阅读 609·2019-08-30 10:51
阅读 1863·2019-08-29 11:08