主题
数据类型与BFC(Day1 3/3)
本页对应 Day01_JavaScript,共 6 段视频,约 1 小时 11 分。
学习目标
- 能区分整型与浮点数的表示形式,说明
0、0x前缀的含义,并预测012、0x12、67.2等字面量的输出结果。 - 能解释
0.1 + 0.2的运算结果及浮点精度原因,并能用科学计数法(如1.3e4、2.3e-2)写出或判断对应的十进制值。 - 能说明
boolean、null、undefined的取值与典型产生场景,并判断未赋值变量在使用时的结果。 - 能说明
NaN的类型及运算、比较特征,能使用isNaN()判断给定数据是否为NaN或转换为number后是否为NaN。 - 能说明
Number.MAX_VALUE、Number.MIN_VALUE与正负Infinity的含义,判断超出有效范围、下溢为0及isFinite()的返回结果。 - 能使用单引号或双引号定义字符串,正确处理引号嵌套,并使用
\n、\t、\`、\uXXXX` 等转义字符输出指定内容。
知识点
先看 number:整数和浮点不是一回事
为什么需要:JS 对外只有一个 number 类型,但内部要处理整数和带小数点的数;不理解这一点,就容易把 012、0x12、0.1 + 0.2 当成“数学课上那样当然正确”。
怎么想:整数可以较精确地转成二进制;很多十进制小数转二进制是无限小数,只能近似存储。所以 number 里仍有“整型/浮点”的差异。
怎么做:看几个字面量和输出:
js
let N01 = 764; // 十进制整数
let N02 = 012; // 八进制表示,等于十进制 10
let N03 = 0x12; // 十六进制表示,等于十进制 18
let N04 = 67.2; // 带小数点就是浮点
console.log(N01); // 764
console.log(N02); // 10
console.log(N03); // 18
console.log(0.1 + 0.2); // 类似 0.30000000000000004推导:八进制 12 是 1*8+2=10;十六进制 12 是 1*16+2=18。0.1 + 0.2 出现长尾,是因为两个小数先转二进制近似值,运算后再转回十进制。
易错点:八进制、十六进制只能表示整数,给 0x12.5 这类写法会报错;浮点结果不要直接当成精确的 0.3,但普通显示精度通常够用。
科学计数法:极端数字的写法
为什么需要:很大或很小的数直接写很多 0 很累,也容易数错。
怎么想:沿用数学里的科学计数法,JS 用 e 表示“乘以 10 的几次方”。
怎么做:
js
let N05 = 1.3e4; // 1.3 * 10^4
let N06 = 2.3e-2; // 2.3 * 10^-2
console.log(N05); // 13000
console.log(N06); // 0.023推导:1.3e4 小数点右移 4 位得 13000;2.3e-2 小数点左移 2 位得 0.023。数太大时,控制台也可能用科学计数法显示,但那只是显示形式,数值本身没变。
易错点:e 不是变量,是语法的一部分;负指数表示很小的小数,不要误以为得到负数。
boolean、null、undefined:状态与空值
为什么需要:程序要表达“真/假”和“暂时没有值”。
怎么想:boolean 只有 true、false;null 和 undefined 都表示“空”,初学不必硬背一堆玄学区别。变量声明后没有赋值,使用时通常是 undefined。
怎么做:
js
let ok = true;
let no = false;
let empty = null;
let unset;
console.log(unset); // undefined易错点:不要主动到处赋 null 来表示“暂时不知道”,也可以先不赋值;后续计算中可能自然得到 undefined 或 null,通常都意味着“没拿到有效结果”。
NaN:不是有效数字的 number
为什么需要:类型转换或非法计算可能得不到有效数字,需要有个值来占位。
怎么想:NaN 全称 “Not a Number”,但它仍是 number 类型,表示“不是有效数字”。
怎么做:
js
console.log(NaN + 0); // NaN
console.log(NaN / 189); // NaN
console.log(250 === 250); // true
console.log(NaN === NaN); // false
console.log(isNaN('hello')); // true
console.log(isNaN(250)); // false推导:NaN 与任何数字计算仍得 NaN;它和任何值都不相等,包括自己。isNaN('hello') 为 true,是因为 'hello' 转 number 失败会得到 NaN。
易错点:判断相等实际开发更推荐 ===;isNaN 会先做转换,不只看“是不是 NaN 本身”。
数字有效范围:Infinity 与 isFinite
为什么需要:计算机能表示的数有上限和下限,超出范围要有特殊表示。
怎么想:最大数约 1.79e308;最小正数约 5e-324。超出正方向得 Infinity,超出负方向得 -Infinity,比最小正数还小会变成 0。
怎么做:
js
console.log(Number.MAX_VALUE); // 约 1.79e308
console.log(Number.MIN_VALUE); // 约 5e-324,最小正数
console.log(4e500); // Infinity
console.log(-4e500); // -Infinity
console.log(3e-400); // 0
console.log(isFinite(100)); // true
console.log(isFinite(Infinity)); // false
console.log(isFinite(NaN)); // false易错点:Number.MIN_VALUE 不是“最小负数”,而是最小正数;Infinity、-Infinity、NaN 都是无效数字,不能当正常数继续算。
string:引号、转义与 Unicode
为什么需要:文本是最常见的数据,必须知道引号怎么配对、特殊字符怎么写。
怎么想:单引号和双引号都能表示字符串;外层用什么引号,里面就不能直接再写同一种引号,需换引号或转义。换行不能直接在代码里敲,要用 \n。
怎么做:
js
let msg01 = 'hello 高小乐';
let msg02 = "你好 老头乐";
console.log(msg01, typeof msg01); // hello 高小乐 string
let msg03 = '锄禾日当午\n汗滴禾下土\n谁知盘中餐\n粒粒皆辛苦';
console.log(msg03);
let msg04 = '说明一下\'可以表示字符串\'';
let msg05 = "这里写\"双引号\"";
let msg06 = '在JS中可以使用\\n表示换行';
console.log('\u0065'); // e推导:\n 是换行符;\'、\" 是转义引号;\` 输出反斜杠本身;\u0065用 4 位十六进制 Unicode 编码表示字符e`。
易错点:单引号字符串里直接写单引号会提前结束字符串,造成语法错误;\u0065 里的 65 是十六进制,不是十进制。
作业目标:先明确“交换”到底交换什么
本节笔记给出的作业是:
js
var a = 100;
var b = 200;要求交换两个变量的值。也就是说,交换后希望 a 里保存 200,b 里保存 100。
为什么需要这个练习?因为变量不是数学符号,而是内存里保存值的容器。以后做排序、轮换、状态互换时,都会遇到“两个位置的值要调换”的问题。先把这个小动作想清楚,后面才不会把“赋值”误当成“交换”。
怎么想?不要一上来写代码,先问自己:执行完每一步后,a 和 b 分别是什么?易错点是把“把 b 的值给 a”理解成“a 和 b 自动互换”。赋值只发生在等号左边,右边只负责提供值。
直接写 a = b; b = a; 为什么会失败
最直觉的写法是:
js
var a = 100;
var b = 200;
a = b;
b = a;
console.log(a);
console.log(b);这样写的问题在于:执行 a = b 后,a 变成 200,原来 a 里的 100 已经被覆盖,找不回来了。接着 b = a,只是把现在的 200 又给 b,最后两个变量都成了 200。
为什么需要先分析这一步?因为交换的本质不是“连续赋值”,而是“先把其中一个值暂存起来,再覆盖,再放回”。怎么想?可以把 a 的值先抄到一张“临时纸条”上,等 a 被覆盖后,再用纸条上的值恢复 b。
易错点:不要用 a = b; b = a;,也不要在没有暂存的情况下直接覆盖。转写稿里反复强调用 console.log 看输出结果,这里也应该每一步打印,而不是凭感觉判断。
用临时变量完成交换
做法是引入第三个变量 temp:
js
var a = 100;
var b = 200;
var temp = a;
a = b;
b = temp;
console.log(a); // 200
console.log(b); // 100逐步推导:
var temp = a;:temp保存100,此时a仍是100,b仍是200。a = b;:a被赋成200,b仍是200,temp仍是100。b = temp;:b被赋成100,完成交换。
为什么这样做可靠?因为 temp 保留了即将被覆盖的旧值。怎么想?可以记成“先存旧 a,再让 a 拿 b,最后让 b 拿旧 a”。易错点有三个:temp 必须先声明再使用;三步顺序不能乱;最后一步不能写成 b = a,否则又把已经变成 200 的 a 赋给 b。
调试过程:把中间值打印出来
转写稿里讲 number 类型时,多次用 console.log 输出结果来验证;本节作业也应沿用这个调试习惯。可以写成:
js
var a = 100;
var b = 200;
var temp = a;
console.log(a, b, temp); // 100 200 100
a = b;
console.log(a, b, temp); // 200 200 100
b = temp;
console.log(a, b, temp); // 200 100 100这样能清楚看到每一步的值。为什么需要打印?因为交换失败通常不是语法错误,而是逻辑错误,代码能运行但结果不对。怎么想?先验证“暂存是否成功”,再验证“覆盖是否发生”,最后验证“恢复是否正确”。易错点:只看最后结果,不看中间过程;或者把 console.log(a, b) 写成字符串 "a, b",那看到的是字面文字,不是变量值。
易错点与本节小结
第一,a 和 b 是 number 类型,保存的是数值本身,赋值时复制的是值,不是让两个变量变成同一个东西。第二,临时变量名可以用 temp,但不要和已有变量重名。第三,var 声明后可以不写分号,但初学阶段建议写完整,减少歧义。第四,不要依赖“交换函数”之类还没讲的内容;本节作业就用最基础的变量和赋值完成。
转写稿本节主要回顾了 number、科学计数法、boolean、null、undefined、NaN、数字范围和 string,并没有直接给出交换变量的代码;上面的推导是按本节已学的“变量保存值、赋值、console.log 调试”来完成的。最终答案就是:
js
var a = 100;
var b = 200;
var temp = a;
a = b;
b = temp;
console.log(a); // 200
console.log(b); // 100先暂存旧值,再覆盖,再恢复;这是交换两个变量最稳的基础写法。
材料核对:本节笔记与转写稿不一致
给定的【本节笔记:BFC】只有标题,没有 BFC 的定义、示例代码、图片或调试记录;而转写稿实际讲的是 JavaScript 的 number、boolean、null、undefined、NaN、数字有效范围与 string。因此,不能依据现有材料编造 BFC 教程。下面仅按转写稿中可核验的内容整理成教程正文;未提供的图片不插入,口头代码按语义整理并纠正同音字。
为什么 number 要区分整数与浮点
为什么需要:很多语言有 int、float,因为整数和小数在二进制中的表示能力不同。怎么想:JS 对外只有一个 number 类型,但内部仍要面对“整数可精确转换、多数小数不能精确转换”的事实。怎么做:先用不同字面量观察输出:
js
let N01 = 764;
let N02 = 012; // 转写稿中的“零开头八进制”写法
let N03 = 0x12; // 十六进制
let N04 = 67.2;
console.log(N01, N02, N03, N04);012 按八进制解释为十进制 10,0x12 为十进制 18。现代代码更推荐写 0o12,避免旧八进制写法的歧义。易错点:八进制、十六进制字面量只能表示整数;0x12.5 这类写法会报语法错误。浮点计算要接受精度问题:
js
console.log(0.1 + 0.2); // 0.30000000000000004原因不是 JS “算错了”,而是 0.1、0.2 多数十进制小数无法精确转成二进制小数,运算后再转回十进制就出现误差。调试时不要用“肉眼相等”判断,应比较误差范围。
科学计数法:大数、小数的简写
为什么需要:极大或极小的数直接写很多 0 很累。怎么想:1.3e4 就是 1.3 × 10^4。怎么做:
js
let N05 = 1.3e4; // 13000
let N06 = 2.3e-2; // 0.023
console.log(N05, N06);易错点:e 只是语法记号;输出时控制台可能按普通形式或科学计数法显示,但“数还是那个数”。负数指数表示小数点前移,不是负一百。
NaN 与数字有效范围
为什么需要:其他类型转 number 时,不一定能得到有效数字,需要占位符;超出范围也需要特殊值。怎么想:NaN 全称 “Not a Number”,但类型仍是 number。怎么做:
js
console.log(typeof NaN); // "number"
console.log(NaN + 1); // NaN
console.log(NaN === NaN); // false
console.log(isNaN("hello")); // true
console.log(Number.MAX_VALUE); // 约 1.79e308
console.log(Number.MIN_VALUE); // 约 5e-324,最小正数
console.log(3e400); // Infinity
console.log(-3e400); // -Infinity
console.log(3e-400); // 0
console.log(isFinite(100)); // true
console.log(isFinite(Infinity));// false易错点:Number.MIN_VALUE 不是最小负数,而是最小正数;NaN 与任何数计算仍是 NaN,且不等于自身;isNaN("hello") 会先尝试转数字,转不成才为 true。Infinity、-Infinity、NaN 都是无效数字,参与后续计算要尽早拦截。
boolean、null、undefined:状态与空值
为什么需要:程序要表达真假和“没有值”。怎么想:boolean 只有 true/false;null 表示空;undefined 常表示未定义。怎么做:未赋值变量使用时得到 undefined。易错点:不必过度纠结 null 与 undefined 的“硬对比”,它们都常表示“没拿到有效结果”;不要依赖自动产生空值,关键数据应显式判断。
string 与转义字符
为什么需要:文本必须用引号界定。怎么想:单双引号在 JS 中基本无区别;引号内容里出现同类引号会提前结束字符串。怎么做:
js
let msg1 = 'hello';
let msg2 = "你好";
let msg3 = '锄禾日当午\n汗滴禾下土\n谁知盘中餐\n粒粒皆辛苦';
let msg4 = 'It\'s ok';
let msg5 = "他说:\"你好\"";
let msg6 = '\\n 原样显示反斜杠 n';
let msg7 = '\u0065'; // e
console.log(msg3, msg4, msg5, msg6, msg7);易错点:字符串里直接敲换行会破坏语法,应写 \n;要显示反斜杠本身写 \`;\u` 后接四位十六进制码点。转写稿中“单引号效率更高”的说法来自其他语言习惯,JS 单双引号本身无性能差异,团队按代码规范即可。
结论
现有材料没有 BFC 知识点,故本节只能按转写稿扩写 JS 数据类型;若需要 BFC 教程,请补充 BFC 的笔记、代码和转写稿。
课堂画面






