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

推荐订阅源

T
Threatpost
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Engineering at Meta
Engineering at Meta
T
The Blog of Author Tim Ferriss
Recent Announcements
Recent Announcements
G
Google Developers Blog
Google DeepMind News
Google DeepMind News
The Register - Security
The Register - Security
MongoDB | Blog
MongoDB | Blog
U
Unit 42
B
Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
L
LangChain Blog
Stack Overflow Blog
Stack Overflow Blog
P
Privacy International News Feed
L
LINUX DO - 最新话题
博客园_首页
博客园 - Franky
大猫的无限游戏
大猫的无限游戏
小众软件
小众软件
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Tor Project blog
V
Visual Studio Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
P
Privacy & Cybersecurity Law Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
K
Kaspersky official blog
C
Cisco Blogs
博客园 - 【当耐特】
阮一峰的网络日志
阮一峰的网络日志
I
Intezer
罗磊的独立博客
MyScale Blog
MyScale Blog
Last Week in AI
Last Week in AI
A
About on SuperTechFans
G
GRAHAM CLULEY
Y
Y Combinator Blog
Microsoft Security Blog
Microsoft Security Blog
GbyAI
GbyAI
T
Threat Research - Cisco Blogs
P
Proofpoint News Feed
D
DataBreaches.Net
The Hacker News
The Hacker News
Spread Privacy
Spread Privacy
AWS News Blog
AWS News Blog
I
InfoQ
T
The Exploit Database - CXSecurity.com
Simon Willison's Weblog
Simon Willison's Weblog
博客园 - 叶小钗
Project Zero
Project Zero

博客园 - lzhdim

