JavaScript 变量声明/赋值

发布于 2024-07-13 05:54:09 字数 3839 浏览 15 评论 0

声明

6 种声明

至今为止,除标签声明之外,JavaScript 中一共只有六条声明用的语句。注意,所有真正被定义“声明”的语法结构都一定是“语句”,并且都用于声明一个或多个标识符。这里的标识符包括变量、常量等。

严格意义上讲,JavaScript 只有变量和常量两种标识符,六条声明语句中:

  • let x … 声明变量 x。不可在赋值之前读。
  • const x … 声明常量 x。不可写。
  • var x … 声明变量 x。在赋值之前可读取到 undefined 值。
  • function x … 声明变量 x。该变量指向一个函数。
  • class x … 声明变量 x。该变量指向一个类(该类的作用域内部是处理严格模式的)。
  • import … 导入标识符并作为常量(可以有多种声明标识符的模式和方法)。

除了这六个语句之外,还有两个语句有潜在的声明标识符的能力,不过它们并不是严格意义上的声明语句(声明只是它们的语法效果)。

这两个语句是指:

  • for (var|let|const x …) … for 语句有多种语法来声明一个或多个标识符,用作循环变量。
  • try … catch (x) …catch 子句可以声明一个或多个标识符,用作异常对象变量。

标识符

let x

x 就是一个标识符

function fn(){
  let x=2
}
  1. 在 Parser 工作阶段,Parser 需要确定 fn 作用域情况,所以它会询问当前作用域有无 x 这个变量,没有的话就会把该变量添加到作用域中
  2. 在 fn 执行前的创建上下文阶段,会【声明/创建】变量 x
  3. 执行函数 fn,对其进行赋值

变量声明在引擎的处理(存疑)

变量声明在引擎的处理上被分成两个部分:一部分是静态的、基于标识符的词法分析和管理,我们称之为声明标识符,它总是在相应上下文的环境构建时作为名字创建的,我们称之为创建标识符,注意;另一部分是表达式执行过程,是对上述名字的赋值,这个过程也称为绑定。

var 的初始化

var y = "outer";
function f() {
  console.log(y); // undefined
  console.log(x); // throw a Exception
  let x = 100;
  var y = 100;
}

正是由于 var y 所声明的那个标识符在函数 f() 创建(它自己的闭包)时就已经存在,所以才阻止了 console.log(y) 访问全局环境中的 y。类似的,let x 所声明的那个 x 其实也已经存在 f() 函数的上下文环境中。访问它之所以会抛出异常(Exception),不是因为它不存在,而是因为这个标识符被拒绝访问了

在 ECMAScript 6 之后出现的 let/const 变量在“声明(和创建)一个标识符”这件事上,与 var 并没有什么不同,只是 JavaScript 拒绝访问还没有绑定值的 let/const 标识符而已。

回到 ECMAScript 6 之前:JavaScript 是允许访问还没有绑定值的 var 所声明的标识符的。这种标识符后来统一约定称为“变量声明(varDelcs)”,而“let/const”则称为“词法声明(lexicalDecls)”。>

对于“变量声明(varDelcs)”,函数的上下文环境在创建一个“变量名”后,会为它初始化绑定一个 undefined 值,再执行代码。而”词法名字(lexicalNames)”在创建之后就没有这项待遇(直到执行代码后才初始化为 undefined),所以它们在缺省情况下就是“还没有绑定值”的标识符。

var,function,let 的创建、初始化和赋值

我用了两个月的时间才理解 let 的总结

注意下面没有提到变量的【声明】

var 声明的「创建、初始化和赋值」过程

function fn(){
  var x = 1
  var y = 2
}
fn()

在执行 fn 时,会有以下过程(不完全):

  1. 进入 fn,为 fn 创建一个环境。
  2. 找到 fn 中所有用 var 声明的变量,在这个环境中「创建」这些变量(即 x 和 y)。
  3. 将这些变量「初始化」为 undefined。
  4. 开始执行代码
  5. x = 1 将 x 变量「赋值」为 1
  6. y = 2 将 y 变量「赋值」为 2

function 声明的「创建、初始化和赋值」过程

fn2()
function fn2(){
  console.log(2)
}

JS 引擎会有以下过程:

  1. 找到所有用 function 声明的变量,在环境中「创建」这些变量。
  2. 将这些变量「初始化」并「赋值」为 function(){ console.log(2) }。
  3. 开始执行代码 fn2()

也就是说 function 声明会在代码执行之前就「创建、初始化并赋值」。

let 声明的「创建、初始化和赋值」过程

{
  let x = 1
  x = 2
}

我们只看 {} 里面的过程:

  1. 找到所有用 let 声明的变量,在环境中「创建」这些变量
  2. 开始执行代码(注意现在还没有初始化)
  3. 执行 x = 1,将 x 「初始化」为 1(这并不是一次赋值,如果代码是 let x,就将 x 初始化为 undefined)
  4. 执行 x = 2,对 x 进行「赋值」

const 声明的「创建、初始化」过程

const 只有「创建」和「初始化」,没有「赋值」过程。

{
  console.log(x)
  const x = 1
}

我们只看 {} 里面的过程:

  1. 找到所有用 let 声明的变量,在环境中「创建」这些变量
  2. 开始执行代码,将 x 「初始化」为 1

总结

  • let 的「创建」过程被提升了,但是初始化没有提升。
  • var 的「创建」和「初始化」都被提升了。
  • function 的「创建」「初始化」和「赋值」都被提升了。

赋值

如果是在一门其它的(例如编译型的)语言中,为变量 x 绑定一个初值 就可能实现为“ 在创建环境时将变量 x 指向一个特定的初始值。这通常是静态语言的处理方法,然而,如前面说过的,JavaScript 是门动态的语言,所以它的 绑定初值 的行为是通过动态的执行过程来实现的,也就是赋值操作。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

寄意

暂无简介

文章
评论
28 人气
更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文