JavaScript 新旧替换一:变量声明

Posted XXHolic

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript 新旧替换一:变量声明相关的知识,希望对你有一定的参考价值。

目录

引子

在工作中,最初接触 ES5 的语法比较多,后来渐渐的接触了新的语法。由于一些原因,需要在不同的项目使用不同的语法。时间长了,发现在写代码的时候,偏向用更加熟悉的旧语法,但感觉这么下去不太妙。于是,就想着针对工作中常用的旧语法,跟可以替换的新语法进行对比,加深印象,然后记录总结一下,有意识的更新相关知识点。

ES5 方式

javascript 中,变量可以用来保存任何类型的数据。每个变量只是一个用于保存值的占位符而已。在 ES5 中,使用 var 声明变量,这种声明方式的特点有:

  1. 声明的变量不赋值,会初始化默认值为 undefined
var testVariable;
console.info(‘testVariable=‘,testVariable); // undefined
  1. 可以一条语句定义多个变量,变量之间用逗号分开。
var name = ‘Tom‘,
    age = 15;
  1. 如果省略 var 声明,则会创建一个全局变量,这样会污染全局变量,这种方式不推荐。
  2. var 声明的变量会自动添加到最近的环境中,当查找变量的时候,搜索过程是从作用域链的前端开始,向上逐级查询。如果在局部环境中找到了变量,则停止搜索,使用找到的变量。
  3. 同一作用域内重复声明同一变量时,后声明会覆盖前声明。
var testVariable = ‘123‘;
var testVariable = ‘12‘;
console.info(‘testVariable=‘,testVariable); //12
  1. 声明的变量会发生“变量提升”,也就是说可以先使用后声明,这种方式不推荐。
console.info(‘testVariable=‘,testVariable); // undefined
var testVariable = 1;

使用 var 声明比较经典的现象是在 for 循环语句中。

function printNum() {
  var numArray = [];
  for(var i=0;i<5;i++) {
    numArray.push(function (){
      console.info(i);
    })
  }
  numArray[0]();
}
printNum(); // 5

for 循环中用 var 声明的变量 i 在函数 printNum 作用域中都有效,每次循环执行的语句 console.info(i) 中的 ifor 循环中声明的 i,指向的是同一个 i,执行完最后一次循环时,i 的值就是 5。

ES2015+ 方式

新增的声明变量方式有:let、const。

let 声明

用法跟 var 类似,这种方式不同的地方有:

  1. 声明的变量,在 let 所在的代码块内有效。
{
  let testLet = 1;
  var testVar = 2;
}
console.info(‘testVar=‘,testVar); // 2
console.info(‘testLet=‘,testLet); // Uncaught ReferenceError: testLet is not defined
  1. 不会“变量提升”,要先声明后使用,否则会报错。
console.info(‘testLet=‘,testLet); // Uncaught ReferenceError: testLet is not defined
let testLet = 1;

这种过早访问 let 声明的引用导致的 ReferenceError 严格说叫做“暂时死亡区”(Temporal Dead Zone,TDZ)错误。这种情况下,使用 typeof 就会有问题。

console.info(typeof testVar);
console.info(typeof testLet);
var testVar = ‘123‘;
var testLet = 123; // Uncaught ReferenceError: testLet is not defined
  1. 同一作用域内,不允许重复声明同一个变量。
let testLet = 1;
let testLet = ‘123‘; // Uncaught SyntaxError: Identifier ‘testLet‘ has already been declared

同样在 for 循环中使用时:

function printNum() {
  var numArray = [];
  for(let i=0;i<5;i++) {
    numArray.push(function (){
      console.info(i);
    })
  }
  numArray[0]();
}
printNum(); // 0

for 循环头部的 let i 为每次循环都重新声明了一个变量 i。头部的声明是一个作用域,循环体内是另外一个单独的作用域。

for(let i=0;i<2;i++) {
  let i = ‘123‘;
  console.info(i);
}
// 123
// 123

const 声明

这种形式的声明,是用于创建常量。常量不是对这个值本身的限制,而是对赋值的那个变量的限制。变量实际是指向一个内存地址,const 就对这个内存地址所保存的数据进行了限制。对于简单的数据(例如数值、字符串、布尔值),值就保存在那个内存地址中,就等同于常量。如果复合类型的数据(例如数组和对象),内存地址中保存的就是一个指向实际数据的指针,const 保证的是这个指针固定,这个指针实际指向的内容就不能控制了。

const testConst = [1,2];
testConst.push(3);
console.info(testConst); // [1,2,3]

这种方式的特点有:

  1. let 一样,所在的代码块内有效。
{
  const TEST = "0.618";
}
console.info(TEST); // Uncaught ReferenceError: TEST is not defined
  1. 不会“变量提升”,要先声明且初始化后才能使用,否则会报错。同样存在“暂时死亡区”。
const K = 1.13198824;
console.info(K);
const TEST;
console.info(TEST);
// SyntaxError: Missing initializer in const declaration
  1. 同 let 一样,同一作用域内,不允许重复声明同一个变量。

选择那种方式?

在目前的工作中,发现使用 const 的频率非常高,一方面可能是由于使用 react 不可变数据,另一方面是听说 JavaScript 引擎在某些情况下对 const 进行了更好的优化。理论上说,引擎如果了解这个变量的值或类型不会改变,那么它就可以取消某些可能的追踪。实际到底有没有,这没有找到相关的信息。

在 stackoverflow 中也有类似的提问:Const in javascript? When to use it and is it necessary。还有一些文章中的描述,似乎想要用 const 来规范代码行为:必须要初始化。这种规范代码行为的方式感觉很奇怪,写代码很重要的一个功能就是清晰的表达你的意图,不仅仅对自己,也是对未来的维护者或合作者。可能有人觉得到时候如果要改数据,把 const 修改为 let 就可以了。这样也许可以达到目的,那么后来接手的人只要想修改数据,就把 const 修改为 let,这样子做真的好吗?

从代码的可读性和可理解性上,个人认同的方式是:当你想表明这个变量不会改变时才使用 const,这样更加合理。

参考资料

以上是关于JavaScript 新旧替换一:变量声明的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript 新旧替换六:键值对数据

javascript 中 replace 对变量进行全局替换

JavaScript 变量声明提升

深入理解javascript闭包

我可以在JavaScript中声明变量的位置

javascript变量声明提升(hoisting)