JavaScript 中的原型与继承 1分钟查清局域网所有IP 20260714 - 个人小作品更新 WorkBuddy 完整教程手册 专为AI而生的企业级QLC SSD!长江存储PE501 61.44TB评测:超过1PB的写入测试 32GB显存才是第一生产力!英特尔锐炫 Pro B70评测:中小企业AI降本神器 JavaScript中的this关键字 C#开发的PopoSaver泡泡屏保应用 - 开源研究系列文章 - 个人小作品 6天不间断测试告诉你到底有多省电!米家空调巨省电大1.5匹评测:制冷峰值功率不超过500W 三倍双摄加持 + D-Log 2 曲线!大疆DJI OSMO Pocket 4P全面评测:补齐短板,化身口袋电影机 晶栈4.0闪存立威!长江存储致态TiPro9000 2TB SSD评测:缓外写入超4GB/s独一档 C# 多线程同步机制详解:原理、使用与性能对比 JavaScript作用域与闭包讲解 最受欢迎的 10 大免费 AI 工具 六种AI生意,从月入一万到月入十万 5个国产大模型实测对比2026:DeepSeek、Kimi、豆包、通义、智谱哪个好用 豆包、元宝、千问、Kimi、DeepSeek,这么多AI软件,到底该用哪个? 微软免费开源了一个 Linux 操作系统,没错!是微软出品 一次看懂5种咖啡冲煮方式:意式、手冲、法压、冷萃、摩卡壶到底有什么区别 120个 实用CSS 技巧汇总合集 JavaScript运算符与表达式详解 C#开发的ScreenSaver屏保应用 - 开源研究系列文章 - 个人小作品 WinForm 中跨线程操作 UI 的解决方案 苹果良心!iOS 27适配设备公布:30款机型 7年前的iPhone 11还能升级 C++图形用户界面开发入门 10个不该免费的GitHub神级项目 JavaScript语言全面概述:从历史到现代实践 一张图看懂常见咖啡 C盘空间多出来4GB:谷歌服软 Chrome本地AI大模型可禁用、删除了 96GB显存运行230B大模型!七彩虹灵创K16笔记本评测:160W性能释放 AMD锐龙AI Max+ 395加持全能移动AI工作站 AI PC最强存储搭档!雷克沙NM1090 PRO 8TB固态评测:14400MB/s满速不缩水 C#已经不是当年的C#了——我用它写了个微秒级数据库引擎 EasyTool:轻量全能的 .NET 工具类库 SQL 入门 17:MySQL 数据类型:从字符串到 JSON 的全面解析 SQL 入门 16:SQL 事务隔离级别与死锁解析(易懂) 原相3955XM+TL3228主控!小米电竞鼠标2全面评测:原生双8K究竟有多强 PCIe 4.0火力全开:闪迪奥丁马仕GX 7100 NVMe SSD上手 超乎预料的千元级电竞主板!七彩虹iGame B850M Ultra-OC V14主板评测 SQL 入门 15:SQL 事务:从 ACID 到四种常见的并发问题 名人 - 我的闪存 C#性能优化技巧 SQL 入门 14:SQL 触发器与事件:自动化数据处理 38个实用的JavaScript 技巧 一款基于 .Net WinForm 开发的节点编辑器,纯 GDI 实现,体积仅 100+Kb Masuit.Tools:这个 C# 工具库 SQL 入门 13:SQL 存储过程与函数:封装逻辑与参数处理 49个 JavaScript 代码快捷技巧,让你在 2026 年成为代码高手 20260503 - 个人小作品更新 SQL 入门 12:SQL 视图:创建、修改与可更新视图 C#如何实现Windows系统桌面截图功能... 6999元AMD新旗舰首测!锐龙9 9950X3D2性能解禁:这颗U根本不是给游戏玩家造的 SQL 入门 11:日期时间格式化、IF、CASE的使用 基于C#的校时类库的实现及使用 - 开源项目研究文章 39g无打孔+原生双8K!雷柏VT0 Air MAX / VT3s Air MAX鼠标评测:轻到飞起还快到极致 WinForm 中控件自适应窗体变化 20260413 - 个人小作品更新 SQL 入门 10:SQL 内置函数:数值、字符串与时间处理 最强麒麟芯+自研风冷 华为Mate80 Pro MAX 风驰版全面评测:涡轮散热封神 性能稳到骨子里 WiFi8核心技术特性与性能分析 2026年最新AMD/Intel桌面CPU排名:多线程、单线程、游戏性能谁才是第一 用DG对C盘进行扩容 - 初学者系列 - 学习者系列 还有比它更强的OEM固态吗!长江存储PC550 1TB评测:不用散热片也能满速的PCIe 5.0 SSD SharpCompress:跨平台的 C# 压缩与解压库 SQL 入门 9:SQL 高级子查询:ANY、EXISTS 与多位置应用 盘点接私活20个最实用的 .NET 开源项目 C#中加载图片的资源释放 20260404 - 个人小作品更新 开启iphone的墙纸玻璃效果 可能是综合性能最强的PCIe 5.0 SSD!铠侠EXCERIA PRO G2 2TB评测:AIDA64线性写入全程不掉速 SQL 入门 8:SQL 复杂查询:子查询与ALL关键词 性能最强的锐龙AI 9 H 465轻薄本!华硕无畏Pro16锐龙版2026评测 4盘RAID 0读写超1100MB/s!希捷酷狼Pro 32TB硬盘评测:百万文件快速完成备份 项目(Project)、项目集(Program)、项目组合(Portfolio) SQL 入门 7:SQL 聚合与分组:函数、GROUP BY 与 ROLLUP
JavaScript变量与数据类型详解
lzhdim · 2026-06-15 · via 博客园 - lzhdim

一、变量声明在 JavaScript 中, 我们主要有三种声明变量的方式: varlet 和 const. 它们看起来差不多, 但实际上差别可大了!1) 老派风的varvar 是 JavaScript 最早的变量声明方式, 它有一些"独特"的行为: 

var name = "小明";console.log(name); // 输出: 小明
// var 允许重复声明var name = "小红";console.log(name); // 输出: 小红
// var 有变量提升的特性console.log(age); // 输出: undefined (不会报错!)var age = 18;

问题:

  • 可以重复声明,容易导致变量被意外覆盖

  • 存在变量提升(hoisting), 代码执行前会把声明提到作用域顶部

  • 只有函数作用域,没有块级作用域

2) 现代派的let

ES6 引入了 let, 解决了 var 的很多问题: 

let name = "小明";console.log(name); // 输出: 小明
// let 不允许重复声明let name = "小红"; // 报错: Identifier 'name' has already been declared
// let 也有提升, 但不允许在声明前使用(暂时性死区)console.log(age); // 报错: Cannot access 'age' before initializationlet age = 18;
// let 有块级作用域if (true) {  let food = "苹果";  console.log(food); // 输出: 苹果}console.log(food); // 报错: food is not defined

