视频加载失败

ES6初识和ES6变量

2492 字
12 分钟
ES6初识和ES6变量

ES6 简介#

ECMAScript 是语言的标准;6 是版本号;ES6 = ECMAScript 这门语言的第 6 代标准

什么是ECMAScript

是欧洲计算机制造商协会,一个标准化组织,ECMAScript 是 由 ECMA 这个标准化组织制定的一个语言标准

具体是什么

ECMAScript规定了语法和API,ECMAScript = 语法 + API

历史版本

  • ES1 ~ 3、ES5 ~ 6
  • ES4 被废弃了(太激进)
  • ES3:do while、switch、正则表达式等
  • ES5:forEach、map、filter、Object.create、Object.defineProperty 等

命名方式

  • ES6->ES7->ES8->… = ES6+
  • ES2015->ES2016->ES2017->…

ES 与 JavaScript 的关系

  • JavaScript(浏览器端) = ECMAScript(语法+API) + DOM + BOM
  • 主流浏览器的最新版本几乎全部支持 ES6
  • IE 老版本等不支持的浏览器,可以用 Babel 转码

ES6新增变量let 和 const#

let 和 const 是什么

  • let 用来声明可变变量。代替var
  • const 用来声明常量(不可重新赋值的变量)。

let 和 const 的用法

let基本用法

let name = "Alice";
name = "Bob"; // 可以重新赋值

const基本用法

const PI = 3.14;

什么是变量,什么是常量

  • var、let声明的就是变量,变量一旦初始化之后,还可以重新赋值
  • const声明的就是常量,一旦初始化,就不能重新赋值

const#

为什么需要 const

避免变量被误修改(防止 bug);如果只用 let / var,变量很容易被不小心改掉:

let PI = 3.14;
PI = 100; // ❌ 可能是误操作,但不会报错
const PI = 3.14;
PI = 100; // ❌ 直接报错,防止 bug

让代码语义更清晰(可读性更强);看到 const,别人就能立刻理解:这个值不会变

const API_URL = "https://api.example.com";
const MAX_COUNT = 10;
//相比let
let API_URL = "..."; // 不确定会不会变

降低维护成本(大型项目很重要);在大项目中:一个变量被多处引用,如果可以随意修改,很容易出错

const config = {...};// 防止重新赋值
let config = {...};// 多个地方可能修改 config

符合函数式编程思想;现代前端(React / Vue)倾向:数据尽量不可变(Immutable)

//不直接修改原数据,更安全
const list = [1, 2, 3];
const newList = [...list, 4];

提升性能优化空间:虽然 JS 引擎会优化很多情况,但不可变数据更容易优化,更少副作用

关键误区

const ≠ “完全不可变”;const 只限制:不能重新赋值(引用不能变)

const obj = { name: "Tom" };
obj.name = "Jerry"; // ✔ 可以

const 的注意事项

  • 一旦声明,就必须立即初始化,不能留到后面复制;
  • 使用const声明的常量允许在不重新赋值的情况下修改他的值(关键误区)

什么时候用let,什么时候需要使用const

  • let 和 const 的选择核心原则其实很简单:默认用 const,需要“重新赋值”时才用 let
  • 不会重新赋值的变量用const;引用类型(对象/数组)通常用 const,因为可以修改对象内容,不能整体重新赋值;配置、常量、固定数据用const; 函数 / 导入模块用const
  • 什么时候用 let(必须会变才用):值会变化的变量;循环变量;需要重新赋值的状态;条件赋值

let、const 与 var 的区别#

重复声明

var可以重复声明; let、const不允许重复声明

var a = 1;
var a = 2; // ✔ 不报错;容易出 bug
console.log(a); // 2
let a = 1;
let a = 2; // ❌ 报错
const a = 1;
const a = 2; // ❌ 报错
function fun(a){
let a = 1;//❌ 报错
}

变量提升

var存在变量提升,但值是 undefined;

console.log(a); // undefined
var a = 10;
//等价于
var a;
console.log(a);
a = 10;

let / const:也会提升,但不能访问;暂时性死区

console.log(a); // ❌ 报错
let a = 10;
console.log(b); // ❌ 报错
const b = 20;

这里的a已经被提升,但是未被初始化,此时处于暂时性死区,变量已经存在,但不能访问它的值,访问这些变量会导致ReferenceError错误

变量的声明周期:声明(在作用域内声明这个变量,此时变量已被标记为存在。)——- 初始化(在内存中为这个变量开辟一块空间,此时由于没有赋值,所以会初始化为undefined。) ——— 赋值(将值赋给这个变量。)

var: 在执行上下文执行之前的预解析阶段,会有声明提升,和初始化提升,这时js会把var存放在变量环境中(你可以简单理解为一个存放变量的地方,函数声明也会放在这个地方),且值为undefined,因此我们可以提前访问,结果为undefined。

let: 在执行上下文执行之前的预解析阶段,仅有声明提升,不会给它初始化,更不会给他赋值,此时存储中有这个变量,但我们无法访问。(let和const存放在词法环境中,你可以简单理解为另一个地方)这也就是所说的暂时性死区当执行到真正的赋值语句的时候,才会执行初始化操作并赋值。

const: 与let的创建顺序基本一致,仅有 声明提升,但非常重要的区别是const本身不存在赋值这一个概念,当执行到 const a = 2时,是直接将const初始化为2。也就是我们所说的const是常量。因为它根本无法赋值,也因此在声明时必须给它一个值。(相当于Promise内部状态只能修改一次,因为Promise源码里后续也没有为状态赋值的操作。) 而对于引用数据类型来说,const初始化的是一个栈内存里分配的指针。你虽然无法修改指针的指向,但可以修改指针指向的堆里面的内容,也就是我们所说的cosnt声明的引用数据类型可以更改。

