JavaScript三大变量声明详析

目录
  • 前言
  • Var
    • 基础写法
      • 声明未定义值
      • 声明定义值
      • 不推荐写法
    • var 声明作用域
      • 局部作用域
      • 全局作用域
      • 便捷语法
    • var 声明提升
  • Let
    • let 作用域
      • 冗余声明
    • 暂时性死区
    • 全局声明
    • 条件声明
    • for 循环中的 let
      • 常见for循环
      • for循环套定时器
  • const
    • const 限制
    • for 循环中的 const
  • 声明风格及最佳实践
  • 总结

前言

ECMAScript 变量是松散类型的,变量可以用于保存任何类型的数据,每个变量只不过是一个用于保存任意值的命名占位符。

本文主要讲述 Javascript 中三大变量声明的用法与写法,有 3 个关键字可以声明变量:varconst 和 let。其中,var 在ECMAScript 的所有版本中都可以使用,而 const 和 let 只能在 ECMAScript 6 及更晚的版本中使用。(现在最新版为 ECMAScript 12

Var

var 操作符用于定义变量(var 也是一个关键字),后跟变量名(即标识符)

基础写法

声明未定义值

这里定义了一个名为test的变量,可以用它保存任何类型的值

 var test;

注意: 不初始化的情况下,变量会保存一个特殊值 undefined

声明定义值

ECMAScript 实现变量初始化,因此可以同时定义变量并设置它的值,如下:

 // 声明定义值
 var test = "good job"; 

像这样的初始化变量不会将它标识为字符串类型,随时可以改变保存的值,从而改变值的类型。

不推荐写法

在下面这个例子中,变量 test 首先被定义为一个保存字符串值的变量,然后又被重写为保存了数值:

 var test = "good job";  
 test = 299;  //合法,但不推荐
 /* 像这种单独的变量可以直接赋值就没必要另起去改了 没必要 */

虽然不推荐改变变量保存值的类型,但这在 ECMAScript 中是完全有效的。

var 声明作用域

使用 var 定义的变量会成为包含它的函数的局部变量,简称为作用域变量。

局部作用域

使用 var 在一个函数内部定义一个变量,就意味着该变量将在函数退出时被销毁,如下:

 function fun() {
  var test = "Hello World"; // 局部变量
 }
 fun();
 console.log(test); // 出错!

这里,test 变量是在函数内部使用 var 定义的,函数为 fun(),调用它会创建这个变量并给它赋值;调用之后变量随即被销毁,因此示例中的最后一行会导致错误。

全局作用域

在函数内定义变量时省略 var 操作符,可以创建一个全局变量,如下

 function fun() {
  test = "Hello World"; // 局部变量
 }
 fun();
 console.log(test); // "Hello World"

去掉之前的 var 操作符之后,test 就变成了全局变量;只要调用一次函数 fun(),就会定义这个变量,并且可以在函数外部访问到。

注意:虽然可以通过省略 var 操作符定义全局变量,但不推荐这么做。

在严格模式下,如果像这样给未声明的变量赋值,则会导致抛出 ReferenceError。

便捷语法

如果需要定义多个变量,可以在一条语句中用逗号分隔每个变量(及可选的初始化),如下:

 var name = "hey~~",
     name = "shrimpsss",
     age = 99;

这里定义并初始化了 3 个变量,因为 ECMAScript 是松散类型的,所以使用不同数据类型初始化的变量可以用一条语句来声明; 虽然插入换行和空格缩进并不是必需的,但这样有利于阅读理解。

注意: 在严格模式下,不能定义名为 eval 和 arguments 的变量,否则会导致语法错误。

var 声明提升

var 这个关键字在函数中声明变量时会自动提升到函数作用域顶部,如下:

 function foo() {
  console.log(age);
  var age = 26;
 }
 foo(); // undefined 

之所以不会报错,是因为 ECMAScript 运行时把它看成等价于如下代码:

 function foo() {
  var age;
  console.log(age);
  age = 26;
 }
 foo(); // undefined 

这就所谓的“提升”(hoist),也就是把所有变量声明都拉到函数作用域的顶部。

Let

let 跟 var 的作用差不多,但 let 声明的范围是块作用域(var 声明的范围是函数作用域)

块作用域是函数作用域的子集,因此适用于 var 的作用域限制同样也适用于 let

let 作用域

let 作用域只能在块作用域里访问,不能跨块访问,也不能跨函数访问

两者的对比会更加凸显不一,如下:

 // --- var ---
 if (true) {
  var name = 'king';
  console.log(name); // Matt
 }
 console.log(name); // Matt
 ​
 // --- let ---
 if (true) {
  let age = 26;
  console.log(age); // 26
 }
 console.log(age); // ReferenceError: age 没有定义

在这里,age 变量之所以不能在 if 块外部被引用,是因为它的作用域仅限于该块内部。

冗余声明

let 不允许同一个块作用域中出现冗余声明

 var name;
 var name;
 let age;
 let age; // SyntaxError;标识符 age 已经声明过了

冗余声明的报错不会因混用 let 和 var 而受影响。

这两个关键字声明的并不是不同类型的变量,它们只是指出变量在相关作用域如何存在,如下:

 var name;
 let name; // SyntaxError
 let age;
 var age; // SyntaxError

JavaScript 引擎会记录用于变量声明的标识符及其所在的块作用域,因此嵌套使用相同的标识符不会报错。

暂时性死区

let 与 var 的另一个重要的区别,就是 let 声明的变量不会在作用域中被提升

 // name 会被提升
 console.log(name); // undefined
 var name = 'vito';
 ​
 // age 不会被提升
 console.log(age); // ReferenceError:age 没有定义
 let age = 26

在解析代码时,JavaScript 引擎也会注意出现在块后面的 let 声明,只不过在此之前不能以任何方式来引用未声明的变量。

在 let 声明之前的执行瞬间被称为“暂时性死区”(temporal dead zone),在此阶段引用任何后面才声明的变量都会抛出 ReferenceError

全局声明

与 var 关键字不同,使用 let 在全局作用域中声明的变量不会成为 window 对象的属性

 /* window.xx:在window对象中查找此属性(元素)*/
 var name = 'vito';
 console.log(window.name); // 'vito'
 ​
 let age = 26;
 console.log(window.age); // undefined

但 let 声明仍然是在全局作用域中发生的,所以相应变量会在页面的生命周期内存续。

条件声明

因为 let 的作用域是块,所以不可能检查前面是否已经使用 let 声明过同名变量,同时也就不可能在没有声明的情况下声明它,没有与var 一样的声明提升。

 /* 方便理解: 把两个<script>代码块看做一个代码块 */
 ​
 <script>
  var name = 'Nicholas';
  let age = 26;
 </script>
 ​
 <script>
  // 假设脚本不确定页面中是否已经声明了同名变量
  // 那它可以假设还没有声明过
  var name = 'Matt';
  // 这里没问题,因为可以被作为一个提升声明来处理
  // 不需要检查之前是否声明过同名变量
  let age = 36;
  // 如果 age 之前声明过,这里会报错
 </script>

为此, let 这个新的 ES6 声明关键字,不能依赖条件声明模式

注意: let 不能进行条件式声明是件好事,因为条件声明是一种反模式,它让程序变得更难理解

for 循环中的 let

在 let 出现之前,for 循环定义的迭代变量会渗透到循环体外部。

常见for循环

如下,用 var 示例:

 for (var i = 0; i < 5; ++i) {
  // 循环逻辑
 }
 console.log(i); // 5 

改成使用 let 就不会有这个问题了,因为 let 迭代变量的作用域仅限于 for 循环块内部:

 for (let i = 0; i &lt; 5; ++i) {
  // 循环逻辑
 }
 console.log(i); // ReferenceError: i 没有定义
复制代码

for循环套定时器

在使用 var 的时候,最常见的问题就是对迭代变量的奇特声明和修改,如下:

 for (var i = 0; i < 5; ++i) {
  setTimeout(() => console.log(i), 0)
 }
 // 实际上会输出 5、5、5、5、5 

怎么样,是不是以为会输入 0、1、2、3、4 ?

之所以会这样,是因为在退出循环时,迭代变量保存的是导致循环退出的值:5。在之后执行超时逻辑时,所有的 i 都是同一个变量,因而输出的都是同一个最终值。

而在使用 let 声明迭代变量时,JavaScript 引擎在后台会为每个迭代循环声明一个新的迭代变量

 for (let i = 0; i < 5; ++i) {
  setTimeout(() => console.log(i), 0)
 }
 // 会输出 0、1、2、3、4 

每个 setTimeout 引用的都是不同的变量实例,所以 console.log 输出的是我们期望的值,也就是循环执行过程中每个迭代变量的值。

这种每次迭代声明一个独立变量实例的行为适用于所有风格的 for 循环,包括 for-in 和 for-of循环。

const

const跟 let 的行为差不多,但区别是用它声明变量时必须同时初始化变量,且尝试修改 const 声明的变量会导致运行时错误(一致性)

const 限制

  • const 不可改值
 const age = 26;
 age = 36; // TypeError
  • const 也不允许重复声明
 const name = 'Lisa';
 const name = 'Vito'; // SyntaxError
  • const 声明的作用域也是块
 const name = 'apple';
 if (true) {
  const name = 'avocado';
 }
 console.log(name); // apple 

const 声明的限制只适用于它指向的变量的引用。 换句话说,如果 const 变量引用的是一个对象,那么修改这个对象内部的属性并不违反 const 的限制,如下:

 const person = {};
 person.name = 'vito'; // ok 

怎么样,是不是很神奇 o( ̄▽ ̄)d

for 循环中的 const

JavaScript 引擎会为 for 循环中的 let 声明分别创建独立的变量实例,虽然 const 变量跟 let 变量很相似,但是不能用 const 来声明迭代变量(因为迭代变量会自增):

 for (const i = 0; i < 10; ++i) {}  // TypeError 类型错误

不过,如果你只想用 const 声明一个不会被修改的 for 循环变量,那也是可以的。

每次迭代只是创建一个新变量,这对 for-of 和 for-in 循环特别有意义的,如下:

 let i = 0;
 for (const j = 7; i < 5; ++i) {
  console.log(j);
 }
 // 7, 7, 7, 7, 7
 ​
 for (const key in {a: 1, b: 2}) {
  console.log(key);
 }
 // a, b
 ​
 for (const value of [1,2,3,4,5]) {
  console.log(value);
 }
 // 1, 2, 3, 4, 5 

声明风格及最佳实践

ECMAScript 6 增加 let 和 const 为这门语言更精确地声明作用域和语义提供了更好的支持

  • 不使用 var

有了 let 和 const,大多数开发者会发现自己不再需要 var 了。限制自己只使用 let 和 const 有助于提升代码质量,因为变量有了明确的作用域、声明位置,以及不变的值。

  • const 优先,let 次之

使用 const 声明可以让浏览器运行时强制保持变量不变,也可以让静态代码分析工具提前发现不合法的赋值操作。因此,应该优先使用 const 来声明变量,只在提前知道未来会有修改时,再使用 let。

总结

  • ECMAScript 变量是松散类型的,变量可以用于保存任何类型的数据
  • var 定义的变量,没有块的概念,可以跨块访问, 不能跨函数访问。
  • let 定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问。
  • const用来定义常量,使用时必须初始化(即必须赋值),只能在块作用域里访问,而且不能修改。
  • 对于 let 与 const 同一个变量只能使用一种方式声明,不然会报错
  • 定义变量优先使用 const ,次之 let,养成良好代码规范

到此这篇关于JavaScript三大变量声明详析的文章就介绍到这了,更多相关JS变量声明内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • JavaScript 声明私有变量的两种方式

    前言 JavaScript并不像别的语言,能使用关键字来声明私有变量. 我了解的JavaScript能用来声明私有变量的方式有两种,一种是使用闭包,一种是使用WeakMap. 闭包 闭包的描述有很多种,比如: 能访问其它函数作用域的函数: 内部函数访问外部函数作用域的桥梁: ...... 使用闭包构建私有变量的逻辑在于: 1.在外部函数中声明变量和内部函数: 2.使用内部函数访问或者修改变量值: 3.在外部函数内返回内部函数: function outside(){ let val = 123;

  • javascript 变量声明 var,let,const 的区别

    目录 作用域(Scope)是什么 var 声明 提升(Hoisting) let 声明 const 声明 作用域(Scope)是什么 作用域是程序的执行环境,它包含在当前位置可访问的变量和函数.在 ES5 语法中,有全局作用域和局部作用域,ES6 则新增了块级作用域. 全局作用域是最外层的作用域,在函数外面定义的变量属于全局作用域,可以被任何其他子作用域访问.在浏览器中,window 对象就是全局作用域.在编写前端代码过程中,其中有一条优化规则就是少使用全局变量,因为全局变量容易导致程序BUG,

  • JavaScript的变量声明与声明提前用法实例分析

    本文实例讲述了JavaScript的变量声明与声明提前用法.分享给大家供大家参考,具体如下: JavaScript的变量声明 JavaScript的变量声明语句无论出现在何处,都会先于其他代码首先被执行.使用var关键词声明变量的作用域是当前的执行上下文,有可能是外围函数,或者,当变量声明在函数体之外时,则为全局变量. 向一个未声明变量赋值会隐式地将其创建为一个全局变量(它变成了全局对象的一个属性).声明变量与未声明变量之间的区别为: 1. 声明变量的作用范围限定在其执行的上下文环境中.未声明的

  • 详解js中let与var声明变量的区别

    ES6 新增了let命令,用来声明局部变量,所声明的变量,只在let命令所在的代码块内有效,而且有暂时性死区的约束. 1.ES6可以用let定义块级作用域变量 代码如下: function f1(){ { var a = 10; let b = 20; } console.log(a); // 10 console.log(b); // Uncaught ReferenceError: b is not defined } f1(); 说明:在ES6之前只有全局作用域和函数作用域,在ES6中新增

  • js变量声明var使用与不使用的区别详解

    一.区分显示的声明与隐式声明(var) JS中变量声明分显式声明和隐式声明. var name = 'muzidigbig';//显示声明 name = 'muzidigbig';//隐式声明(为全局变量的一个属性) 在函数中使用var关键字进行显式声明的变量是做为局部变量,在全局范围内声明的变量为全局变量:而没有用var关键字,使用直接赋值方式声明的是全局变量(全局对象属性). // name = 'muzidigbig';//隐式声明(为全局变量的一个属性) console.log(name

  • JavaScript进阶(一)变量声明提升实例分析

    本文实例讲述了JavaScript变量声明提升.分享给大家供大家参考,具体如下: 如下代码输出的结果是? var num = 123; function foo1(){ console.log( num ); //undefined var num = 456; console.log( num ); //456 } foo1(); Javascript代码执行分为两个大步: 预解析的过程 代码的执行过程 1.预解析与变量声明提升 程序在执行过程中,会先将代码读取到内存中检查,会将所有的声明在此

  • JavaScript中的变量声明你知道吗

    目录 变量 (一)var 1)关于var声明的变量的作用域 2)var声明提升(hoist) (二)let 1)与var不同,let声明的变量不会再作用域中被提升,这一现象被称为“暂时性死区” 2)全局声明 (三)Const 总结 变量 ECMAScript中,变量可以保存任何类型的数据(既可以是字符串也可以是数组也可以是别的……),也即“松散的”,变量只是一个用来区分的占位符,一共有var.const.let三个关键字用于声明变量(var在ECMAScrip所有版本可用,后两个只在ES6及以后

  • Javascript变量函数声明提升深刻理解

    目录 前言: 变量提升 函数提升 为什么要提升? 最佳实践 总结 前言: Javascript变量函数声明提升(Hoisting)是在 Javascript 中执行上下文工作方式的一种认识(也可以说是一种预编译),从字面意义上看,“变量提升”意味着变量和函数的声明会在物理层面移动到代码的最前面,在代码里的位置是不会动的,而是在编译阶段被放入内存中会和代码顺序不一样.变量函数声明提升虽然对于实际编码影响不大,特别是现在ES6的普及,但作为前端算是一个基础知识,必须掌握的,是很多大厂的前端面试必问的

  • JavaScript三大变量声明详析

    目录 前言 Var 基础写法 声明未定义值 声明定义值 不推荐写法 var 声明作用域 局部作用域 全局作用域 便捷语法 var 声明提升 Let let 作用域 冗余声明 暂时性死区 全局声明 条件声明 for 循环中的 let 常见for循环 for循环套定时器 const const 限制 for 循环中的 const 声明风格及最佳实践 总结 前言 ECMAScript 变量是松散类型的,变量可以用于保存任何类型的数据,每个变量只不过是一个用于保存任意值的命名占位符. 本文主要讲述 Ja

  • JavaScript中变量声明有var和没var的区别示例介绍

    本文来论述JavaScript中变量声明有var和没var的区别,关于Js中的变量声明的作用域是以函数为单位,所以我们经常见到避免全局变量污染的方法是 (function(){ // ... })(); 在函数内部,有var和没var声明的变量是不一样的.有var声明的是局部变量,没var的,声明的全局变量,所以可以借此向外暴露接口东东. 在全局作用域内声明变量时,有var 和没var看起来都一样,我们知道,声明的全局变量,就是window的属性,究竟是否一样,我们通过ECMAScrpit5提供

  • JavaScript变量声明详解

    定义在函数体外的都属于全局变量,定义在函数体内的属于局部变量.这里的定义是指通过var声明的. JavaScript有隐含的全局概念,意味着你不声明的任何变量都会成为一个全局对象属性.例如: 复制代码 代码如下: function test(){     myname = "huming";     alert(myname); } test(); // "huming" alert(myname); //"huming" 两个结果是一样的,说明

  • JavaScript的变量声明提升问题浅析(Hoisting)

    一.变量声明提升 hoisting 英['hɔɪstɪŋ] 美['hɔɪstɪŋ] n. 起重,提升 v. 把-吊起,升起( hoist的现在分词 ) 先来看一个栗子 var cc = 'hello'; function foo(){ console.log(cc); var cc = 'world'; console.log(cc); } foo(); console.log(cc); 这里将会输出 undefined.'world' .'hello' 此处主要有两个知识点: 1.作用域 2.

  • JavaScript私有变量实例详解

    本文实例讲述了JavaScript私有变量.分享给大家供大家参考,具体如下: 任何在函数中定义的变量,就是私有变量,因为这些变量在函数外部是无法访问到的.总的来说,私有变量包括函数的参数.局部变量和在函数内部定义的其他函数. function add(num1, num2){ var sum = num1 + num2; return sum; } 上面的例子中的 num1, num2, sum 就是函数的私有变量. 如果在这个函数内部创建一个闭包,那么闭包通过自己的作用域链也可以访问这些变量,

  • JavaScript变量声明的var、let、const详解

    目录 前言 内容 JavaScript的变量声明 var的变量声明 变量声明在函数作用域中 变量重复声明 变量声明提升 怪异危险的var let和const的变量声明 块级作用域 不可重复声明 暂时性死区 使用好let和const 总结 参考资料 前言 一个程序语言在运行的过程中,变量的声明在整个程序的生命周期中,是不断在进行的过程.任何程序的计算都会涉及至少一个变量,而计算的结果的则可能会涉及到另外的一个或者多个变量.变量在使用前是要声明,变量声明的过程在计算机的底层,牵涉到的是内存空间和内存

  • 一个JavaScript变量声明的知识点

    上周四吃完午饭,leader发了一道JavaScript的题目给我们做,我们Team里面有做前端的,有做后台的,也有坐mobile web的,所以大家对题目的理解各自都不一样,然后在QQ讨论组里面进行讨论.发现虽然很基础,但是通过讨论收获不少,分享出来.当然在有开发经验的开发者看来,这些都是学习JavaScript最基础的东西.因为平时都是用jQuery或者第三JS组件,所以对JavaScript基础学习不够重视.题目如下,问题是:2次alert分别输出什么结果? 复制代码 代码如下: <scr

  • 最通俗易懂的javascript变量提升详解

    如下所示: a = 'ghostwu'; var a; console.log( a ); 在我没有讲什么是变量提升,以及变量提升的规则之前, 或者你没有学习过变量提升,如果按照现有的javascript理解, 对于上述的例子,你可能会认为第3行代码的输出结果应该是undefined, 因为第二行是var a; 声明变量,但是没有赋值,所以a的值是undefined, 但是正确的结果是ghostwu. 至于为什么,请继续往下看! console.log( a ); var a = 'ghostw

随机推荐