6

Array

js 的 Array 是 Object 数组,每个槽位可以存储任意类型的数据。

如果把一个值设置给超过数组最大索引的索引,数组会自动扩展,中间元素都是undefined

数组的 length 属性不是只读的,通过修改 length 属性可以从数组末尾删除或添加元素。

push()/pop() 栈,push()/shift() 队列

sort() 会在每一项上调用 String()转型函数,然后比较字符串来决定顺序。

定型数组 TypedArray

ArrayBuffer 是所有定型数组及视图引用的基本单位。ArrayBuffer 某种程度上类似于 C++的 malloc()。

7 iterator和generator

迭代器 next() 方法返回的 IteratorResult 对象包含属性 donevalue。每个迭代器都表示对 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;
//    }
// }
functiongeneratorFn() {
  yield* [1, 2, 3];
}

yield*最有用的地方是实现递归操作:

functionnTimes(n) {
  if (n > 0) {
    yieldnTimes(n-1);
    yield n-1;
  }
}
for (const x of nTimes(3)) {
  console.log(x);
}
// 0
// 1
// 2

8 类

解构并不要求变量必须在解构表达式中声明。不过,如果是给事先声明的变量赋值,则赋值表达式必须包含在一对括号中:

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,把所有权从一个线程转移到另一个线程,有:ArrayBufferMessagePortImageBitmapOffscreenCanvas

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 端存储

  • 有数量和 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 脚本内部的selfWorkerGlobalScope子类对象。

终止 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 高级程序设计