X

曜彤.手记

随记,关于互联网技术、产品与创业

吉 ICP 备10004938号

《JavaScript 高级程序设计(第四版)》读书笔记(第 18-28 章)


书接上回,本文为第 18-28 章的笔记。

第 18 章 - 动画与 Canvas 图形

  1. (Page:1317)window.requestAnimationFrame()
window.addEventListener('scroll', () => {
  window.requestAnimationFrame(() => {
    console.log('dadadada...');
  });
});
  1. (Page:1323)Canvas 与 WebGL:(略);

第 19 章 - 表单脚本

(略)

第 20 章 - JavaScript API

  1. (Page:1452)AtomicsSharedArrayBuffer
const view = new Uint32Array(new SharedArrayBuffer(4));
const workers = [];
const workerScript = `
  const DEFAULT_INDEX = 0;
  self.onmessage = ({ data }) => {
    data[DEFAULT_INDEX]++;
    Atomics.store(data, DEFAULT_INDEX, 
      Atomics.load(data, DEFAULT_INDEX));
    console.log(data[DEFAULT_INDEX]);
  }
`;
for (let i = 0; i < 4; ++i) {
  workers.push(
    new Worker(
      URL.createObjectURL(
        new Blob([workerScript]))));
}
for (worker of workers) {
  worker.postMessage(view);
}
const view = new Int32Array(new SharedArrayBuffer(4));
const workers = [];
const workerScript = `
  self.onmessage = ({ data }) => {
    console.log('Wait to obtain lock...');
    Atomics.wait(data, 0, 0, 1e6);
    console.log('Obtained lock...');
    Atomics.add(data, 0, 1);
    console.log('Releasing lock...');
    Atomics.notify(data, 0, 1);
    console.log(Atomics.load(data, 0, 1));
  }
`;
for (let i = 0; i < 4; ++i) {
  workers.push(
    new Worker(
      URL.createObjectURL(
        new Blob([workerScript]))));
}
for (worker of workers) {
  worker.postMessage(view);
}
setTimeout(() => {
  Atomics.notify(view, 0, 1);
}, 1000);
  1. (Page:1466)跨上下文消息:是一种在不同执行上下文(如不同工作线程或不同源的页面)间传递信息的能力
<!-- parent.html -->
<html>
<body>
  <iframe src="http://localhost:3000/child.html"></iframe>
  <script type="text/javascript">
    window.addEventListener('load', () => {
      let iframeWin = document.querySelector('iframe').contentWindow;
      iframeWin.postMessage('A secret', 'http://localhost:3000');
    });
    window.addEventListener('message', event => {
      if (event.data) {
        console.log(`Received from iframe... ${event.data}`);
      }
    });
  </script>
</body>
</html>
<!-- child.html -->
<html>
<body>
  <script type="text/javascript">
    window.addEventListener('message', event => {
      if (event.origin === 'http://localhost:3000' && event.data) {
        console.log(`Iframe received... ${event.data}`);
        event.source.postMessage('Confirmed!', 'http://localhost:3000');
      }
    });
  </script>
</body>
</html>
  1. (Page:1469)Encoding API:用于实现字符串与 TypedArray 之间的转换Firefox 与 Safari 不支持)。
  1. (Page:1480)File APIBlob API
  1. (Page:1491)媒体元素 & HTML5 拖放:(略);
  2. (Page:1513)Notifications API
Notification.requestPermission().then(p => {
  if (p === 'granted') console.log('Notification enabled.')
});
const noti = new Notification('Congrats!', {
  body: 'You won $1000!',
  vibrate: true,
});
// lifecycles.
noti.onshow = () => console.log('Notification was shown!');
noti.onclick = () => console.log('Notification was clicked!');
noti.onclose = () => console.log('Notification was closed!');
noti.onerror = () => console.log('Notification experienced an error!');
  1. (Page:1517)Page Visibility API:(略);
  2. (Page:1518)Streams API
async function* ints() {
  for (let i = 0; i < 5; ++i) {
    yield await new Promise(resolve => setTimeout(resolve, 1000, i));
  }
}
const readableStream = new ReadableStream({
  async start(controller) {
    for await (let chunk of ints()) {
      // enqueue the data of this stream.
      controller.enqueue(chunk);
    }
    controller.close();
  }
});
const readableStreamDefaultReader = readableStream.getReader();  // locked.
(async function() {
  while(true) {
    // read data from the queue of this stream.
    const { done, value } = await readableStreamDefaultReader.read();
    if (done) {
      break;
    } else {
      console.log(value);
    }
  }
})();
const writableStream = new WritableStream({
  write(value) {
    console.log(value);
  }
});
const writableStreamDefaultWriter = writableStream.getWriter();
(async function() {
  for await (let chunk of ints()) {
    await writableStreamDefaultWriter.ready;
    writableStreamDefaultWriter.write(chunk);    
  }
  writableStreamDefaultWriter.close();
})();
// return two kinds of stream.
const { writable, readable } = new TransformStream({
  transform(chunk, controller) {
    controller.enqueue(chunk * 2);
  }
});
  1. (Page:1535)计时 API
  1. (Page:1545)Web Component:(略);
  2. (Page:1578)Web Cryptography API:(略);

