浅谈JavaScript的编程基础:编译过程和作用域

112 阅读4分钟

本篇文章将带大家了解js中的编译过程、js中的几种作用域,以及在js中var、let、const这几个关键字的区别。

js中的编译:

js首先对词法分析,接着对代码进行解析,最后生成代码。 例如:

//var a = 123  //var, a, =, 123  => var a = 123 (这是编译的过程)
var a = 1;
console.log(a);

则是输出 a = 1. 但是当我们将位置互换后:

console.log(a);
var a = 1;

则是输出:undefined。为什么会出现这种情况呢?这正是因为在预处理时JavaScript引擎将var所声明的变量进行了声明提升,将var所声明的变量在其所在的作用域中置顶,但其它的操作不会进行。

console.log(a);  //                      var a;       (声明提升)
var a = 1        //js将代码解析后    - >   console.log(a); (此时a并未被赋值,所以输出undefined)  
                //                       a = 1;       (a被赋值,但未被访问,保留)

而使用从const和let关键字时则不会出现上述情况,例:

console.log(a);   //Error: Cannot access 'a' before initialization
let a = 1;        //结果报错

console.log(a); //Error: Cannot access 'a' before initialization
let a = 1       //结果报错

此时用const和let两个关键字都是相同的结果,都会报错哦。这段代码之所以会报错,是因为JavaScript引擎的执行顺序和对let、const声明的特殊处理规则。这是因为使用let和const两个关键字时都会形成暂时性死区(Temporal Dead Zone, TDZ),从而报错。const和let关键字都是在 ECMAScript 6(ES6)标准中引入的,它们之间有共同的地方,但也存在着一些关键性的区别。

const、let和var关键字的区别:

var关键字:var声明的变量存在声明提升,同时var在全局声明的变量则会被添加到window对象上。 const关键字:声明变量的时候必须要进行赋值,且const声明的是常量不可进行修改。如果是复杂数据类型如数组或对象,虽然不能改变引用,但可以修改其内部属性或元素。 let关键字:声明变量的时候可以赋值也可以不赋值。

const和let关键字的相同之处:

两者都有块级作用域,这意味着它们在声明它们的代码块(如if语句、for循环或一对花括号内)内有效,而不像var声明的变量那样具有函数作用域或全局作用域。let和const都不存在变量提升(hoisting)现象,即它们在声明之前是不可访问的,这避免了潜在的错误和混淆.在相同作用域内,let和const都不允许重新声明同名变量,这有助于减少因变量覆盖而导致的错误。在变量声明之前访问 let或const声明的变量会出现暂时性死区。

总结:const适合不进行修改的变量,而let则是适合需要在特定作用域内可变的场景中使用。

JavaScript中的作用域:

  1. 全局作用域:在代码的最外层定义的变量拥有全局作用域,这意味着它们在代码的任何地方都是可访问的。全局变量在浏览器环境中会成为window对象的属性。var在全局声明的变量会被添加到window对象上。
  2. 函数作用域:在函数内部定义的变量拥有局部作用域,这些变量只能在该函数内部被访问,不能被外界访问。
  3. 块级作用域:它们允许在块(例如if语句或for循环的大括号内)中创建具有块级作用域的变量,这使得这些变量只能在定义它们的块中可见。(块级作用域通常由此组成 {} + let 或 {} + const)
  4. 词法作用域(静态作用域):JavaScript中采用词法作用域,这意味着变量的作用域在代码编写阶段就已经确定,由其所在的源代码中的位置决定。内部作用域可以访问外部作用域的变量,但外部作用域不能访问内部作用域的变量,这称为“作用域链”。(同时其中有一些特殊的代码:eval() 让原本不属于这里的代码,变得好像天生就定义在了这里一样。with(){} 当修改对象中不存在的属性时,这个属性会被泄露到全局,变成全局变量)

总结:

本文讲解了JavaScript中的编译过程、作用域的概念以及var、let和const三个关键字的核心差异,同时JavaScript中的编译流程和作用域规则对代码的行为有着直接影响。