惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
CERT Recently Published Vulnerability Notes
U
Unit 42
T
The Blog of Author Tim Ferriss
H
Hackread – Cybersecurity News, Data Breaches, AI and More
B
Blog RSS Feed
Microsoft Azure Blog
Microsoft Azure Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
S
Securelist
L
Lohrmann on Cybersecurity
Blog — PlanetScale
Blog — PlanetScale
Recorded Future
Recorded Future
D
DataBreaches.Net
Spread Privacy
Spread Privacy
T
Threat Research - Cisco Blogs
I
Intezer
P
Palo Alto Networks Blog
Simon Willison's Weblog
Simon Willison's Weblog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
I
InfoQ
宝玉的分享
宝玉的分享
Security Latest
Security Latest
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
T
Threatpost
Cisco Talos Blog
Cisco Talos Blog
P
Proofpoint News Feed
博客园 - 司徒正美
H
Hacker News: Front Page
Y
Y Combinator Blog
爱范儿
爱范儿
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
NISL@THU
NISL@THU
月光博客
月光博客
有赞技术团队
有赞技术团队
Cloudbric
Cloudbric
酷 壳 – CoolShell
酷 壳 – CoolShell
G
Google Developers Blog
A
Arctic Wolf
博客园 - 【当耐特】
W
WeLiveSecurity
V
Visual Studio Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
V
V2EX
C
Cyber Attacks, Cyber Crime and Cyber Security
S
SegmentFault 最新的问题
The GitHub Blog
The GitHub Blog
The Cloudflare Blog
Stack Overflow Blog
Stack Overflow Blog

静观小窗

一个有趣的项目背后的难点--MC的3D皮肤生成器 power by Qwen 博客俱乐部,最有社区氛围的中文博客联盟 文化决定语言,语言决定思想:我们赖以生存的隐喻(读后感) 我开发了一款博客图片压缩工具,支持PicGo一键压缩上传 寻找网络友邻 整合全网102个二次元动漫随机图片API接口,2025年十月最新 宋代的遗憾 搭建个人起始网站,便于控制浏览器使用和时间规划 Google Gemini CLI 免费安装配置指南:支持Gemini 2.5 Pro (2025最新) NixOS深度评测:一个六年Linux用户的初体验,为何惊艳的设计哲学仍让我望而却步 我的NS2使用体验记录,为什么因为马里奥派对空前盛会入坑 关于秦制的个人理解,为什么秦制在我看来是功过鲜明的必然 拜访一个人,在千年之后 Vercel/Netlify国内加速:EdgeOne免费CDN优选IP实战指南 C/C++程序员必看:JavaScript核心概念深度解析(动态类型、原型链、事件循环) C/C++程序员转向JavaScript:一份超详细的语法映射与避坑指南 从C++到JS:函数、this与闭包的核心差异与实践指南 VSCode配置JavaScript开发环境:Node.js安装与调试指南 博客迁移实战:从WordPress到Next.js的零成本高性能之路 《原则》读书笔记:如何将瑞·达利欧的智慧应用到日常 MATLAB入门教程:面向C++/OIer的数据可视化与科学计算指南 LaTeX公式与三线表教程:从入门到精通的排版指南 软路由远程访问提速:SMB压缩与50M上行优化实战 Hyprland 安装与配置超详细教程 (Arch Linux):含 Waybar 及一键脚本 Linux文件系统与磁盘分区:从入门到精通的实战指南 Guide to Installing a USB WiFi Adapter on OpenWrt (LuCI) 阿里云CentOS 9服务器从零到一:安全配置与宝塔面板安装指南 WordPress个人博客搭建指南:从服务器到主题美化全攻略 Arch/Windows双系统终极指南:无缝鼠标共享与显卡配置 NAS怎么选?黑群晖、CentOS自建与绿联NAS深度对比与选型指南 Arch Linux 安装 KDE Plasma 6:一篇来自老用户的深度评测(2025版) 我的第一份Ubuntu安装与美化笔记(新手超详细避坑指南)
C/C++程序员必看:JavaScript变量与作用域深度解析(从var到const)
间窗 (Vindo) · 2025-08-19 · via 静观小窗

作为一名有C/C++基础的开发者,初次接触JavaScript时,你可能会对它的变量声明、类型系统和作用域机制感到困惑。本文旨在深入解析这些 JS变量JS作用域 的核心概念,特别是 varletconst 的区别,以及 变量提升 和闭包的奥秘。通过与C/C++的对比,帮助你建立正确的JS心智模型,实现平滑的 C++转JS 技术栈迁移。

一、变量声明:从 varletconst

C 背景锚点

C/C++ 中,变量声明通常伴随着类型(如 int x;),且作用域清晰。

