JavaScript 高级程序设计 读书笔记(第三章)
前几天小哆啦去参加了一场超有挑战性的面试,本以为凭借自己的聪明才智和平时积累的小本事,肯定能轻松应对。可没想到,面试官抛出的一些关于 JavaScript 的深入问题,让小哆啦有点招架不住。面试结束后,面试官人特别好,他看着小哆啦渴望知识的眼神,语重心长地建议小哆啦可以好好研究研究《JavaScript 高级程序设计》这本书,说里面的知识能帮小哆啦在编程的道路上突飞猛进。小哆啦一听,立马来了精神,下定决心要好好研读这本书,还开启了每日读书总结,打算把学到的知识都分享给大家。
第三章:基本概念的深度探索
在 JavaScript 的世界里,第三章的内容可以说是奠基石,它决定了你对这门语言的基本理解。如果你曾经因为 null == undefined 结果是 true 而怀疑人生,或者因为 typeof null 居然是 object 而一脸问号,那么恭喜你,这一章就是为你准备的。
1. ECMAScript 的基本类型
JavaScript 的数据类型大致分为两类:基本类型(Primitive Type) 和 引用类型(Reference Type)。掌握它们的区别,能让你在调试 Bug 时少掉几根头发。
基本类型(按值访问,存储在栈中)
Undefined:变量声明了但没赋值,默认是undefined,像是大雄的作业,每次老师问他写没写,他总说"还没写"。Null:表示"空对象指针",你可以理解成"有个位置,但里面空无一物",就像静香约你出去,结果你到地方才发现她放了你鸽子。Boolean:只有true和false,在逻辑判断时很重要(可惜人类世界的判断往往不止两个值)。Number:包括整数和浮点数,但浮点数的运算可能会让你崩溃,比如0.1 + 0.2 !== 0.3。String:字符串是不可变的,每次操作都会生成新字符串(拼接的时候一定要小心,别浪费性能)。Symbol(ES6):用来创建唯一值,避免变量冲突。BigInt(ES11):当Number.MAX_SAFE_INTEGER已经满足不了你的数学欲望时,你可以用BigInt处理大数运算。
引用类型(按引用访问,存储在堆中)
Object:一切皆对象,所有复杂结构都可以归结为对象。Array:JS 中的数组是动态类型的,可以存放不同类型的元素。Function:函数也是对象,可以赋值给变量,也可以作为参数传递。Date、RegExp、Error:这些都是内置对象,帮助我们处理各种高级功能。
深度理解:基本类型 vs 引用类型
基本类型存储在 栈内存 中,访问时是按值访问 ,而引用类型存储在 堆内存 中,访问时是按引用访问。
示例:
js
let a = 10;
let b = a;
b = 20;
console.log(a); // 10
console.log(b); // 20
这里 b = a 只是值的拷贝,所以修改 b 不会影响 a。
js
let obj1 = { name: "小哆啦" };
let obj2 = obj1;
obj2.name = "大雄";
console.log(obj1.name); // "大雄"
这里 obj2 = obj1 复制的是 引用 ,两个变量指向同一个对象,修改 obj2 也会影响 obj1。
2. 类型转换的"坑"
JavaScript 是弱类型语言,类型转换是家常便饭。但有时候它的转换逻辑会让你怀疑人生。
字符串与数字的转换
js
console.log(1 + "1"); // "11"
console.log(1 - "1"); // 0
+ 号在这里触发了字符串拼接,而 - 号则触发了隐式转换。
布尔值的转换
js
console.log(Boolean(0)); // false
console.log(Boolean("")); // false
console.log(Boolean("false")); // true
这里 "false" 不是空字符串,所以它被转换成 true,这在某些情况下可能会引发 Bug。
总结:
0、NaN、null、undefined、""这五个值转换为Boolean时会变成false。- 其他所有值,包括
"false"、[]、{}都会转换成true。
3. 严格模式("use strict")
严格模式可以让 JavaScript 变得更加严格,避免一些潜在的错误。
示例:
js
"use strict";
x = 10; // 报错:x is not defined
在严格模式下,未声明的变量不能被赋值,防止意外创建全局变量。
严格模式的优点:
- 禁止使用
with语句。 - 禁止给
NaN、Infinity赋值。 - 函数中的
this默认不再指向window,而是undefined。
4. 作用域与变量提升
JavaScript 采用 词法作用域,也就是作用域在定义时就确定了。
示例:
js
function foo() {
var a = 10;
function bar() {
console.log(a);
}
return bar;
}
let baz = foo();
baz(); // 10
这里 bar 形成了闭包,依然能访问 foo 内部的 a。
变量提升(Hoisting)
js
console.log(a); // undefined
var a = 10;
var 声明的变量会被提升,但不会赋值。
js
console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 20;
let 和 const 声明的变量不会被提升,访问前必须声明。
总结
- 基本类型 vs 引用类型:基本类型存储在栈,按值传递;引用类型存储在堆,按引用传递。
- 隐式类型转换 :
+可能触发字符串拼接,-可能触发数字转换。 - 严格模式 :防止意外创建全局变量,修正
this指向。 - 作用域 & 变量提升 :JS 采用词法作用域,
var有变量提升,let/const没有。
以上就是第三章的读书笔记,下一篇我们深入解析第四章,聊聊变量、作用域和垃圾回收!