# ...
运算符
剩余参数:在函数定义中用于接受传入的多余参数。
扩展运算符:可以将一个数组 or 对象的元素展开。
1 | const func = (a, b, ...args) => { // 接受剩余的[4, 5, 6] |
# 数组
1 | let arr = [1, 2, 3]; |
[]
访问超过数组长度的下标时,数组长度会自动扩充,剩余为空槽。
1 | const cmp = (a, b) => { |
JS
中的自定义比较函数有三个返回值, -1, 1, 0
。
# 带键的集合 Map 、Set
- Map 中的键可以任意类型, 而 Object 的键只能是 String 或 Symbol(接受 String 参数的别名)。
- Map 将原始值存储为键, 而 Object 将每个键都视为字符串。
- Map 和 Set 的遍历顺序都是其插入的顺序。
# 继承与原型链
在 JS
中, 继承是通过对象实现的。每个对象都有一条链接到另一个称为原型的对象的内部链,以此类推,直到原型为 null
的对象作为原型链的最后的一环。这个过程是动态的,即你可以在运行时修改原型链上的任何成员。
# 继承属性
每个对象都有一条指向原型对象的链, 当需要访问对象的属性时, 会先访问该对象本身,如果没找到会继续往它的原型上查找属性。如果跟原型都存在相同的属性,原型上的属性值会被遮蔽。\
备注:根据 ECMAScript 标准,符号
someObject.[[Prototype]]
用于指定someObject
的原型。使用Object.getPrototypeOf()
和Object.setPrototypeOf()
函数分别访问和修改 [[Prototype]] 内部插槽。这与 JavaScript 访问器__proto__
是等价的,后者是非标准的,但许多 JavaScript 引擎实际上实现了它。为了保持简洁和避免困惑,在我们的表示法中,我们会避免使用obj.__proto__
,而是使用obj.[[Prototype]]
。其对应于Object.getPrototypeOf(obj)
。
注意:虽然 obj.__proto__
访问器时非标准的,但是 { __proto__: ... }
语法是标准的。
1 | const myObj = { |
注意: Object.prototype
隐式的成为了原型, Array
和 RegExp
、 Function
也是一样的都有自己的原型, 并且它们的原型的原型还是 Object.prototype
。但箭头函数没有原型。
1 | function doSomething() {} |
# 创建对象和改变原型链的方法总结
# 语法结构创建
1 | const myObj = { |
# 构造函数
使用 new ()
创建对象,调用原型的构造函数。
# 使用 Object.create()
调用 Object.create()
会创建一个新对象。该对象的 [[Prototype]]
是该函数的第一个参数,如果不传参, 则为 Object.prototype
。
# 使用类 extends
声明类的后面跟上 extends
指定要继承的类。
# 使用 Object.setPrototypeOf()
传入两个参数 (a, b)
,表示吧 a 的原型设为 b。
# 使用 __proto__
访问器 (非标准)。
__proto__
访问器# 性能
查找位于原型链上层的属性花费的时间可能会对性能有负面影响。所以在检查对象本身是否存在某个属性的时候,可以使用 hasOwnProperty
或者 Object.hasOwn
方法。
# 类
# 私有字段
在属性 or 方法前面加上 #
, 即可将其定义为私有字段。私有属性只能在类内部访问,私有方法只能在类内部调用。
# 静态属性
在方法前面加上 static
, 这个方法不能从实例中访问, 只能通过类调用。
# 扩展与继承
如上面的 extends
, 即派生类。
# 迭代器和生成器
# 迭代器
迭代器是一个对象,它通过 next()
方法去迭代某个实现了迭代器协议的对象。其返回拥有两个属性的对象:
- value: 迭代序列的下一个值。
- done:
true
则为迭代结束。
1 | function makeRangeIterator(start = 0, end = Infinity, step = 1) { |
上面的代码,首先从创建了 makeRangeIterator
函数,然后在里面创建了 rangeIterator
对象,然后使用它的 next()
方法来创建迭代器。函数的返回值是一个迭代器对象,它可以用 next()
来进行持续迭代。
# 生成器函数
上面实现的是自定义迭代器,但是 JS
中提供了更方便的工具(Generator 函数)来作为迭代算法。它使用 function*
语法编写。
这种生成器函数返回一种特殊迭代器 - 生成器。每次调用 next()
将会执行,直至遇到 yield
关键字得到值。
1 | function* makeRangeIterator(start = 0, end = Infinity, step = 1) { |
这是使用 function*
对上面代码的改写。
# 自定义的可迭代对象
常见的可迭代对象有 Array
和 Map
等。它们可以通过 for...of
循环遍历。
如果想让 Object
也变为可迭代器:
- 实现
[Symbol.iterator]()
方法,返回一个带有next()
方法的迭代器对象。 - 实现
*[Symbol.iterator]()
方法,返回一个生成器对象,支持yield
关键字,这种方法更加自然。
1 | const myIterable = { |
1 | const myIterable = { |
# 高级生成器
next()
也可以接受参数以修改生成器的状态,常见做法是根据参数重启生成器。