JS 差异本质

JavaScript 是一种动态类型语言,变量声明不带类型。早期只有 var,ES6 引入了 letconst,它们在作用域和提升行为上与 var 有显著区别。

1.1 var:历史遗留的“粗心”变量

var 声明的变量具有函数作用域,且存在“变量提升”(Hoisting)现象,这在C/C++程序员看来非常反直觉。

function example() {
  console.log(x); // 输出: undefined (因为变量被提升了)
  var x = 10;
  console.log(x); // 输出: 10

  if (true) {
    var y = 20;
  }
  console.log(y); // 输出: 20 (y 在函数作用域内,不受 if 块影响)
}
example();

我的经验:我曾经因为 var 的这种“粗心”行为,在大型项目中排查了很久的bug。它很容易导致变量污染和意外覆盖,所以现在几乎不再使用 var

1.2 let:现代JS的首选可变变量

let 声明的变量具有块级作用域({} 内部),且不存在 var 那样的变量提升问题(存在“暂时性死区”)。

function example() {
  // console.log(z); // 错误!ReferenceError: Cannot access 'z' before initialization
  let z = 30;
  console.log(z); // 输出: 30

  if (true) {
    let w = 40;
    console.log(w); // 输出: 40
  }
  // console.log(w); // 错误!ReferenceError: w is not defined (w 在 if 块外不可访问)
}
example();

1.3 const:声明常量

const 用于声明常量,一旦赋值后就不能再重新赋值。它也具有块级作用域。

const PI = 3.14159;
// PI = 3.14; // 错误!TypeError: Assignment to constant variable.

二、动态类型 vs 静态类型

C 背景锚点

C/C++ 是静态类型语言,变量类型在编译时确定,如 int number = 42;

JS 差异本质

JavaScript 是动态类型语言,变量的类型在运行时根据其值动态确定。同一个变量可以在不同时刻持有不同类型的数据。

let data = 42;        // number
console.log(typeof data); // "number"

data = "Hello";       // 现在是 string
console.log(typeof data); // "string"

三、值类型 vs 引用类型

C 背景锚点

C/C++ 中有值类型(如 int)和引用类型(如指针 int*)。值类型直接存储数据,引用类型存储数据地址。

JS 差异本质

JavaScript 中,基本数据类型(number, string, boolean, null, undefined, symbol, bigint)是值类型,赋值时是拷贝值。对象(object, array, function)是引用类型,赋值时是拷贝引用(地址)

let obj1 = { name: "Alice" };
let obj2 = obj1;        // obj2 拿到的是 obj1 的“引用”
obj2.name = "Bob";
console.log(obj1.name); // "Bob" —— 原对象被修改!

四、作用域链与闭包

C 背景锚点

C 语言中,嵌套作用域通过栈帧实现,变量查找遵循从内到外的规则。

JS 差异本质

JavaScript 中,每个函数都有一个“作用域链”,用于查找变量。JS作用域 查找规则:从内到外,逐层向上。当一个内部函数引用了外部函数的变量,并且这个内部函数被返回或传递出去时,即使外部函数执行完毕,内部函数仍然能访问外部函数的变量——这就是闭包

function createCounter() {
  let count = 0; // 私有变量
  return function() {
    count++;
    return count;
  };
}

const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
// count 本该随 createCounter 调用结束而销毁,但被闭包“留住”了

五、变量提升 (Hoisting) 与暂时性死区 (TDZ)

C 背景锚点

C 语言中,变量必须先声明后使用。

JS 差异本质

JavaScript 中存在 变量提升 现象:

  • var 声明的变量会被提升到作用域顶部,但赋值不提升,导致“先用后声明”时值为 undefined
  • letconst 声明的变量也会被提升,但在声明前的区域称为暂时性死区(Temporal Dead Zone, TDZ),访问会抛错。这强制开发者按顺序书写代码,提高了代码可读性。
console.log(x); // undefined (var 提升)
var x = 10;

// console.log(y); // 错误!Cannot access 'y' before initialization (let 的 TDZ)
let y = 20;

六、全局对象与模块作用域

C 背景锚点

C 语言中,全局变量通常通过 extern 关键字在不同文件间共享。

JS 差异本质

在浏览器环境中,全局对象是 window。早期 var 声明的全局变量会成为 window 的属性,容易造成命名冲突。现代 JavaScript (ES6+) 推荐使用模块作用域,通过 import/export 机制实现模块化,避免污染全局对象。

总结

希望通过与C/C++的对比,你对 JS变量JS作用域 有了更清晰的认识。理解 var let const 的区别,掌握 变量提升 和闭包,是掌握 C++转JS 的关键一步。