变量
var 定义
定义一个变量
1 | var msg; |
定义但不初始化的情况,变量会保存一个特殊值
undefined
定义变量 并初始化
1 | var msg = "hello word"; |
像这样的初始化不会将变量标识为 字符串类型, 只是一个简单的复制, 你可以随时改变保存的值,也可以改变值的类型
1 | var msg = "hello"; |
定义多个变量
声明多个变量可用 ,
号分割每个变量 (可选是否初始化)
1 | // 定义 |
var 作用域
var 定义的变量会成为包含它的函数所属的局部变量**
1 | function test(){ |
这里的
msg
变量 为test
函数内部 使用var
定义的. 调用test
函数 会创建msg
这个变量并给它赋值,调用后变量即被销毁,所以 在 函数外部调用msg
这个变量会导致错误
函数内部定义变量时省略 var
操作符 可以创建一个全局变量
1 | function test(){ |
去掉
var
操作符后,msg
就变成了全局变量, 只要调用一次 test() 就会定义这个变量, 并且可以在 函数外部访问注意:
不要这样定义全局函数,很容易遗漏!!!!
不要这样定义全局函数,很容易遗漏!!!!
不要这样定义全局函数,很容易遗漏!!!!
在严格模式下.如果给这样未声明的变量赋值,会抛出
ReferenceError
错误
var 声明提升
使用 var
关键词 声明的变量会自动提升到函数作用域顶部,所以下面书写的代码不会报错
1 | function test(){ |
之所以不会报错, 是因为 ECMAScript
运行时会把它看成等价于如下代码
1 | function test(){ |
这就是所谓的
提升(hoist)
, 也就是把所有变量声明都啦到函数作用域顶部
反复多次使用 var 声明同一个变量也没问题
运行时 变量结果会读取最后一次赋值
1 | function test(){ |
let 声明
let
和 var
的区别是 let
声明的范围是 块作用域
,而 var
声明的范围是 函数作用域
1 | function test(){ |
1 | function test2(){ |
使用
let
定义的变量不能再if
块 外部被引用, 是因为它的作用域限于该块的内部块作用域是函数作用域的子集, 因此
var
的作用域限制同样也适用于let
let
也不允许在同一个块作用域
内重复声明遍变量
1 | let age; |
let
和 var
嵌套使用示例:
1 | var name = "zhangsan"; |
javascript 引擎会记录用于变量声明的标识符和其所在的块作用域, 因此嵌套的标识符不会报错,而是因为同一个块中没有重复声明
let
和 var
这两个关键词声明的并不是不同类型的变量,它们只是指出变量在相关作用域如何存在
1 | var name; |
let
和 var
的区别
暂时性死区
let
和 var
的另一个重要的区别, 就是 let
声明的变量不会在作用域中被提升
1 | // name 会背提升 |
在解析代码时, JavaScript 引擎也会注意出现在块后面的
let
声明, 只不过在此之前不能以任何方式来引用未声明的变量在 let 声明前的执行瞬间被称为
暂时性死区(temporal dead zone)
, 所以 在此阶段引用任何后面才声明的变量则会抛出 ReferenceError使用 let声明变量 必须要按照 先声明 后使用的原则!
使用 let声明变量 必须要按照 先声明 后使用的原则!
使用 let声明变量 必须要按照 先声明 后使用的原则!
全局声明
与 var
关键词不同, 使用 let
在全局作用域中声明的变量 不会成为 window
对象的属性 (var
声明的变量则会)
1 | var name = "张三"; |
不过, let 声明任然是在全局作用域中发生的, 相应变量会在页面的生命周期内存续, 因此, 为了避免 SyntaxError , 必须要保证页面不会重复声明同一个变量
声明条件
使用 var
声明变量时, 由于声明会被提升, JavaScript 引擎会自动将多余的声明在作用域顶部合并为一个声明.
因为 let 的作用域是块 ,所以不可能检查前面是否使用的 let 声明过同名变量也就不可能在没有声明的情况下声明它
1 | <script> |
使用 try/catch 语句 或 typeof 操作符也不能解决, 因为 条件块中 let 声明的作用域 仅限于 该块.
1 | <script> |
for 循环中的 let 声明
在 let 出现前 , for 循环定义的迭代变量 会渗透到循环体外部
1 | for(var i; i < 5; i++){ |
改用 let 之后,这个问题就消失了, 因为 迭代变量的作用域仅限于 for 循环块内部
1 | for(let i;i < 5; i++){ |
在使用 var 的时候,最常见的问题就是对迭代变量的奇特声明和修改
1 | for (var i;i<5; i++){ |
之所以这样 是因为在退出循环时, 迭代变量保存的是导致循环退出的值 : 5 , 在之后的执行超市逻辑时, 所有的 i 都是同一个变量,因而输出的都是同一个最终值
使用 let 迭代变量时, JavaScript 引擎在后台会为每一个迭代循环声明一个新的迭代变量
每个 setTimeout 引用的都是不同的变量实例, 所以 console.log 输出的是我们期望的值,也就是循环过程中每个迭代变量的值
1 | for(let i; i < 5; i++){ |
这种迭代声明一个独立变量实例的行为适用于所有风格的 for 循环, 包括 for-in 和 for-of 循环
const 声明
const
的行为与 let
基本相同, 唯一一个重要的区别就是 用 const
来声明变量时必须同时初始化变量,且 尝试修改 const
声明的变量会导致运行时错误
1 | const age = 11; |
const 声明的限制只适用于它指向的变量的引用,换句话说, 如果 const 变量引用的是一个对象, 那么修改这个对象内部的属性并不违反 const 的限制
1 | const person = {}; |
JavaScript 引擎会为 for 循环中的 let 声明分别创建独立的变量实例, 虽然 const 变量 和 let 变量 很相似, 但是不能用 const 来声明迭代变量 (因为迭代变量会自增)
1 | for (const i = 0; i < 10; ++i) {} // TypeError:给常量赋值 |
不过,如果你只想用 const 声明一个不会被修改的 for 循环变量,那也是可以的。也就是说,每次迭代只是创建一个新变量。这对 for-of 和 for-in 循环特别有意义
1 | let i = 0; |
在 for 循环块作用域中,只是使用 const 声明变量,不重复赋值也是可以用的
所谓特别的意义
const 的作用域仅限于 块,那么 可以在 for 作用域中 用 const 来声明变量,达到不反复开辟内存的作用
声明风格及最佳实践
ECMAScript 6
增加 let 和 const 从客观上为这门语言更精准的声明作用域和语义提供了更友好的支持,行为怪异的 var 所造成的各种问题 已经让 JavaScript 社区为之苦恼很多年, 随着这两个新关键词的出现, 新的 有助于提升代码质量的最佳实践也逐渐显现,
1, 不使用 var
有了 let 和 const , 大多数开发者会发现自己不再需要 var 了, 限制自己只使用 let 和 const 有助于提升代码质量, 因为变量有了明确的作用域, 声明位置, 以及不变的值
2, const 优先, let 次之
使用 const 声明可以让浏览器运行时强制保持变量不变, 也可以让静态代码分析工具提前发现不合法的赋值操作. 因此 很多开发者认为应该优先使用 const 来声明变量, 只在前提知道未来会有修改时,再使用 let ,这样可以让开发者更有信心的推断某些变量的值永远不会变, 同时也能迅速发现因为意外赋值导致的非预期行为
- 本文标题:javascript 变量详解
- 本文作者:mr00ff
- 创建时间:2021-06-18 16:48:22
- 本文链接:https://www.sysxo.com/javascript/javascript变量.html
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!