3) 常量constconst 用于声明常量, 声明后不能重新赋值:

const PI = 3.14159;console.log(PI); // 输出: 3.14159
PI = 3.14; // 报错: Assignment to constant variable
// 但注意! 对于对象和数组, const 只保证引用不变const person = { name: "小明" };person.name = "小红"; // 这是允许的!console.log(person); // 输出: { name: "小红" }
person = { name: "小刚" }; // 报错: Assignment to constant variable

4) 三者之间的对比

特性varletconst
作用域 函数作用域 块级作用域 块级作用域
重复声明 允许 不允许 不允许
变量提升 有(但不可用) 有(但不可用)
可重新赋值 可以 可以 不可以
必须初始化 不需要 不需要 需要

建议:

  1. 默认使用 const

  2. 需要重新赋值的变量用 let

  3. 避免使用 var (除非你需要兼容非常老的浏览器)


二、JavaScript的数据类型1) 基本类型

基本类型有 7 种:

  1. number - 数字

  2. string - 字符串

  3. boolean - 布尔值

  4. null - 空值

  5. undefined - 未定义

  6. symbol - 符号 (ES6新增)

  7. bigint - 大整数 (ES2020新增)


特点:

  • 存储在栈内存中

  • 按值访问

  • 不可变(immutable)

  • 比较时比较的是值


示例:

let a = 10;let b = a; // b 是 a 的值的一个副本a = 20;console.log(a); // 20console.log(b); // 10
let str = "hello";str[0] = "H"; // 字符串是不可变的,这行代码不会报错但也不起作用console.log(str); // 输出: "hello"

2) 引用类型

引用类型主要是:

Object (包括数组、函数、日期、正则表达式等)

特点:

  • 存储在堆内存中

  • 按引用访问

  • 可变(mutable)

  • 比较时比较的是引用(内存地址)


示例:

let obj1 = { name: "小明" };let obj2 = obj1; // obj2和 obj1指向同一个对象
obj1.name = "小红";console.log(obj2.name); // 输出:"小红" (因为两者引用同一个对象)
let arr1 = [1, 2, 3];let arr2 = arr1;arr1.push(4);console.log(arr2); // 输出:[1, 2, 3, 4]

3) 基本类型与引用类型的比较

// 基本类型比较let num1 = 5;let num2 = 5;console.log(num1 === num2); // true (值相同)
// 引用类型比较let obj1 = { name: "小明" };let obj2 = { name: "小明" };console.log(obj1 === obj2); // false (虽然内容相同, 但引用不同)
let obj3 = obj1;console.log(obj1 === obj3); // true (引用相同)

4) 特殊的null和undefined

null 和 undefined 都表示"无", 但有细微差别: 

  • undefined 表示变量已声明但未赋值

  • null 表示变量有值, 但这个值是"空"

let a;console.log(a); //undefined (声明但未赋值)
let b = null;console.log(b); //null (明确赋值为空)
// 有趣的现象console.log(typeof null); console.log(typeof undefined); 

三、类型检测

1) typeof运算符

typeof 是最常用的类型检测方法:

typeof 42; // "number"typeof "hello"; // "string"typeof true; // "boolean"typeof undefined; // "undefined"typeof Symbol(); // "symbol"typeof 123n; // "bigint"
// 两个特殊情况typeof null; // "object" (历史遗留问题)typeof function() {}; // "function"

问题:

  • 不能区分数组和普通对象(都返回 "object")

  • 对 null 返回 "object"

2) instanceof运算符

instanceof 用于检测对象是否是某个构造函数的实例:

let arr = [1, 2, 3];arr instanceof Array; //truearr instanceof Object; //true (因为数组也是对象)
let date = new Date();date instanceof Date; //truedate instanceof Object; //true
// 基本类型不能用 instanceof检测42 instanceof Number; //false

3) Object.prototype.toString.call()

这是最准确的类型检测方法:

Object.prototype.toString.call(42); Object.prototype.toString.call("hello"); Object.prototype.toString.call(true); Object.prototype.toString.call(null); Object.prototype.toString.call(undefined); Object.prototype.toString.call([]); Object.prototype.toString.call({}); Object.prototype.toString.call(new Date()); 

