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 引用类型
基本类型存储在 栈内存 中,访问时是按值访问,而引用类型存储在 堆内存 中,访问时是按引用访问。
示例:
let a = 10;
let b = a;
b = 20;
console.log(a); // 10
console.log(b); // 20
这里 b = a
只是值的拷贝,所以修改 b
不会影响 a
。
let obj1 = { name: "小哆啦" };
let obj2 = obj1;
obj2.name = "大雄";
console.log(obj1.name); // "大雄"
这里 obj2 = obj1
复制的是 引用,两个变量指向同一个对象,修改 obj2
也会影响 obj1
。
2. 类型转换的“坑”
JavaScript 是弱类型语言,类型转换是家常便饭。但有时候它的转换逻辑会让你怀疑人生。
字符串与数字的转换
console.log(1 + "1"); // "11"
console.log(1 - "1"); // 0
+
号在这里触发了字符串拼接,而 -
号则触发了隐式转换。
布尔值的转换
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 变得更加严格,避免一些潜在的错误。
示例:
"use strict";
x = 10; // 报错:x is not defined
在严格模式下,未声明的变量不能被赋值,防止意外创建全局变量。
严格模式的优点:
- 禁止使用
with
语句。 - 禁止给
NaN
、Infinity
赋值。 - 函数中的
this
默认不再指向window
,而是undefined
。
4. 作用域与变量提升
JavaScript 采用 词法作用域,也就是作用域在定义时就确定了。
示例:
function foo() {
var a = 10;
function bar() {
console.log(a);
}
return bar;
}
let baz = foo();
baz(); // 10
这里 bar
形成了闭包,依然能访问 foo
内部的 a
。
变量提升(Hoisting)
console.log(a); // undefined
var a = 10;
var
声明的变量会被提升,但不会赋值。
console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 20;
let
和 const
声明的变量不会被提升,访问前必须声明。
总结
- 基本类型 vs 引用类型:基本类型存储在栈,按值传递;引用类型存储在堆,按引用传递。
- 隐式类型转换:
+
可能触发字符串拼接,-
可能触发数字转换。 - 严格模式:防止意外创建全局变量,修正
this
指向。 - 作用域 & 变量提升:JS 采用词法作用域,
var
有变量提升,let/const
没有。
以上就是第三章的读书笔记,下一篇我们深入解析第四章,聊聊变量、作用域和垃圾回收!