in file
"use strict";
// code
in chrome dev tools
"use strict"; // Shift+Enter
// code Enter
in old browser
(function () {
"use strict";
// code
});
Default open strict mode on use Class or modules
- boolean
- number: 小于 2^53, 大于 -(2^53)的整数
- bigint: 任意范围内的整数
- string
- null
- undefined
- symbol
- object: array, function, object
- alert: 模态框信息
- prompt: 模态输入框
- confirm: 模态选择框
- 数字转字符 String()
- 字符转数字 Number(), parseInt(), parseFloat()
- Number 转换规则
- undefined <=> NaN
- null <=> 0
- true <=> 1
- false <=> 0
- '' <=> 0
- '123' <=> 123
- '哈哈 agss' <=> NaN
- Number 转换规则
- bool 转换: Boolean()
未定义的变量作为判断条件, 与下面表达式相同
let a;
const res1 = a ?? "haha";
const res2 = a === undefined || a === null ? "haha" : a;
// 支持循环前的标签, 标签是 break/continue 跳出嵌套循环可以转到外部的唯一方法
outer: for (let i = 0; i < 3; i++) {
if (i === 1) {
continue outer;
}
console.log(i);
}
函数声明: 主代码中声明位单独的语句的函数
- 定义之前可被调用
function sum() {
console.log("sum");
}
函数表达式: 在一个表达式中或另一个语法结构中创建的函数
- 定义后才可调用
let sum = function () {
console.log("sum");
};
大多数情况下, 需要声明一个函数时, 首先考虑函数声明语法, 它能够为组织代码提供更多的灵活性, 因为我们可以在声明之前调用这些函数
- 多词属性名必须加引号, 且只能使用中括号访问
let user = {
"like birds": true,
};
console.log(user["like birds"]);
- 计算属性
let fruit = prompt("which fruit to buy?", "apple");
let bag = {};
bag[fruit] = 5;
- in 关键字判断是否在对象中, 尤其是当属性 key 存在, 但 value 为 undefined 的时候
let use = { name: "meng", age: 11, eat: undefined };
console.log(name in use);
console.log(eat in use);
- for...in 迭代对象
let user = { name: "meng", age: 11 };
for (const key in user) {
console.log(key, user[key]);
}
- 对象排序
对象有特别的顺序: 整数属性会被进行排序, 其他属性按照创建的顺序展示
整数属性: 一个可以不做任何更改的情况下与一个整数进行相互转换的字符串
const codes = {
3: "yu",
2: "xiang",
1: "meng",
};
Object.keys(codes).map((item) => console.log(item));
- 复制对象
使用 for in
const user = { name: "meng", age: 11 };
const newUser = {};
for (const key in user) {
newUser[key] = user[key];
}
使用 Object.assign
const newUser = Object.assign({}, user);
可达性: 如果一个值通过引用链从根访问任何其他值, 则认为该值是可达的
- 当前执行的函数, 它的局部变量和参数
- 当前嵌套调用链上的其他函数, 他们的局部变量和参数
- 全局变量
垃圾回收的基本算法被称为: 'mark-and-sweep'
定期执行以下步骤进行垃圾回收:
- 垃圾收集器找到所有的根, 并标记他们
- 然后遍历并标记他们所有的引用
- 然后遍历标记的对象标记他们的引用, 所有被遍历到的对象都会被记住, 以免再次遍历到同一对象
- 没有被标记的对象都会被删除
一些优化建议
- 分代收集: 对象被分成两组, 新的和旧的, 频繁检查新对象是否需要清除, 检查旧对象频率降低
- 增量收集: 将整个对象拆分为多个部分, 将这些部分逐一清除, 这样会有很多小型的垃圾回收, 会带来微小的延迟, 而不是大的延迟
- 闲时收集: 在 CPU 空闲时尝试运行, 减少可能对代码执行的影响
当一个函数被使用 new 操作符执行时, 按照以下步骤创建
- 一个新的空对象被创建并分配给 this
- 函数体执行, 通常会修改 this, 为其添加新的属性
- 返回 this 的值
构造器的目的---实现可重用的对象创建代码
在一个函数内部是否进行了 new 调用, 可以使用 new.target, 调用返回该函数, 每调用则返回 undefined
省略括号: 如果没有参数, 可以省略 new 后的括号
let user = new User; === let user = new User();
实现一个 new 函数
function new(Con, ...args){
const obj = Object.create(Con);
const result = Con.apply(obj, args);
return result instanceof Object ? result : obj;
}
总结:
- 构造函数, 或简称构造器, 就是常规函数, 但对于构造函数要大写, 这是约定
- 构造函数只能使用 new 来调用, 这样的调用意味着再开始时创建了空的 this, 并在最后返回填充了值的 this
检查左边部分是否为 undefined 或者 null
const user = [
{
name() {
console.log("I am pangyujs");
},
},
];
const result = user?.[0]?.name?.();
注意: 可选链不要过度使用, 否则可能引起代码中的错误被消除, 可选链具有短路效应
只有 string 和 symbol 可以作为对象的属性键, symbol 保证全局唯一
- symbol 不会自动转为字符串, 使用 symbol.toString() 或者 symbol.description
- 全局唯一可以保证隐藏属性, 例如三方库使用 symbol 防止用户篡改代码
- 在 for in 和 object.keys 会被跳过, 但 Object.getOwnPropertySymbols(obj) 和 Reflect.ownKeys(obj) 可以获取一个对象的所有键, 包括 symbol
- object.assign 会复制字符串和 symbol 属性
全局 symbol
应用程序的不同部分想要访问 symbol, 完全相同的属性, 此时可以从全局 symbol 注册表中读取
const id = Symbol.for("id"); // 返回symbol
const idAgain = Symbol.for("id");
const idKey = Symbol.keyFor(id); // id 返回symbol的key, 只适用于全局symbol
console.log(id === idAgain);
可以使用它们来微调对象的各个方面
- 所以对象都为 true
- 数字转换发生在对象相减或应用数学函数时, 例如 Date 可以实现两个日期的差值计算
- 字符串转化, 通常发生在想 alert(obj), 会隐式调用对象的 toString 方法
类型转换有三种变体, 称为 hint
- string
对象转字符串, 对期望一个字符串的对象执行操作时, 如 alert
alert(obj);
obj1[obj] = 123;
- number 对象到数字的转换, 如进行数学运算时
const num = Number(obj);
const n = +obj;
const delta = date2 - date2;
const greater = user1 > user2;
- default
在少数情况下发生, 当运算符"不确定"期望值的类型时, 如二元加法, 判断于字符串, 数字, symbol 比较
let total = obj1 + obj2;
if (obj1 === 1) {
}
如果此方法存在, 则会被用于所有 hint
let user = {
name: "meng",
money: 1000,
[Symbol.toPrimitive](hint) {
console.log("hint=", hint);
return hint === "string" ? `{name: "${this.name}"}` : this.money;
},
};
console.log(user);
console.log(+user);
console.log(user + 500);
如果没有 Symbol.toPrimitive, 那么 js 尝试寻找 toString 和 valueOf 方法
- 对于 string hint: 调用 toString 方法, 如果不存在, 调用 valueOf 方法, 因此对于字符串转换, 优先调用 toString 方法
- 对于其他 hint: 调用 valueOf 方法, 如果不存在, 则调用 toString 方法, 因此对于数学运算, 优先调用 valueOf 方法
alert(user); // [object Object]
alert(user.valueOf() === user); // true
实现 toString 和 valueOf
let user = {
name: "meng",
money: 1000,
toString() {
return `{name: ${this.name}}`;
},
valueOf() {
return this.money;
},
};
alert(user); // toString -> {name: "John"}
alert(+user); // valueOf -> 1000
alert(user + 500); // valueOf -> 1500
通常希望有一个"全能"的地方来处理原始转换, 可以只实现 toString()方法, 这将处理所有原始转换
总结:
对象到原始值的转换, 是由许多期望以原始值作为值的内建函数和运算符自动调用的
有三种类型(hint):
- string, 对于 alert 和其他需要字符串的操作
- number, 对于数学运算
- default, 少数运算符, 通常对象以和 number 相同的方式实现 default 转换
转换算法是:
- 调用 objSymbol.toPrimitive, 如果这个方法存在
- 否则, 如果 hint 为 string, 尝试调用 toString 或者 valueOf
- 否则, 如果 hint 为 number 或者 default, 尝试调用 valueOf 或者 toString
所有方法必须返回一个原始值才能工作, 实际使用中只实现 toString 方法就够了
Symbol.iterator
const range = {
from: 1,
to: 5,
[Symbol.iterator]() {
return {
current: this.from,
last: this.to,
next() {
if (this.current <= this.last) {
return { done: false, value: this.current++ };
} else {
return { done: true };
}
},
};
},
};
for (let num of range) {
console.log("num=====", num);
}
Array.from: 可以转换一个类数组为真数组
Map 是一个带键的数据项的集合
- new Map([iterable]), 创建 map, 可选择带有 [key,value] 对的 iterable 来进行初始化
- map.set(key, value), 根据键存值, 返回 map 自身, 可链式调用
- map.get(key), 根据键返回值, 如果不存在此键, 则返回 undefined
- map.has(key), 如果 key 存在则返回 true, 否则返回 false
- map.delete(key), 删除制定的键对应的值, 如果删除成功返回 true, 否则返回 false
- map.clear(), 清空 map
- map.size, 返回当前元素个数
与普通 Object 不同点
- 任何键, 对象都可以作为键
- 有其他的便捷方法, 如 size 属性
Set 是一组唯一值的集合
- new Set([iterable]), 创建 set, 可选择带有 iterable 来进行初始化
- set.add(value), 添加一个值, 返回 set 本身
- set.delete(value), 删除成功为 true, 否则为 false
- set.has(value), 存在返回 true, 否则返回 false
- set.clear(), 清空 set
- set.size, 返回元素的个数
WeakMap 和 WeakSet 被用作"主要"对象存储之外的"辅助"数据结构, 一旦对象从主存储器中删除, 如果该对象仅被用作 WeakMap 或 WeakMap 的键, 那么该对象会自动清除
- JS 中, 日期和时间使用 Date 对象来表示, 我们不能单独创建日期和时间, Date 对象总是同时创建两者
- 月份从 0 开始计数
- 一周的某一天 getDay()同样从 0 开始计算
- 当设置了超出范围的组件时, Date 会进行自动校准
- 日期可以相减, 得到的是一 ms 为单位的两者差值
- 使用 Date.now() 可以更快的获取当地时间的时间戳
- 浏览器有 performance.now() 的方法给出从页面加载开始以毫秒为单位的微秒数
- JSON 是一种数据格式, 具有自己的独立标准和大多数编程语言的库
- JSON 支持 Object, array, string, number, boolean 和 null
- JS 提供反序列化成 JSON 的方法 JSON.stringify() 和解析 JSON 的方法 JSON.parse
- 两种方法都支持用于智能读写的转换函数
- 如果一个对象有 toJSON, 那么它会被 JSON.stringify 调用