6
Array
js 的 Array 是 Object 数组,每个槽位可以存储任意类型的数据。
如果把一个值设置给超过数组最大索引的索引,数组会自动扩展,中间元素都是undefined。
数组的 length 属性不是只读的,通过修改 length 属性可以从数组末尾删除或添加元素。
push()/pop() 栈,push()/shift() 队列
sort() 会在每一项上调用 String()转型函数,然后比较字符串来决定顺序。
定型数组 TypedArray
ArrayBuffer 是所有定型数组及视图引用的基本单位。ArrayBuffer 某种程度上类似于 C++的 malloc()。
7 iterator和generator
迭代器 next() 方法返回的 IteratorResult 对象包含属性 done 和 value。每个迭代器都表示对 Iterable 对象的一次性有序遍历。
用 yield 实现输入输出:yield val1 向外输出val1,外面 g.next(val2) 用 val2 代替 yield val1 处的值,若 g.next() 则 yield val1 处的值为 undefined。
联系 python 中的 yield
用 yield* 迭代Iterable对象:
// function* generatorFn() {
// for (const x of [1, 2, 3]) {
// yield x;
// }
// }
function* generatorFn() {
yield* [1, 2, 3];
}yield*最有用的地方是实现递归操作:
function* nTimes(n) {
if (n > 0) {
yield* nTimes(n-1);
yield n-1;
}
}
for (const x of nTimes(3)) {
console.log(x);
}
// 0
// 1
// 28 类
解构并不要求变量必须在解构表达式中声明。不过,如果是给事先声明的变量赋值,则赋值表达式必须包含在一对括号中:
let personName, personAge;
let person = {
name: "Matt",
age: 27,
};
({ name: personName, age: personAge } = person);
console.log(personName, personAge); // Matt, 27类定义:
class Person {
constructor() {
// 添加到this的所有内容都会存在于不同的实例上
this.locate = () => console.log("instance", this);
}
// 定义在类的原型对象上
locate() {
console.log("prototype", this);
}
//定义在类本身上
static locate() {
console.log("class", this);
}
}
let p = new Person();
p.locate(); // instance, Person {}
Person.prototype.locate(); // prototype, {constructor: ... }
Person.locate(); // class, class Person {}20
transferable 对象
transferable 对象就是有 move 语义的 object,把所有权从一个线程转移到另一个线程,有:ArrayBuffer、MessagePort、ImageBitmap、OffscreenCanvas
postMessage()的 2nd 可选参数指定 transferable 对象数组:
// main.js
worker.postMessage(arrBuf); // 不转移
worker.postMessage(arrBuf, [arrBuf]); // 转移SharedArrayBuffer可在多 、、
间共享引用,Atomics api 可保护 SharedArrayBuffer 原子访问:
// main.js
worker.postMessage(sharedArrBuf); // 不转移
// worker.js
Atomics.add(sharedArrBuf, 0, 1);24
CORS
CORS(Cross-Origin Resource Sharing,跨源资源共享)的基本思路是使用自定义的 HTTP 头部允许 client 和 server 互相了解。
25 client 端存储
cookie
- 有数量和 4k 大小限制
- expires 设成过去时间就能删除
- 只能存一个 kv 对,多个 kv 对可以编码成值后放到这个 kv 对里
- http-only 只能服务端读取
web storage
kv 存储:
- sessionStorage 存储到浏览器关闭
- localStorage 存储到清除浏览器缓存。要访问 localStorage 对象,页面必须来自同一个域(子域不行)、在相同端口上使用相同协议。
监听 storage 事件:
window.addEventListener("storage", (event) =>
alert("Storage changed for ${event.domain}")
);每个源(协议、域和端口)一般限制 5MB
IndexedDB
对象存储,异步 API:.onerror(), .onsuccess()
如果想取得多条数据,需要在事务中创建一个游标(cursor)。游标是一个指向结果集的指针。与传统数据库查询不同,游标不会事先收集所有结果。相反,游标指向第一个结果,并在接到指令前不会主动查找下一条数据。
版本变化只能在只有一个标签页使用数据库时才能完成。应该在每次成功打开数据库后都添加onversionchange事件处理程序。
let req, db;
req = indexedDB.open(<user>, <passwd>);
req.onsuccess = (event) => {
db = event.target.result;
db.onversionchange = () => db.close();
}每个源(协议、域和端口)一般限制 5MB
27 web worker
每个页面都有自己的单线程 js 环境,web worker 在页面环境外创建一个独立的单线程 js 环境,web worker 和页面环境不一定同属一个进程
三种 web worker
- (dedicated) worker,只能被创建它的页面使用。也称后台脚本,只能使用同源脚本创建,但 worker 内部可
importScripts()加载其他源的脚本。 - shared worker,可以被不同页面使用。使用与创建共享 worker 的脚本同源的脚本创建,可与共享 worker 收发消息。
- service worker,拦截请求、缓存响应,可让网页离线使用
worker
页面内创建 worker 时返回与 worker 交互的代理对象。
页面和 worker 间通信可在代理对象或 worker 上postMessage()。
两 worker 间通信可在页面内创建MessageChannel,并将 channel 的两 port 传给两 worker,然后两 worker 在 port 上postMessage()。
同源脚本间通信还能使用BroadcastChannel。
worker 脚本内部的self是WorkerGlobalScope子类对象。
终止 worker:在 worker 脚本内self.close()异步终止,或从页面内worker.terminate()同步终止。
shared worker
在脚本 url 和 worker 名称都相同时只增加引用计数,不创建新 worker
- 相对 url 和绝对 url 视为相同 url
- url 后带和没带
?视为不同 url
service worker
两个主要作用:充当网络缓存、启用推送通知
只能在 https 下使用,多个同源页面共享一个 service worker
在navigator.serviceWorker实例上注册脚本:
navigator.serviceWorker.register("./serviceWorker.js");caches是个双层字典:
str => Cache{ Request/URL => Response }
clients跟踪关联的 window、worker、shared worker
参考
- JavaScript 高级程序设计