作者:孙泓旻 链接:https://juejin.cn/post/7209939789808812093 来源:稀土掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

暂时性死区

只要作用域内存在let、const,它们所声明的变量或常量就自动”绑定”这个区域,不再受到外部作用域的影响

let a = 2;
let b = 4;
function fun() {
//console.log(a);//应为函数作用域绑定了a,所以没法往外找,报错
console.log(b); //相反,函数作用域内没找到b,就往外找
//let a = 1;
}
fun();

window 对象的属性和方法(全局作用域中)

var会挂到 window 上,全局污染问题

var a = 10;
console.log(window.a); // 10

let / const:不会挂到 window, 更安全,不污染全局对象

let a = 10;
const b = 20;
console.log(window.a); // undefined
console.log(window.b); // undefined

块级作用域

var没有块级作用域(只有函数作用域)

if (true) {
var a = 10;
}
console.log(a); // 10,if / for 里的变量“泄露”到外面
for (var i = 0; i < 3; i++) {
console.log(i);
}
console.log(i); //3

let / const:有块级作用域

if (true) {
let a = 10;
const b = 20;
}
console.log(a); // ❌ 报错
console.log(b); // ❌ 报错
for (let a = 0; a < 3; a++) {
console.log(a);
}
console.log(a); //❌ 报错

作用域链

let a = 1;
function foo() {
let b = 2;
function bar() {
let c = 3;
console.log(a); // ?1
console.log(b); // ?2
console.log(c); // ?3
}
bar();
}
foo();

查找过程(关键)

1️⃣ 找 c

在 bar 内部 → 直接找到

2️⃣ 找 b

bar 没有 → 去上一层 foo → 找到

3️⃣ 找 a

bar 没有 → foo 没有 → 去全局 → 找到

总结:函数定义时的作用域嵌套关系,而不是调用时决定的,访问变量时:先在当前作用域找,找不到 → 去上一级作用域,一直找到全局作用域,还找不到 → 报错 ReferenceError

常见误区:

  • 作用域链是运行时决定的;错!作用域链在函数定义时就已经确定
  • 跟 this 是一回事;完全不同:作用域链作用是找变量;this作用指向对象

总结

特性varletconst
重复声明✔ 可以❌ 不可以❌ 不可以
变量提升✔ 有(undefined)✔ 有(TDZ)✔ 有(TDZ)
暂时性死区❌ 没有✔ 有✔ 有
块级作用域❌ 没有✔ 有✔ 有
window属性✔ 会挂载❌ 不会❌ 不会

let 和 const 的应用#

示例:点击按钮1打印1,点击按钮2打印2,点击按钮3打印3

<button class="btn">1</button>
<button class="btn">2</button>
<button class="btn">3</button>
<script>
var btns = document.querySelectorAll('.btn');
for (var i = 0; i < btns.length; i++) {
btns[i].addEventListener('click', function () {
console.log(i); //都是3
});
}
</script>

为什么打印出来都是3?

因为点击的时候:for 循环已经执行完了,i 早就变成 3 了

拆解:

1️⃣ var 没有块级作用域

for (var i = 0; i < 3; i++) {}

等价于:

var i; // 只有一个 i

👉 只有一个共享的 i

2️⃣ addEventListener 里的函数“没有立即执行”

function () {
console.log(i);
}

👉 它只是“注册”,不是执行

3️⃣ 点击发生时才执行函数

当你真正点击时:

👉 for 循环早就结束了

i === 3

4️⃣ 作用域链在找 i

点击时执行函数:

console.log(i);

查找过程:

当前函数作用域 → 没有 i
外层作用域(for 所在函数 / 全局)→ i = 3

👉 所以打印 3

闭包方式解决:

<button class="btn">1</button>
<button class="btn">2</button>
<button class="btn">3</button>
<script>
var btns = document.querySelectorAll('.btn');
for (var i = 0; i < btns.length; i++) {
(function (index) {
btns[index].addEventListener('click', function () {
console.log(index + 1);
});
})(i);
}
</script>
  • 立即执行函数形成了函数作用域,这个函数作用域会保存这个index,当点击的时候触发点击事件,向外找这个index

正确示例:

<button class="btn">1</button>
<button class="btn">2</button>
<button class="btn">3</button>
<script>
var btns = document.querySelectorAll('.btn');
for (let i = 0; i < btns.length; i++) {
btns[i].addEventListener('click', function () {
console.log(i + 1);
});
}
</script>
  • let 在 for 循环中有一个特殊机制:每一轮循环,都会创建一个新的 i 绑定
  • let 的本质:形成多个闭包环境;每个循环

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

ES6初识和ES6变量
https://f.youzi177.cn/posts/2026102101es6-chu-shi-he-es6-bian-liang/
作者
小封鸭
发布于
2026-10-21
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
小封鸭
小楼一夜听春雨,深巷明朝卖杏花
公告
欢迎来到我的博客。这里主要记录前端全栈和日常内容
分类
标签
最新动态
站点统计
文章
60
分类
3
标签
12
总字数
107,734
运行时长
0 天
最后活动
0 天前
站点信息
构建平台
EdgeOne Pages
博客版本
Firefly v6.16.8
文章许可
CC BY-NC-SA 4.0
文章目录