阅读路线
1-6 8,10,11 12-19 24
1
宿主 版本
DOM
2
<script src="http://www.somewhere.com/afile.js"> </script>
2.1.4
脚本里加载脚本
2.1.5
XHTML 兼容
2.4
降级
3
'use strict'
2^53
var const let
var -- fuction
const, let -- {}
for (let i )
typeof 操作符
null 初始化
0.1+0.2
NaN NaN 不相等
isNaN(NaN);
Math.abs(1 / 3 - (1 - 2 / 3)) < 0.0000001; // true
parse 从头往后截
字符串不可变
方法、函数 变字符串
Template literals
`${}`
String.raw`\n`
output
console.log();
...expressions
标签函数
function tagF(strings, ...expressions){
}
Symbol () Symbol. for ()
new String() // object
操作符改变变量的值 ++age
前后缀不同
age-- + 20
一元操作符转换类型
NaN和Infinity在位操作中被当成0
~
取反-1
&
|
^
<<
null NaN undefined
! && ||
短路特性
let found = true;
let result = (found || someUndeclaredVariable); // 不会出错
console.log(result); // 会执行
+优先转字符串 -
转为数值 比较时有数值转数值 全是字符串比较编码
let num1 = 5;
let num2 = 10;
let message = "The sum of 5 and 10 is " + num1 + num2;
console.log(message); // "The sum of 5 and 10 is 510"
let num1 = 5;
let num2 = 10;
let message = "The sum of 5 and 10 is " + (num1 + num2); console.log(message); // "The sum of 5 and 10 is 15"
let result = "23" < "3"; // true
let result = "23" < 3; // false
null == undefined; // true
NaN == NaN; // false
"55" !== 55; // true
variable = boolean_expression ? true_value : false_value;
let max = (num1 > num2) ? num1 : num2;
let num1 = 1, num2 = 2, num3 = 3;
let i = 0;
do {
i += 2;
} while (i < 10);
let i = 0;
while (i < 10) {
i += 2; }
let count = 10;
for (let i = 0; i < count; i++) {
console.log(i);
}
for (;;) { // 无穷循环 doSomething();
}
for-in BOM
for (const el of [2,4,6,8]) {
document.write(el);
}
let num = 25;
switch (true) {
case num < 0:
console.log("Less than 0.");
break;
case num >= 0 && num <= 10:
console.log("Between 0 and 10.");
break;
case num > 10 && num <= 20:
console.log("Between 10 and 20.");
break;
default:
console.log("More than 20.");
}
注意 switch语句在比较每个条件的值时会使用全等操作符,因此不会强制转换数据类型(比如,字符串"10"不等于数值 10)
// 唯一的全局变量MYAPP:
let MYAPP = {};
// 其他变量:
MYAPP.name = 'myapp';
MYAPP.version = 1.0;
// 其他函数:
MYAPP.foo = function () {
return 'foo';
};
// 声明变量:
let x, y;
// 解构赋值:
({x, y} = { name: '小明', x: 100, y: 200});
// 语法错误: Uncaught SyntaxError: Unexpected token =
function buildDate({year, month, day, hour=0, minute=0, second=0}) {
return new Date(`${year}-${month}-${day} ${hour}:${minute}:${second}`);
}
4
原始值(primitive value)就是 最简单的数据,引用值(reference value)则是由多个值构成的对象。
6 种 原始值:Undefined、Null、Boolean、Number、String 和 Symbol。
引用值是保存在内存中的对象。在操作对象时,实际上操作的是对该对象的引用(reference)而非 实际的对象本身。为此,保存引用值的变量是按引用(by reference)访问的。对于引用值而言,可以随时添加、修改和删除其属性 和方法。
let person = new Object();
person.name = "Nicholas";
console.log(person.name); // "Nicholas"
let name = "Nicholas";
name.age = 27;
console.log(name.age); // undefined
ECMAScript 中所有函数的参数都是按值传递的。
function addTen(num) {
num += 10;
return num;
}
let count = 20;
let result = addTen(count); console.log(count); // 20,没有变化 console.log(result); // 30
function setName(obj) {
obj.name = "Nicholas";
}
let person = new Object();
setName(person);
console.log(person.name); // "Nicholas"
function setName(obj) { obj.name = "Nicholas"; obj = new Object(); obj.name = "Greg";
}
let person = new Object();
setName(person);
console.log(person.name); // "Nicholas"
为什么捏,因为传递的是值,函数(对象)的时候,在函数里有一个值的复制,这意味着一开始函数内外指针都指向一个对象,所以这时候加上. name 属性有用的 但是最后一个函数,在函数内部修改了指针,让它变成指向一个新的对象,这个改变就无法影响外部的对象的指针,所以后面的改变没用,在函数结束的时候就被销毁!
instance of
每个上下文都有一个关联的变量对象(variable object), 而这个上下文中定义的所有变量和函数都存在于这个对象上。虽然无法通过代码访问变量对象,但后台 处理数据会用到它。
浏览器中,全局上下文就是我们常说的 window 对象(第 12 章会详细介绍),因此所有通过 var 定 义的全局变量和函数都会成为 window 对象的属性和方法。
上下文中的代码在执行的时候,会创建变量对象的一个作用域链(scope chain)。这个作用域链决定 了各级上下文中的代码在访问变量和函数时的顺序。
var声明 无任何声明的话函数外也可以访问变量
提升
标记,引用计数 垃圾回收 性能
垃圾回收程序运行的时候,会标记内存中存储的所有变量(记住,标记方法有很多种)。然后,它 会将所有在上下文中的变量,以及被在上下文中的变量引用的变量的标记去掉。在此之后再被加上标记 的变量就是待删除的了,原因是任何在上下文中的变量都访问不到它们了。随后垃圾回收程序做一次内 存清理,销毁带标记的所有值并收回它们的内存。
fuction createName(name){
let localPerson = new Object();
localPerson.name = name;
return localPerson;
}
let globalPerson = createName("John");
globalPerson = null;
隐藏类
function Article(opt_author) {
this.title = 'Inauguration Ceremony Features Kazoo Band';
this.author = opt_author;
}
let a1 = new Article();
let a2 = new Article('Jake');
a1.author = null;
内存泄漏
减少执行垃圾回收的次数
虽然 `str1` 和 `str2` 都是 `"hello"`,但在 JavaScript 中,**原始值**是根据**值本身**比较的,只要内容相同,就会被认为是相等的。
原始值共享内存地址,但是对象即使内容相同,内存地址也不同
5 基本引用类型
自己划拉的
返回 UTC 时间 可以使用本地时间方法转换
2025-02-16T12:57:27.919Z
是 ISO 8601 格式的日期字符串,表示协调世界时(UTC)2025 年 2 月 16 日中午 12:57:27.919。这种格式常用于 Date 对象的字符串表示,比如通过调用 new Date().toISOString()
得到的结果。
常用的方法和操作
-
获取时间戳与转换
getTime()
:返回自 1970 年 1 月 1 日以来的毫秒数。Date.now()
:返回当前的时间戳(毫秒)。
-
获取日期和时间的各个部分
getFullYear()
:获取完整的年份(如 2025)。getMonth()
:获取月份(0-11,注意:0 表示1月,11 表示12月)。getDate()
:获取一个月中的第几天(1-31)。
可以自动处理跨月份 的情况getDay()
:获取星期几(0-6,0 表示星期天)。getHours()
、getMinutes()
、getSeconds()
、getMilliseconds()
:分别获取小时、分钟、秒和毫秒。
-
设置日期和时间的各个部分
setFullYear(year)
、setMonth(month)
、setDate(date)
等:用于设置年份、月份、日期等属性。- 同样也有
setHours()
、setMinutes()
、setSeconds()
、setMilliseconds()
。
-
格式化日期
-
toISOString()
:返回 ISO 8601 格式的字符串。YYYY-MM-DDTHH:mm:ss.sssZ
-
YYYY:四位数的年份(例如,2025)。
-
MM:两位数的月份,范围 01 至 12。
-
DD:两位数的日期,范围 01 至 31。
-
T:日期和时间的分隔符,固定为字母 T。
-
HH:两位数的小时(24 小时制),范围 00 至 23。
-
mm:两位数的分钟,范围 00 至 59。
-
ss:两位数的秒数,范围 00 至 59。
-
sss:三位数的毫秒,范围 000 至 999。
-
Z:表示该时间是以 UTC(协调世界时)表示的,字母 Z 表示“零时区”。
-
toString()
:返回一个更为易读的日期和时间字符串(具体格式依赖于运行环境)。 -
toLocaleString()
、toLocaleDateString()
、toLocaleTimeString()
:根据本地区域设置返回格式化后的日期/时间字符串。
-
-
本地时间方法 vs. UTC 方法:
-
本地时间方法:
getFullYear()
getMonth()
getDate()
getDay()
getHours()
getMinutes()
getSeconds()
getMilliseconds()
这些方法返回的是 Date 对象对应的当地时间(即你的系统时区)中的各个部分。
-
UTC 时间方法:
getUTCFullYear()
getUTCMonth()
getUTCDate()
getUTCDay()
getUTCHours()
getUTCMinutes()
getUTCSeconds()
getUTCMilliseconds()
这些方法返回的是对应的 UTC 时间部分。
为引用类型添加新的方法
挂载到原型链上
Date.prototype.addDays = function(days) {
const date = new Date(this.valueOf());
date.setDate(date.getDate() + days);
return date;
};
const today = new Date();
const tomorrow = today.addDays(1);
console.log(tomorrow);
书本内容
基本引用类型 Date ()
let date1 = new Date(2019, 0, 1); // 2019年1月1日
let date2 = new Date(2019, 1, 1); // 2019年2月1日
console.log(date1 < date2); // true
console.log(date1 > date2); // false
延伸: UTC等时间标准
RegExp 正则表达式
let expression = /pattern/flags;
\g \i
// 匹配第一个"bat"或"cat",忽略大小写
let pattern1 = /[bc]at/i;
// 跟 pattern1 一样,只不过是用构造函数创建的
let pattern2 = new RegExp("[bc]at", "i");
exec()
test()
let text = "mom and dad and baby";
let pattern = /mom( and dad( and baby)?)?/gi;
let matches = pattern.exec(text);
console.log(matches.index);
console.log(matches.input);
console.log(matches[0]);
console.log(matches[1]);
console.log(matches[2]);
//0
// "mom and dad and baby"
// "mom and dad and baby"
// " and dad and baby"
// " and baby"
注意 RegExp构造函数的所有属性都没有任何Web标准出处,因此不要在生产环境中使用它们。
包装类型
读模式
let s1 = "some text";
s1.color = "red";
console.log(s1.color); // undefined
let value = "25";
let number = Number(value);
console.log(typeof number);
let obj = new Number(value);
console.log(typeof obj);
// 转型函数 // "number" // 构造函数 // "object"
延伸:包装类型
我擦,字符串
.codePointAt()
.concat
slice(-4)
substring(4,-4)
let stringValue = "Lorem ipsum dolor sit amet, consectetur adipisicing elit";
let positions = new Array();
let pos = stringValue.indexOf("e");
while(pos > -1) {
positions.push(pos);
pos = stringValue.indexOf("e", pos + 1);
}
console.log(positions); // [3,24,32,35,52]
includes
for-of
迭代器
.match()
单例内置对象 不用显式实例化
encodeURI
window
Math.ceil()、Math.floor()、Math.round() 和 Math.fround()
注意 Math.random()方法在这里出于演示目的是没有问题的。如果是为了加密而需要 生成随机数(传给生成器的输入需要较高的不确定性),那么建议使用 window.crypto. getRandomValues()。
JavaScript 中的对象称为引用值,几种内置的引用类型可用于创建特定类型的对象。
JavaScript 比较独特的一点是,函数实际上是 Function 类型的实例,也就是说函数也是对象。因为函数也是对象,所以函数也有方法,可以用于增强其能力。
6 集合引用类型
对象字面量创建实例
Object 类型
let person = {
name: "Nicholas",
age: 29
};
console.log(person["name"]); // "Nicholas"
console.log(person.name); // "Nicholas"
使用中括号的主要优势就是可以通过变量访问属性
let propertyName = "name";
console.log(person[propertyName]); // "Nicholas"
第 8 章将更全面、深入地介绍 Object 类型。
数组 Array
数组的增删查改
增 看下面的栈和队列方法
删
查
find findlast
includes
改
创建数组 或者浅拷贝 嗯造新数组咯
- Array.from() from 支持
=>
- of
数组空位 hole undefined 就完事了
``
[,,,,]
数组索引 我了个可变长度啊
数组 length 不是只读 可以改变长度
array.lenth
始终可以指向即将添加的新元素
检测数组 这他妈的是数组吗?
if value instanceof Array
原型链
Array.isArray()
跨境使用
迭代器方法 获得数组里的东西
基本
const aKeys = Array.from(a.keys());
const aValues = Array.from(a.values()); const aEntries = Array.from(a.entries());
console.log(aKeys); // [0, 1, 2, 3]
console.log(aValues); // ["foo", "bar", "baz", "qux"] console.log(aEntries); // [[0, "foo"], [1, "bar"], [2, "baz"], [3, "qux"]]
扩展运算符
const aKeys = [...a.keys()]; 把a数组展开获得keys
复制和填充方法 简单分个身
fill(里面后两位可以比大小1,2,3)
copyWithin() 在数组里复制并覆盖内容
- 过界了不能用
转换方法 数组嗯造字符串
所有对象都有 toLocaleString()、toString()和 valueOf()方法
toLocaleString
顾名思义可以本地化 牛逼!
const price = 123456.789; console.log(price.toLocaleString('en-US', { style: 'currency', currency: 'USD' })); // "$123,456.79" console.log(price.toLocaleString('zh-CN', { style: 'currency', currency: 'CNY' })); // "¥123,456.79"
典中典之 array.join(',')
栈方法 我擦,栈!
a.push() a.pop() 都对最后一项
队列方法 我擦,队列!
a.shift()推出来第一项
unshift() 和shift相反 往开头塞东西
排序方法 把你资历发出来看看
a.reverse() a.sort()
a.sort 这个傻逼方法接收数值也还是当成字符串做比较 纯sb
给它擦屁股:
let values = [0, 1, 5, 10, 15];
values.sort((a, b) => a < b ? 1 : a > b ? -1 : 0);
返回1,-1,或者0
alert(values); // 15,10,5,1,0
操作方法 ✂️
concat(a,a2,a3)
把所有拼起来造新数组
打平=是否保留原数组作为一个元素合并到新数组
典中典之 a.slice()
a.splice() 两参数删 3参数插入 会返回被删的东西
搜索和位置方法 🔍
3 个严格相等的搜索方法:indexOf()、lastIndexOf()和 includes()
find()和 findIndex()方法使用了断言函数。这两个方法都从数组的最小索引开始。find()返回 第一个匹配的元素,findIndex()返回第一个匹配元素的索引。
alert(people.find((element, index, array) => element.age < 28)); // {name: "Matt", age: 27}
alert(people.findIndex((element, index, array) => element.age < 28)); // 0
迭代方法 对每一项
every():对数组每一项都运行传入的函数,如果对每一项函数都返回 true,则这个方法返回 true。
filter():对数组每一项都运行传入的函数,函数返回 true 的项会组成数组之后返回。
forEach():对数组每一项都运行传入的函数,没有返回值。
map((element,index)=>{fn}):对数组每一项都运行传入的函数,返回由每次函数调用的结果构成的数组。
some():对数组每一项都运行传入的函数,如果有一项函数返回 true,则这个方法返回 true。
归并方法 这次真的要聚了
reduce()和 reduceRight()
定型数组
为了提升传输数组的效率 => WebGL
ArrayBuffer()
分配内存
function foo() {
return { // 这里不会自动加分号,因为{表示语句尚未结束
name: 'foo'
};
}
function area_of_circle(r, pi) {
let size = 0;
if (arguments.length == 1){
size = (r ** 2) *3.14;
} else {
size = (r ** 2) * pi;
}
return size;
}
Map 键值对
Map 的大多数特性都可以通过 Object 类型实现,但二者之间还是存在一些细微的差异。
与 Object 只能使用数值、字符串或符号作为键不同,Map 可以使用任何 JavaScript 数据类型作为 键。
与 Object 类型的一个主要差异是,Map 实例会维护键值对的插入顺序,因此可以根据插入顺序执 行迭代操作。
基本操作 创建添加获取啥的
m.get ()
const m = new Map();
alert(m.has("firstName")); // false
alert(m.get("firstName")); // undefined
alert(m.size); // 0
m.set("firstName", "Matt")
.set("lastName", "Frisbie");
alert(m.has("firstName")); // true
alert(m.get("firstName")); // Matt
alert(m.size); // 2
m.delete("firstName"); // 只删除这一个键/值对
alert(m.has("firstName")); // false
alert(m.has("lastName")); // true
alert(m.size); // 1
m.clear(); // 清除这个映射实例中的所有键/值对
alert(m.has("firstName")); // false
alert(m.has("lastName")); // false
alert(m.size); // 0
顺序与迭代 按照插入顺序来
迭代器
m.entries (key)
for (let pair of m.entries()) {
alert(pair);
}
// [key1,val1]
// [key2,val2]
// [key3,val3]
const m = new Map([
["key1", "val1"],
["key2", "val2"],
["key3", "val3"]
]);
console.log([...m]); // [[key1,val1],[key2,val2],[key3,val3]]
回调
m.keys m.values
基本类型改不了 key 对象可以改内部属性但是引用不变
const keyObj = {id: 1};
const m = new Map([
[keyObj, "val1"]
]);
// 修改了作为键的对象的属性,但对象在映射内部仍然引用相同的值
for (let key of m.keys()) {
key.id = "newKey";
alert(key); // {id: "newKey"}
alert(m.get(keyObj)); // val1
}
alert(keyObj); // {id: "newKey"}
那选 Object 还是 Map 捏 键值对关系
一般 Map 综合强一点
WeakMap
弱映射中的键只能是 Object 或者继承自 Object 的类型,尝试使用非对象设置键会抛出 TypeError。值的类型没有限制。
不可迭代键
WeakMap 实例之所以限制只能用对象作为键,是为了保证只有通过键对象的引用才能取得值。如果 允许原始值,那就没办法区分初始化时使用的字符串字面量和初始化之后使用的一个相等的字符串了。
弱映射造就了在 JavaScript 中实现真正私有变量的一种新方式。前提很明确:私有变量会存储在弱 映射中
因为 WeakMap 实例不会妨碍垃圾回收,所以非常适合保存关联元数据。
如果这里使用的是弱映射,如以下代码所示,那么当节点从 DOM 树中被删除后,垃圾回收程序就 可以立即释放其内存(假设没有其他地方引用这个对象):
const wm = new WeakMap();
const loginButton = document.querySelector('#login');
// 给这个节点关联一些元数据 wm.set(loginButton, {disabled: true});
Set 像加强的 Map
什么是 Set
?
Set
是 ES6 引入的一种新的集合类型,用来存储唯一值的集合。它的主要特点是:
- 不允许重复元素(自动去重)。
- 元素的存储顺序基于插入顺序,但不像数组那样支持索引。
- 提供了专门的操作方法,比如
add()
、delete()
、has()
和clear()
。
示例:
javascript
复制编辑
const mySet = new Set(); mySet.add(1); // 添加元素 1 mySet.add(2); // 添加元素 2 mySet.add(1); // 重复元素不会被添加 console.log(mySet); // 输出:Set(2) { 1, 2 } console.log(mySet.has(1)); // true mySet.delete(2); // 删除元素 2 console.log(mySet); // Set(1) { 1 }
Set
的常见应用场景
-
去重:
- 去除数组中的重复值是
Set
的常见用法。
javascript
复制编辑
const arr = [1, 2, 2, 3, 4, 4]; const uniqueArr = [...new Set(arr)]; console.log(uniqueArr); // [1, 2, 3, 4]
- 去除数组中的重复值是
-
快速查找:
Set
的has()
方法查找效率高(接近 O(1)),适合在大量数据中判断某个值是否存在。
javascript
复制编辑
const uniqueValues = new Set([1, 2, 3, 4]); console.log(uniqueValues.has(3)); // true
-
集合操作(数学意义上的集合):
-
交集:
javascript
复制编辑
const setA = new Set([1, 2, 3]); const setB = new Set([2, 3, 4]); const intersection = new Set([...setA].filter(x => setB.has(x))); console.log(intersection); // Set { 2, 3 }
-
差集:
javascript
复制编辑
const difference = new Set([...setA].filter(x => !setB.has(x))); console.log(difference); // Set { 1 }
-
-
处理动态数据集合:
- 比如维护一个实时更新的用户在线列表或订阅者列表。