作用域是什么?

Posted 差不多是条咸鱼了

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了作用域是什么?相关的知识,希望对你有一定的参考价值。

javascript作为编程语言,最基本的功能之一就是能够存储变量当中的值。而一套设计良好的用来存储变量,并且之后可以方便地找到这些变量的规则,被称为作用域

一、编译原理

首先要清楚,任何JavaScript代码片段在执行前都要进行编译,然后做好执行他的准备,并且通常马上就会执行他。其中:

  • 引擎:从头到尾负责整个JavaScript程序的编译及执行过程;
  • 编译器:负责语法分析及代码生成;
  • 作用域:负责收集并维护由所有声明的标识符(变量)组成的一系列查询,并实施一套非常严格的规则,确认当前执行的代码对这些标识符的访问权限。

这三者如何协同工作?

例如 var a = 2;这段程序,一般认为这是一句声明,但引擎却认为这是两个完全不同的声明:一个由编译器在编译时处理,另一个则由引擎在运行时处理。

这个变量的赋值操作会执行两个动作,首先编译器会在当前作用域中声明一个变量(如果之前没有声明过),然后在运行时引擎会在作用域中查找该变量,如果能够找到就会对他赋值

查找过程中,引擎会进行两种类型的查询:LHS查询、RHS查询。

LHS查询:试图找到变量的容器本身,从而可以对其赋值(当变量出现在赋值操作的左侧时进行,查找的目的是对变量进行赋值);

RHS查询:与简单的查找某个变量的值一样(当变量出现在赋值操作的非左侧时进行,目的是获取变量的值)。

二、作用域嵌套

当一个块或函数嵌套在另一个块或函数中时,就发生了作用域的嵌套。因此,在当前作用域中无法找到某个变量时,引擎就会在外层嵌套的作用域中继续查找,直到找到该变量,或抵达最外层的作用域(全局作用域)为止。

三、抛出异常

区分LHS和RHS是一件很重要的事,因为在变量还没有声明的情况下,这两种查询的行为是不一样的。

如果RHS查询在所有嵌套的作用域中遍寻不到所需的变量,引擎就会抛出 ReferenceError异常;当引擎执行LHS查询时,如果在顶层(全局作用域)中也无法找到目标变量,全局作用域中就会创建一个具有该名称的变量,并将其返还给引擎(前提是程序运作在非‘严格模式’下)。

严格模式禁止自动或隐式地创建全局变量。

如果RHS查询找到了变量,但是接下来对这个变量的值进行不合理的操作的话,比如试图对要给非函数类型的值进行函数调用,或者引用null或undefined类型的值中的属性,那么引擎会抛出林外一种类型的异常,叫做 TypeError异常

ReferenceError跟作用于判别失败相关,而TypeError则代表作用域判别成功了,但是对结果的操作是非法或者不合理的。

四、一个小测验

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

var c = foo(2);

这段程序有几处LHS查询?几处RHS查询?

 

拓展

JavaScript异常类型

  • 1.SyntaxError:解析代码时发生语法错误;
  • 2.ReferenceError:引用一个不存在的变量时发生错误; || 将一个值分配给无法分配的对象,比如对函数的运行结果或者this赋值;
  • 3.RangeError:当一个值超出有效 范围时发生的错。(数组长度为负数 || Number对象的方法参数超出范围 || 函数堆栈超过最大值);
  • 4.TypeError:变量或参数不是预期类型时发生的错误。比如对字符串等原始类型的值使用new命令,就会抛出这种错误;因为new命令的参数应该是一个构造函数;
  • 5.URIError:URI相关函数的参数不正确时抛出的错误,主要涉及encodeURI()、decodeURI()、encodeURIComponent()、decodeURIComponent()、escape()和unescape()这六个函数;
  • 6.EvalError:eval函数没有被正确执行时,会抛出这个错误,已经不再ES5中出现。

上面的六种异常对象都继承自Error对象;关于异常的更多详情,可参考 JavaScript中的异常处理 一文。

 

严格模式

"use strict";
  • 1.全局变量必须显示声明;
  • 2.只允许静态绑定;----禁止with语句;创设eval作用域;
  • 3.禁止this关键字指向全局对象;
  • 4.禁止在函数内部遍历调用栈;
  • 5.禁止删除变量;
  • 6.显示报错;
  • 7.重名错误;----对象不能有重名的属性;函数不能有重名的参数;
  • 8.禁止八进制表示法;
  • 9.arguments对象的限制;----不允许对arguments对象赋值;arguments不再追踪参数的变化;禁止使用arguments.callee;
  • 10.函数声明必须在顶层;
  • 11.新增了一些保留字:implements, interface, let, package, private, protected, public, static, yield。

严格模式详情可参考阮一峰的 Javascript 严格模式详解 一文。

小测试答案

LHS查询--3处

c = ..; || a (= 2)(隐士变量分配) || b = ..

RHS查询--4处

foo(2.. || = a; || a .. || ..b

以上是关于作用域是什么?的主要内容,如果未能解决你的问题,请参考以下文章

隐藏域是干啥东东 有啥作用 为啥有的网页上经常用到 如何使用

你不知道的JavaScript-作用域是什么

读书笔记你不知道的JavaScript(上卷)--作用域是什么

☀️作用域是什么?作用域链又是什么?你怎么理解?

☀️作用域是什么?作用域链又是什么?你怎么理解?

JavaScript 中变量的作用域是啥?