4) Array.isArray()

专门用于检测数组:

Array.isArray([]); //trueArray.isArray({}); //false

5) 最佳实践

  1. 检测基本类型(除了null)用 typeof

  2. 检测数组用 Array.isArray()

  3. 检测null用 === null

  4. 需要精确检测对象类型时用 Object.prototype.toString.call()

  5. 知道对象的具体构造函数时可以用 instanceof

四、类型转换JavaScript 是弱类型语言, 会自动进行类型转换. 这既是便利也是坑!1) 显示类型转换字符串转换:

String(123); //"123"String(true); //"true"String(null); //"null"String(undefined); //"undefined"
//等价于123.toString(); //"123"true.toString(); //"true"
//注意:null和 undefined没有toString方法

数字转换:

Number("123"); //123Number("123abc"); //NaN(Not a Number)Number(true); //1Number(false); //0Number(null); //0Number(undefined); //NaN
//其他方法parseInt("123px"); //123parseFloat("3.14.15"); //3.14+"123"; //123 (一元加号运算符)

布尔值转换:

Boolean(1); // trueBoolean(0); //falseBoolean(""); //falseBoolean("hello"); //trueBoolean(null); //falseBoolean(undefined); //falseBoolean({}); //trueBoolean([]); //true
//等价于!!1; //true(双感叹号技巧)!!0; //false

2) 隐式类型转换JavaScript 在某些情况下会自动进行类型转换:字符串拼接

"今年是" + 2023; //"今年是2023" (数字转为字符串)1 + "2"; //"12"

数学运算

"10" - 5; // 5 (字符串转为数字)"10" * "2"; // 20"10" / "2"; // 5"abc" - 1; // NaN
//注意加法的特殊性1 + 2 + "3"; // "33" (从左到右计算)"1" + 2 + 3; // "123"

布尔值

if ("hello") { //"hello"被转为 true  console.log("执行");}
//常见的假值(falsy values)://false, 0, "", null, undefined, NaN//其他所有值都是真值(true)

==和===的区别

1 == "1"; //true(类型转换后比较)1 === "1"; //false(严格比较,不转换类型)
0 == false; //true0 === false; //false
null == undefined; //truenull === undefined; //false

总是应该使用 === 和 !== 避免隐式转换带来的意外行为.五、深拷贝与浅拷贝1) 浅拷贝 (只拷贝第一层属性)

let person = { name: "小明", hobbies: ["篮球", "音乐"] };
//方法1:Object.assignlet copy1 = Object.assign({}, person);
//方法2:展开运算符let copy2 = { ...person };
//修改拷贝后的对象copy1.name = "小红";copy1.hobbies.push("游泳");
console.log(person.name); //"小明"(未受影响)console.log(person.hobbies); //["篮球", "音乐", "游泳"](受影响!)

2) 深拷贝 (完全拷贝所有层级)

//方法1: JSON.parse(JSON.stringify()) (最简单但有局限)let deepCopy1 = JSON.parse(JSON.stringify(person));
//方法2: 使用工具库如lodash的_.cloneDeep//let deepCopy2 = _.cloneDeep(person);
//方法3: 手动实现递归拷贝function deepClone(obj) {  if (obj === null || typeof obj !== "object") return obj;  let clone = Array.isArray(obj) ? [] : {};  for (let key in obj) {    if (obj.hasOwnProperty(key)) {      clone[key] = deepClone(obj[key]);    }  }  return clone;}
let deepCopy3 = deepClone(person);

六、ES6+新特性1) 模板字符串

const name = "小明";const age = 18;console.log(`我叫${name}, 今年${age}岁`); 

2) 解构赋值

//对象解构const person = { name: "小明", age: 18 };const { name, age } = person;
//数组解构const arr = [1, 2, 3];const [first, second] = arr;

3) 新的原始类型Symbol:

const sym1 = Symbol("唯一标识");const sym2 = Symbol("唯一标识");console.log(sym1 === sym2); //false(每个Symbol都是唯一的)
//常用作对象的唯一键const obj = {  [sym1]: "这是Symbol作为键的值"};

BigInt:

const bigNum = 1234567890123456789012345678901234567890n;console.log(bigNum + 1n); //可以表示和操作超大整数