1. JS中的对象
JS 的对象是“动态的”,可以随时增删属性。
object是一个对象,在JS中可以通过object[key] = value,给object对象增加key属性。
const student = {};
student['name'] = '小明';// 或者 student.name = '小明';
console.log(student);
输出
{name: '小明'}
但是
const student = {};
student[name] = '小明';
console.log(student);
输出
{"": '小明'}//或者直接报错
因为student[name] = '小明';此时 name 是一个未定义的变量,而不是字符串。
2. var、let、const 在JS里的区别
1.作用域(scope)
var 是函数作用域(function-scoped)或全局(若在全局声明)。
let/const 是块级作用域(block-scoped),即 { ... } 之内。
function test() {
if (true) {
var a = 1;
let b = 2;
const c = 3;
}
console.log(a); // 1 —— var 在函数内可访问
console.log(b); // ReferenceError(引用错误): b is not defined
console.log(c); // ReferenceError: c is not defined
}
test();
2.提升(hoisting)与暂时性死区(TDZ)
JavaScript 执行代码前,引擎会先扫描整个作用域里的变量和函数声明。它会先“记住”有哪些变量或函数存在。这个过程叫 “提升”(Hoisting)。
所谓“提升”,意思是:
- 声明语句虽然写在后面,但在执行时, 它的“声明部分”会像被提前到作用域的最上方一样生效。
- 不是真的移动代码,只是引擎提前知道了变量的名字。
所以,在代码执行时,你可以在声明之前访问这个变量——
不过,不同的声明方式行为不同(这是重点!)。
区别
- var
console.log(a); // 输出: undefined
var a = 10;
解释:
引擎执行前,会先把这段代码“内部理解”为:
var a; // 声明被提前了(提升)
console.log(a);
a = 10; // 赋值依然在原来的地方
所以 console.log(a) 不会报错,但此时 a 还没赋值,是 undefined。
- let / const
console.log(b); // ReferenceError
let b = 20;
为什么这里报错?
let 和 const 也被提升了,但在它们真正执行到声明语句之前,会处于“暂时性死区 (TDZ)”。
在这段“死区”中,访问变量会直接报错(引擎禁止你使用未初始化的变量)。
- const 还要求声明时必须初始化。
3.重新赋值(re-assignment)与重新声明(re-declare)
- var:可以重新赋值,也可以在同一作用域重复声明(不会报错)。
- let:可以重新赋值,但不允许在相同作用域重复声明。
- const:不能重新赋值,且不能重复声明。必须在声明时初始化。
示例:
var a = 1;
var a = 2; // 合法
a = 3; // 合法
let b = 1;
// let b = 2; // SyntaxError: Identifier 'b' has already been declared
b = 2; // 合法
const c = 1;
// c = 2; // TypeError: Assignment to constant variable.
// const c = 3; // SyntaxError
4.const 与对象/数组(引用的可变性)
const 是对绑定(binding) 的限制:你不能把标识符重新绑定到另一个值,但如果值本身是对象/数组,其内部是可变的。
const obj = {x: 1};
obj.x = 2; // 合法 —— 修改对象属性
// obj = {x: 3}; // TypeError: Assignment to constant variable.
const arr = [1,2];
arr.push(3); // 合法
// arr = [4,5]; // TypeError
5. 全局对象行为(浏览器中的 window)
在全局作用域:
- var foo = ... 会成为 window.foo(浏览器环境)。
- let / const 不会创建 window 的属性(不会污染全局对象)。
var g = 1;
let h = 2;
console.log(window.g); // 1
console.log(window.h); // undefined
6.推荐实践
- 默认使用 const:多数变量不需要重新绑定,使用 const 能防错并表达意图。
- 需要修改时用 let:例如循环计数、累加器、可变状态。
- 避免使用 var:只有在你需要兼容非常旧的代码或特殊场景时才考虑。
- 注意 TDZ:不要在 let/const 声明前访问变量(会抛错)。
- 对象/数组也要留心可变性:若需要完全不可变结构,使用 Object.freeze 或不可变库。
3. JS中的作用域
作用域(Scope) 就是变量(或函数)在代码中的可访问范围。
你在哪能访问到这个变量?在哪访问不到?这就是由「作用域」决定的。
1.JavaScript 主要有 4 种作用域
| 作用域类型 | 关键字 | 举例 | 特点 |
|---|---|---|---|
| 1️⃣ 全局作用域(Global Scope) | — | 脚本最外层声明的变量 | 任何地方都能访问 |
| 2️⃣ 函数作用域(Function Scope) |
var, 函数声明 |
函数内部定义的变量 | 只在函数内可访问 |
| 3️⃣ 块级作用域(Block Scope) |
let, const
|
{ ... } 内定义的变量 |
只在花括号内可访问 |
| 4️⃣ 模块作用域(Module Scope) | ES Module |
import/export 文件内 |
只在当前模块文件有效 |
2.全局作用域
在最外层定义的变量(不在任何函数或块中)属于全局作用域。
var x = 10;
function show() {
console.log(x); // 可以访问
}
show();
console.log(x); // 也可以访问
全局作用域的变量在任何地方都能访问。
但要小心:污染全局命名空间。
浏览器里,全局变量会挂到 window 对象上:
var a = 1;
console.log(window.a); // 1
3.函数作用域(Function Scope)
每个函数都会创建自己的独立作用域。
function test() {
var y = 20;
console.log(y); // 函数内部可访问
}
test();
console.log(y); // ReferenceError
var 定义的变量在函数作用域内有效,外部无法访问。
4.块级作用域(Block Scope)
由 { ... } 包裹的区域,比如:
- if、for、while、switch 块
- 普通花括号 {}
在块级作用域内用 let 或 const 声明的变量,只在该块中有效。
{
let a = 1;
const b = 2;
var c = 3;
}
console.log(c); // 3
console.log(a); // ReferenceError
console.log(b); // ReferenceError
- var 不受块级作用域限制(只有函数作用域)。
- let 和 const 是真正的块级作用域变量。
5.模块作用域(Module Scope)
ES6 引入模块系统(.js 文件中使用 import / export)。
每个模块文件自动拥有独立作用域,模块间互不干扰。
// fileA.js
export const name = "Alice";
// fileB.js
import { name } from "./fileA.js";
console.log(name); // "Alice"
console.log(window.name); // ❌ undefined (不是全局变量)
模块作用域相当于一种“隔离的全局作用域”,不会污染 window。
6.作用域嵌套(Scope Chain)
作用域是可嵌套的:
const a = 1;
function outer() {
const b = 2;
function inner() {
const c = 3;
console.log(a, b, c); // ✅ 都能访问
}
inner();
}
outer();
查找规则:
当代码访问一个变量时,JavaScript 会:
- 先在当前作用域找;
- 找不到就往上层作用域(外层函数 / 全局)查;
- 一直找到全局为止;
- 若全都找不到 → 抛出 ReferenceError。
这个查找链条称为 “作用域链(Scope Chain)”。
Top comments (0)