代码示例
1. number 类型:整型、浮点、科学计数法、NaN、有效范围
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>number 类型示例</title>
</head>
<body>
<script>
var n01 = 764;
var n02 = 012; // 0 开头:八进制表示
var n03 = 0x12; // 0x 开头:十六进制表示
var n04 = 67.2; // 带小数点:浮点数
console.log(n01, n02, n03, n04);
// 浮点数计算精度问题
console.log(0.1 + 0.2);
// 科学计数法
var n05 = 1.3e4;
var n06 = 1.67e78;
var n07 = 2.3e-2;
console.log(n05, n06, n07);
// NaN:not a number,但类型仍是 number
console.log(NaN, typeof NaN);
console.log(NaN * 0, NaN / 189);
console.log(250 == 250, 250 == 150, NaN == NaN);
console.log(isNaN(NaN), isNaN('hello'), isNaN(250));
// 数字有效范围
console.log(Number.MAX_VALUE);
console.log(Number.MIN_VALUE); // 最小正数,不是最小数
var n08 = 3e400; // 超出范围:正无穷
var n09 = -3e400; // 负无穷
var n10 = 3e-400; // 比最小正数还小:变成 0
console.log(n08, n09, n10);
console.log(isFinite(100), isFinite(Infinity), isFinite(NaN));
// boolean、null、undefined
var t = true;
var f = false;
var empty = null;
var undef;
console.log(t, f, empty, undef);
</script>
</body>
</html>要点解释:
012是八进制表示,输出为十进制的10;0x12是十六进制表示,输出为十进制的18。0.1 + 0.2不会精确等于0.3,而是0.30000000000000004,这是十进制小数转二进制小数不能精确表示导致的。NaN的类型是number,它与任何数字计算结果还是NaN,并且NaN == NaN为false。Number.MIN_VALUE表示最小正数,不是最小数;最小数可用-Number.MAX_VALUE表示。3e400超出范围会变成Infinity,3e-400会变成0;isFinite(NaN)为false。null表示空,undefined表示未定义;声明变量但未赋值时得到undefined。- 易错点:
0开头和0x开头只能表示整数,浮点数不能这样写;开启严格模式后012这类八进制写法可能报错。
2. string 类型:单双引号、转义字符、换行、Unicode
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>string 类型示例</title>
</head>
<body>
<script>
var msg01 = 'hello高小乐';
var msg02 = "你好老头乐";
console.log(msg01, typeof msg01);
console.log(msg02, typeof msg02);
// 字符串内容中写同类引号:需要转义
var msg03 = '他说:\'你好\'';
var msg04 = "他说:\"你好\"";
console.log(msg03);
console.log(msg04);
// 反斜杠本身:用 \\ 表示
var msg05 = '在GS中可以使用\\n表示换行';
console.log(msg05);
// \n 表示换行
var msg06 = '锄禾日当午\n汗滴禾下土\n谁知盘中餐\n粒粒皆辛苦';
console.log(msg06);
// Unicode 编码:\u 后接四位十六进制数字
console.log('\u0065');
console.log('\u38AF');
</script>
</body>
</html>要点解释:
- 单引号和双引号都可以表示字符串,
typeof结果都是'string'。 - 单引号字符串里直接写单引号会提前结束字符串,导致语法错误;应换成双引号或使用
\'转义。 \n表示换行,字符串中不能直接敲一个真实换行来换行。\` 表示反斜杠本身,避免\n` 被解析成换行。\u0065表示 Unicode 编码对应的字符e;\u38AF表示另一个 Unicode 字符。- 易错点:
\u后面必须是四位十六进制数字;字符串中直接写未转义的同类引号会报语法错误。
3. 作业:交换两个变量的值
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>交换两个变量</title>
</head>
<body>
<script>
var a = 100;
var b = 200;
console.log('交换前:', a, b);
var temp = a;
a = b;
b = temp;
console.log('交换后:', a, b);
</script>
</body>
</html>要点解释:
- 先用
temp暂存a的原值,避免a被覆盖后丢失。 - 如果直接写
a = b; b = a;,最后a和b都会变成200。 - 交换顺序必须是:先暂存
a,再让a = b,最后让b = temp。 - 易错点:不要在没有临时变量的情况下直接互相赋值,否则原值会被覆盖。
常见错误
- 现象:
var n = 012; console.log(n)得到10,误以为12→ 原因:0开头被按八进制解析 → 修法:整数统一写十进制,避免前导0;需要八进制时显式写0o12。 - 现象:
0x1.8、0X12.3报错 → 原因:八进制/十六进制字面量只适用于整数 → 修法:浮点数只用十进制或科学计数法表示。 - 现象:
0.1 + 0.2 === 0.3为false→ 原因:十进制小数不能精确转成二进制小数 → 修法:浮点比较用误差阈值,如Math.abs(a - b) < Number.EPSILON;展示用toFixed()。 - 现象:
x === NaN永远为false,无法判断NaN→ 原因:NaN与任何值(包括自身)都不相等 → 修法:用Number.isNaN(x)或Object.is(x, NaN)。 - 现象:
isNaN('hello')为true,把字符串误判成NaN本身 → 原因:isNaN()会先做 number 转换 → 修法:先用Number.isNaN()判断值,或先检查typeof再转换。 - 现象:单引号字符串里直接写单引号,或字符串里直接敲换行导致语法错误 → 原因:引号提前闭合,换行提前结束语句 → 修法:外层换双引号、用
\'转义;换行写\n。 - 现象:
a = b; b = a;后两个变量值相同 → 原因:a的原值被覆盖 → 修法:先用临时变量保存原值,或用解构[a, b] = [b, a]。
练习
- 写出下列表达式的结果,并说明原因:
012、0x12、1.2e3、1.2e-3。 - 用至少两种方法交换
var a = 100; var b = 200;,并说明每种方法的限制。 - 写一个函数
isValidNumber(x):只有正常有效数字返回true,NaN、Infinity、-Infinity返回false。 - 写一个函数
isEqual(a, b),用于安全比较两个浮点数是否“相等”,并处理NaN。 - 用字符串输出两行内容,第一行包含
He said: "It's ok",第二行包含反斜杠\n字样,要求不产生语法错误。
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | number-整型和浮点 | 30:03 |
| 2 | number-科学计数法 | 06:42 |
| 3 | boolean、null、undefined | 02:13 |
| 4 | number-NaN | 09:26 |
| 5 | number-数字有效范围 | 09:57 |
| 6 | string | 13:34 |
小结
number对外是一个类型,但内部仍存在整数与浮点的运算差异。- 整数可用八进制、十六进制表示;浮点不能使用这些字面量形式。
- 浮点数不要直接用
===判断相等,应使用误差范围。 NaN是number类型,但属于无效数字,且不自等。NaN、Infinity、-Infinity都不应当作正常有效数字继续参与业务计算。- 字符串单双引号等价;嵌套引号靠换外层引号或转义解决,换行用
\n。 - 交换变量必须先保留原值,避免覆盖后再赋值。