一,作用域概念:
我的理解是:js引擎或编译器对变量的操作可以起作用的一块空间,脱离了这个空间,变量就“无效”了。 专业的解释是:作用域是
根据名称查找变量的一套规则。(现实中,通常需要同时顾及几个作用域)
二,常规的编译过程:三步:对 var a =2;的编译步骤
> 1,分词/词法分析:将字符串分解成代码块,又称词法单元。var 、a、=、2、;
2,解析/语法解析:词法单元流(数组)生成AST抽象语法树
3,代码生成:将AST转换成可执行的代码。(将AST转化为一组机器指令,用来创建一个叫做a的变量,包括内存分配,并将一个值2存储在a中)。
三,相比上述编译器的的三步编译,javascript的引擎更复杂,例如,他会在第二三步骤对 运行性能 进行优化,包括对冗余元素进行优化。
四,js的编译
遇到 var a =2; 引擎认为这里有两个不同的声明。一个由编译器在编译时处理,一个由js引擎在运行时处理。
1,遇到 var a,编译器会询问作用域,是否已经有一个该名称的变量在同一个作用域的集合中。如果是,编译器忽略该声明,继续进行编译。否则,他会要求作用域在该集合中声明一个变量,命名为a。
2,接下来,编译器会为引擎生成运行时所需的代码,这些代码被用来处理a = 2
这个赋值操作,引擎会问作用域,在当前的作用域集合中是否有a这个变量,如果有引擎就拿来用,如果否,引擎会继续查找该变量。如果引擎找到了变量a,就会将2赋值给他,否则引擎就会抛出一个异常!
说白了,一个声明变量,一个拿来使用,中间,两者都要让作用域参与。
五,LHS 和 RHS ,
是一个赋值操作的左侧和右侧。L是查询和赋值 R是查询(取到他的源值)
六,ReferenceError ,TypeError
ReferenceError 对象代表当一个不存在的变量被引用时发生的错误.
当执行RHS引用时,如果对变量使用了错误的用法,比如对一个未声明过的变量a执行函数操作a(),报错ReferenceError。对未声明过的变量a执行访问操作(害,RHS不就是查询引用操作吗),a,报错ReferenceError。
如果对null或者undefined的变量(声明过了,未赋值或置为null)进行属性访问 a.xxx的操作,报错TypeError。
总结:只要声明过了,再进行不合理的操作,基本就是TypeError。只要没声明过,再进行不合理
的操作,就是引用错误ReferenceError。
当执行RHS时,被执行的代码变量不一定有作用域,可能还没有被声明过,所以,会出现个ReferenceError 和 TypeError错误。
当执行LHS时,如果变量没有被声明过,引擎会声明一个同名的变量(前提是在非严格模式下,严格模式下,LHS的变量声明会被阻止,所以,我们自己测试时,可以适当的调整环境模式:严格模式、慵懒模式、)
七八九十