You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
30-Days-Of-JavaScript/js_notes/02-variables.js

199 lines
12 KiB

// 02 · 变量与数据类型
// 学练复习一体:概念总结 → 示范 → 轮到你
// 跑法:Quokka / 右上角 ▷ / node 本文件
// 示范区每行后注释是【预期输出】,跑完自己对答案
// ═════ 概念总结 ═════
//
// 1. 什么是变量
// 变量就是给数据起个名字,方便反复使用和修改。
// let age = 18 // 把 18 存进名叫 age 的盒子
// age = 19 // 改成 19
//
// 2. let / const / ~~var~~ ⭐
// ┌────────┬──────────┬──────────────────────────────────┐
// │ 关键字 │ 能改值吗 │ 什么时候用 │
// ├────────┼──────────┼──────────────────────────────────┤
// │ const │ ❌ 不能 │ 默认首选,值不变的都用它 │
// │ let │ ✅ 能改 │ 需要改变的值(计数器、累加等) │
// │ var │ ✅ 能改 │ ⚠️ 老写法,有坑,别用 │
// └────────┴──────────┴──────────────────────────────────┘
// 原则:优先 const,确实要改再换 let。防手滑改错,代码也更好读。
// const PI = 3.14 // 常量,不会变
// let count = 0 // 会变的用 let;count = count + 1 ✅
// // PI = 3.15 // ❌ 报错:const 不能重新赋值
// ⚠️ var 为啥"有坑"?一个典型:变量声明前就用它,var 会【静默给 undefined】
// 把 bug 藏起来;而 const/let 会【当场报错】(TDZ),让你一眼发现。
// (详见 10-functions.js "提升 hoisting" 一节)
//
// 3. 变量命名规则 ⭐
// 必须遵守(否则报错):
// - 只能用字母、数字、_、$;不能以数字开头
// - 不能用关键字(如 let、const)
// - 区分大小写(age 和 Age 是两个变量)
// 社区惯例(建议遵守):
// - 用 camelCase 小驼峰:firstName、isMarried、myAge
// - 名字要有意义:age 好过 a
//
// 4. 八种数据类型
// 原始类型(Primitive)—— 7 种,最常用前 3 个:
// ┌───────────┬──────────────────┬──────────────────────────┐
// │ 类型 │ 例子 │ 说明 │
// ├───────────┼──────────────────┼──────────────────────────┤
// │ number │ 18, 3.14, -5 │ 数字(整数小数不分家) │
// │ string │ 'hi', "abc" │ 字符串 │
// │ boolean │ true, false │ 真/假 │
// │ undefined │ undefined │ 声明了但没赋值 │
// │ null │ null │ 手动表示"空" │
// │ bigint │ 10n │ 超大整数(少见) │
// │ symbol │ Symbol() │ 唯一标识(少见) │
// └───────────┴──────────────────┴──────────────────────────┘
// 引用类型(非原始):object —— {}、[]、函数等(后面专门讲)
//
// 5. typeof —— 查一个值是什么类型 ⭐
// typeof 18 // 'number'
// typeof 'hi' // 'string'
// typeof true // 'boolean'
// typeof undefined // 'undefined'
// 小坑:typeof null 会返回 'object',这是 JS 历史遗留 bug,记住即可。
//
// ── 三个最爱混的值,typeof 都出人意料(速查)⭐⭐ ──
// ┌───────────┬──────────────┬────────────────────────────────────┐
// │ 值 │ typeof 结果 │ 一句话 + 坑 │
// ├───────────┼──────────────┼────────────────────────────────────┤
// │ undefined │ 'undefined' │ 系统给的"还没值";自成一个类型 │
// │ null │ 'object' ⚠️ │ 你给的"空";typeof 说它 object 是坑 │
// │ NaN │ 'number' ⚠️ │ 无效数字,属 number;NaN!==NaN 是坑 │
// └───────────┴──────────────┴────────────────────────────────────┘
// 记:null 不是真 object(历史 bug);NaN 不是"不是数字",它就是 number。
// 详见下方 §6(undefined vs null)、§7(NaN)。
//
// 6. undefined vs null ⭐
// 两个都表示"没有",区别在【谁放的、是不是有意】:
// - undefined:系统给的"还没值"(默认状态)。像杯子你还没倒过。
// - null:你主动给的"这里【有意】空着"(刻意清空/占位)。像杯子你特意倒空并标记。
// let x; console.log(x) // undefined ← 没赋值,系统默认
// let y = null // null ← 你主动清空
// null === undefined // false ← 概念不同:一个"未设置",一个"设为空"
//
// ── null 到底是什么?怎么理解 ⭐ ──
// null 是一个【独立的原始值】,自成一类,类里只有它一个成员;含义="有意的空"。
// • typeof null // 'object' ← 这是 1995 年的历史 bug(底层用全 0 表示,被误判)。
// 全世界老代码都依赖它了,改了会崩,只好将错就错。→ null 不是对象,是原始值!
// (呼应 00-concepts/value-vs-reference.md:null 明列在"原始值"栏)
// • 怎么判断是不是 null?直接用 === 就行,可靠(不像 NaN 连自己都不等):
// if (x === null) { ... } // ✅ null === null 成立
// // ❌ 别用 typeof x === 'object' 判 null:{}、[] 也是 'object',会误伤
// • 什么时候用:"这位置将来会有个对象,但现在还没有"→ 用 null 明确占位:
// let currentUser = null // 还没登录,主动标记"当前无用户"
// currentUser = { name: 'Tom' } // 登录后再填
// 比放 undefined 更能表达"我【知道】这里暂时空,不是忘了"(agent 代码常见)。
//
// 7. NaN / Infinity 都属于 number ⭐
// NaN(Not a Number)名字唬人,但它自己的类型偏偏是 number ——
// 它是 number 家族里表示"无效数字"的特殊值,不是独立的第 8 种类型。
// typeof NaN // 'number' ← 名叫"不是数字",类型却是数字!
// typeof Infinity // 'number'
// ┌────────────────┬──────────┬──────────────────────────────────┐
// │ 特殊 number 值 │ 含义 │ 怎么产生 │
// ├────────────────┼──────────┼──────────────────────────────────┤
// │ NaN │ 无效数字 │ 'abc' - 1、Number('hi') 转换失败 │
// │ Infinity │ 正无穷 │ 1 / 0 │
// │ -Infinity │ 负无穷 │ -1 / 0 │
// └────────────────┴──────────┴──────────────────────────────────┘
// 大坑:NaN 不等于它自己 ⭐
// NaN === NaN // false ← 连自己都不等于!
// 所以不能用 === NaN 判断,要用专门函数:
// Number.isNaN(x) // 这才是判断"是不是 NaN"的正确方法
//
// ✅ 本主题要点回顾
// 1. 变量 = 给数据起名字
// 2. 优先 const,要改才用 let,别用 var ⭐
// 3. 命名:小驼峰、有意义、不能数字开头
// 4. 常用类型:number / string / boolean,外加 undefined / null
// (null 是"有意的空",独立原始值;判断用 === null,typeof null==='object' 是坑)
// 5. typeof 查类型(注意 typeof null === 'object' 是坑)
// 6. NaN / Infinity 都属于 number;NaN !== NaN,判断用 Number.isNaN() ⭐
// ═════ 示范 ═════
// ── 1. let 可以改,const 不能改 ⭐ ─────────────────
let age = 18
console.log(age) // 18
age = 19 // let 允许重新赋值
console.log(age) // 19
const PI = 3.14
console.log(PI) // 3.14
// PI = 3.15 // ← 取消注释会报错:Assignment to constant variable
// ── 2. const 首选,会变的才用 let ─────────────────
let count = 0
count = count + 1
count = count + 1
console.log('count =', count) // count = 2
// ── 3. 常用数据类型 ───────────────────────────────
const myNumber = 100 // number
const myString = 'JavaScript' // string
const myBool = true // boolean
console.log(myNumber, myString, myBool) // 100 JavaScript true
// ── 4. typeof 查类型 ⭐ ───────────────────────────
console.log(typeof 18) // number
console.log(typeof 'hi') // string
typeof 'hi' // ← 这行会算,但文件里【看不到】任何输出(见第 8 组)
console.log(typeof true) // boolean
console.log(typeof undefined) // undefined
console.log(typeof null) // object ← 历史遗留坑,记住即可
// ── 5. undefined vs null ─────────────────────────
let x // 声明但没赋值
console.log(x) // undefined ← 系统默认
let y = null // 主动清空
console.log(y) // null ← 你给的
// ── 6. 小驼峰命名 + 反引号拼句子(复习上一章) ──────
const firstName = 'Asabeneh'
const country = 'Finland'
console.log(`${firstName} lives in ${country}`) // Asabeneh lives in Finland
// ── 7. 数组的 typeof 是 'object' ⭐ ───────────────
// 数组不是独立类型,本质是特殊的 object,所以 06-arrays 才专门讲
const arr = [1, 2, 3]
console.log(typeof arr) // object ← 不是 'array'!
console.log(Array.isArray(arr)) // true ← 想确认是不是数组用这个
// ── 8. "能算" ≠ "能看见":文件里必须 console.log ⭐ ─
typeof 'hi' // 这行会算出 'string',但在文件里【看不到】任何东西
console.log(typeof 'hi') // string ← 用 console.log 包起来才显示
// typeof 是运算符不是函数 → 后面加不加括号都行:
console.log(typeof 'hi') // string
console.log(typeof ('hi')) // string ← 这括号只是分组,不是函数调用
// ═════ 轮到你 ═════
// 👇 轮到你(把 ??? 换掉,取消注释,跑一下对答案)
// 练习 A:声明一个 const 存你的名字,再用反引号打印 "我叫 xxx"
// const myName = '???'
// console.log(`我叫 ${myName}`)
// 练习 B:声明一个 let 叫 score = 0,让它加 10,再加 5,打印结果(应为 15)
// let score = ???
// score = ???
// score = ???
// console.log('score =', score)
// 练习 C:用 typeof 查一下 3.14 是什么类型,打印出来(应为 number)
// console.log(typeof ???)
const myName = "Jaydon"
console.log(`我叫 ${myName}`) // 我叫 Jaydon ← 是 ${} 不是 &{} !
let score = 0
score += 10
score += 5
console.log(score)