第 21 章 - 错误处理与调试

  1. (Page:1610)错误处理:
class CustomError extends Error {
  constructor(message) {
    super(message);
    this.name = 'CustomError';
    this.message = message;
  }
}
throw new CustomError('My error message.');
window.onerror = (message, url, line) => {
  console.log(message);
  return false;
};
const logError = (sev, msg) => {
  let img = new Image();
  let encodedSev = encodeURIComponent(sev);
  let encodedMsg = encodeURIComponent(msg);
  img.src = `log.php?sev=${encodedSev}&msg=${encodedMsg}`;
}
  1. (Page:1637)代码调试:

第 22 章 - 处理 XML

(略)

第 23 章 - JSON

  1. (Page:1672)JSONJavaScript Object Notation

第 24 章 - 网络请求与远程资源

  1. (Page:1692)XMLHttpRequest:(略);
  2. (Page:1710)CORS:(略);
  3. (Page:1718)Fetch API
fetch('/json', {
  method: 'POST',
  body: JSON.stringify({ foo: 'bar', }),
  headers: new Headers({
    'Content-Type': 'application/json',
  }),
});
  1. (Page:1771)Beacon API:
window.addEventListener('unload', () => {
  navigator.sendBeacon("/log", JSON.stringify({
    date: new Date().getTime(),
  }));
}, false);
  1. (Page:1774)Web Socket:(略);

第 25 章 - 客户端存储

  1. (Page:1798)JavaScript Document.cookie API 无法访问带有 HttpOnly 属性的 Cookie;此类 Cookie 仅作用于服务器。例如,持久化服务器端会话的 Cookie 不需要对 JavaScript 可用,而应具有 HttpOnly 属性。此预防措施有助于缓解跨站点脚本(XSS)攻击;

第 26 章 - 模块

  1. (Page:1830)模块系统
let Foo = (function() {
  return {
    bar: 'baz',
    baz: function() {
      console.log(this.bar);
    }
  };
})();
console.log(Foo.bar);
Foo.baz();
<!-- 通过标签引入/构建模块 -->
<script type="module">
  // module implementation.
</script>
<script type="module" src="module.js"></script>

第 27 章 - 工作者线程

  1. (Page:1873)三种 Worker 类型:
  1. (Page:1902)三种在上下文间转移信息的方式

第 28 章 - 最佳实践

  1. (Page:2013)性能:
const process = (val) => {
  // do some work here.
};
let iterations = Math.floor(values.length / 8);
let leftover = values.length % 8;
let i = 0;
if (leftover > 0) {
  do {
    process(values[i++]);
  } while(--leftover > 0);
}
do {
  process(values[i++]);
  process(values[i++]);
  process(values[i++]);
  process(values[i++]);
  process(values[i++]);
  process(values[i++]);
  process(values[i++]);
  process(values[i++]);
} while (--iterations > 0);

附录 A - ES2018 和 ES2019

  1. (Page:2049)同步/异步迭代器:
class Emitter {
  constructor(max) {
    this.max = max;
    this.syncIdx = 0;
    this.asyncIdx = 0;
  }
  *[Symbol.iterator]() {
    while(this.syncIdx < this.max) {
      yield this.syncIdx++;
    }
  }
  async *[Symbol.asyncIterator]() {
    while(this.asyncIdx < this.max) {
      yield new Promise((resolve) => resolve(this.syncIdx++));
    }
  }
}
const emitter = new Emitter(5);
for (const x of emitter) {
  console.log(x);
}
for await (const x of emitter) {
  console.log(x);
}

ECMAScript 不一致性记录(部分出于“兼容性”原因)

  1. typeof null 结果为 object;
  2. typeof NaN 结果为 number(虽然为了保持 IEEE-754 定义上的一致性,但作为动态语言,可以在 Runtime 实现层进行语义优化);
  3. parseInt("0o10") 八进制无法得到正确的结果,与十六进制形式 parseInt("0x10") 不统一;
  4. String.prototype.substrString.prototype.substring 从函数名上无法区分差异性;
  5. Arraynew Array 的结果一致,但对于其他结构化类型,则必须使用 new 关键字进行初始化,否则会抛出 TypeError;
  6. ES5(empty)和 ES6(undefined)方法对待数组空位的不同。


这是文章底线,下面是评论
  暂无评论,欢迎勾搭 :)