逻辑运算符小记
&&
与运算 && 做了如下的事:
- 从左到右依次计算操作数。
- 在处理每一个操作数时,都将其转化为布尔值。如果结果是
false,就停止计算,并返回这个操作数的初始值。 - 如果所有的操作数都被计算过(例如都是真值),则返回最后一个操作数。
换句话说,与运算返回第一个假值,如果没有假值就返回最后一个值。
||
或运算|| 做了如下的事情:
- 从左到右依次计算操作数。
- 处理每一个操作数时,都将其转化为布尔值。如果结果是
true,就停止计算,返回这个操作数的初始值。 - 如果所有的操作数都被计算过(也就是,转换结果都是
false),则返回最后一个操作数。
返回的值是操作数的初始形式,不会做布尔转换。
换句话说,一个或运算 || 的链,将返回第一个真值,如果不存在真值,就返回该链的最后一个值。
??
a ?? b 的结果是:
- 如果
a是已定义的,则结果为a, - 如果
a不是已定义的,则结果为b。
+号可以隐式转换将字符变成数字
查找字符串小记
| 方法 | 选择方式…… | 负值参数 |
|---|---|---|
slice(start, end) |
从 start 到 end(不含 end) |
允许 |
substring(start, end) |
从 start 到 end(不含 end) |
负值被视为 0 |
substr(start, length) |
从 start 开始获取长为 length 的字符串 |
允许 start 为负数 |
Map和Set
Map —— 是一个带键的数据项的集合。
方法和属性如下:
new Map([iterable])—— 创建 map,可选择带有[key,value]对的iterable(例如数组)来进行初始化。map.set(key, value)—— 根据键存储值,返回 map 自身。map.get(key)—— 根据键来返回值,如果map中不存在对应的key,则返回undefined。map.has(key)—— 如果key存在则返回true,否则返回false。map.delete(key)—— 删除指定键对应的值,如果在调用时key存在,则返回true,否则返回false。map.clear()—— 清空 map 。map.size—— 返回当前元素个数。
与普通对象 Object 的不同点:
- 任何键、对象都可以作为键。
- 有其他的便捷方法,如
size属性。
Set —— 是一组唯一值的集合。
方法和属性:
new Set([iterable])—— 创建 set,可选择带有iterable(例如数组)来进行初始化。set.add(value)—— 添加一个值(如果value存在则不做任何修改),返回 set 本身。set.delete(value)—— 删除值,如果value在这个方法调用的时候存在则返回true,否则返回false。set.has(value)—— 如果value在 set 中,返回true,否则返回false。set.clear()—— 清空 set。set.size—— 元素的个数。
在 Map 和 Set 中迭代总是按照值插入的顺序进行的,所以我们不能说这些集合是无序的,但是我们不能对元素进行重新排序,也不能直接按其编号来获取元素。
Rest和spread
Array.from适用于类数组对象也适用于可迭代对象。Spread 语法只适用于可迭代对象。
当我们在代码中看到
"..."时,它要么是 rest 参数,要么是 spread 语法。有一个简单的方法可以区分它们:
- 若
...出现在函数参数列表的最后,那么它就是 rest 参数,它会把参数列表中剩余的参数收集到一个数组中。 - 若
...出现在函数调用或类似的表达式中,那它就是 spread 语法,它会把一个数组展开为列表。
使用场景:
- Rest 参数用于创建可接受任意数量参数的函数。
- Spread 语法用于将数组传递给通常需要含有许多参数的函数。
我们可以使用这两种语法轻松地互相转换列表与参数数组。
- 若
闭包
函数嵌套函数
Promise和async/await
!Promise
用于处理异步操作,避免回调地狱。
Promise 类有 6 种静态方法:
Promise.all(promises)—— 等待所有 promise 都 resolve 时,返回存放它们结果的数组。如果给定的任意一个 promise 为 reject,那么它就会变成Promise.all的 error,所有其他 promise 的结果都会被忽略。Promise.allSettled(promises)(ES2020 新增方法)—— 等待所有 promise 都 settle 时,并以包含以下内容的对象数组的形式返回它们的结果:
status:"fulfilled"或"rejected"value(如果 fulfilled)或reason(如果 rejected)。
Promise.race(promises)—— 等待第一个 settle 的 promise,并将其 result/error 作为结果返回。Promise.any(promises)(ES2021 新增方法)—— 等待第一个 fulfilled 的 promise,并将其结果作为结果返回。如果所有 promise 都 rejected,Promise.any则会抛出AggregateError错误类型的 error 实例。Promise.resolve(value)—— 使用给定 value 创建一个 resolved 的 promise。Promise.reject(error)—— 使用给定 error 创建一个 rejected 的 promise。
async
放置在一个函数前面,总是返回一个 promise。其他值将自动被包装在一个 resolved 的 promise 中。
await
只在async中工作,关键字 await 让 JavaScript 引擎等待直到 promise 完成(settle)并返回结果。
async/await总结
函数前面的关键字 async 有两个作用:
- 让这个函数总是返回一个 promise。
- 允许在该函数内使用
await。
Promise 前的关键字 await 使 JavaScript 引擎等待该 promise settle,然后:
- 如果有 error,就会抛出异常 —— 就像那里调用了
throw error一样。 - 否则,就返回结果。
这两个关键字一起提供了一个很好的用来编写异步代码的框架,这种代码易于阅读也易于编写。
有了 async/await 之后,我们就几乎不需要使用 promise.then/catch,但是不要忘了它们是基于 promise 的,因为有些时候(例如在最外层作用域)我们不得不使用这些方法。并且,当我们需要同时等待需要任务时,Promise.all 是很好用的。
打包
import 命名的导出时需要花括号,而 import 默认的导出时不需要花括号。
Document
文档对象模型(Document Object Model),简称 DOM,将所有页面内容表示为可以修改的对象。
document 对象是页面的主要“入口点”。我们可以使用它来更改或创建页面上的任何内容。
浏览器对象模型(Browser Object Model),简称 BOM,表示由浏览器(主机环境)提供的用于处理文档(document)之外的所有内容的其他对象。
DOM
有 6 种主要的方法,可以在 DOM 中搜索元素节点:
| 方法名 | 搜索方式 | 可以在元素上调用? | 实时的? |
|---|---|---|---|
querySelector |
CSS-selector | ✔ | - |
querySelectorAll |
CSS-selector | ✔ | - |
getElementById |
id |
- | - |
getElementsByName |
name |
- | ✔ |
getElementsByTagName |
tag or '*' |
✔ | ✔ |
getElementsByClassName |
class | ✔ | ✔ |
目前为止,最常用的是 querySelector 和 querySelectorAll,但是 getElement(s)By* 可能会偶尔有用,或者可以在旧脚本中找到。
此外:
elem.matches(css)用于检查elem与给定的 CSS 选择器是否匹配。elem.closest(css)用于查找与给定 CSS 选择器相匹配的最近的祖先。elem本身也会被检查。
让我们在这里提一下另一种用来检查子级与父级之间关系的方法,因为它有时很有用:
- 如果
elemB在elemA内(elemA的后代)或者elemA==elemB,elemA.contains(elemB)将返回 true。
修改文档
创建新节点的方法:
document.createElement(tag)—— 用给定的标签创建一个元素节点,document.createTextNode(value)—— 创建一个文本节点(很少使用),elem.cloneNode(deep)—— 克隆元素,如果deep==true则与其后代一起克隆。
插入和移除节点的方法:
node.append(...nodes or strings)—— 在node末尾插入,node.prepend(...nodes or strings)—— 在node开头插入,node.before(...nodes or strings)—— 在node之前插入,node.after(...nodes or strings)—— 在node之后插入,node.replaceWith(...nodes or strings)—— 替换node。node.remove()—— 移除node。
文本字符串被“作为文本”插入。
在
html中给定一些 HTML,elem.insertAdjacentHTML(where, html)会根据where的值来插入它:"beforebegin"—— 将html插入到elem前面,"afterbegin"—— 将html插入到elem的开头,"beforeend"—— 将html插入到elem的末尾,"afterend"—— 将html插入到elem后面。
事件处理
有 3 种分配事件处理程序的方式:
- HTML 特性(attribute):
onclick="..."。 - DOM 属性(property):
elem.onclick = function。 - 方法(method):
elem.addEventListener(event, handler[, phase])用于添加,removeEventListener用于移除。
HTML 特性很少使用,因为 HTML 标签中的 JavaScript 看起来有些奇怪且陌生。而且也不能在里面写太多代码。
DOM 属性用起来还可以,但我们无法为特定事件分配多个处理程序。在许多场景中,这种限制并不严重。
最后一种方式是最灵活的,但也是写起来最长的。有少数事件只能使用这种方式。例如 transtionend 和 DOMContentLoaded(上文中讲到了)。addEventListener 也支持对象作为事件处理程序。在这种情况下,如果发生事件,则会调用 handleEvent 方法。
无论你如何分类处理程序 —— 它都会将获得一个事件对象作为第一个参数。该对象包含有关所发生事件的详细信息。
坐标
相对于窗口的坐标:
clientX和clientY。相对于文档的坐标:
pageX和pageY。简而言之,相对于文档的坐标
pageX/Y以文档的左上角为参照物,并且同一位置的坐标不随页面的滚动而改变。相对于窗口的坐标clientX/Y以当前窗口的左上角为参照物,并且同一位置的坐标会随着页面的滚动而改变。
加载资源
async 和 defer 有一个共同点:加载这样的脚本都不会阻塞页面的渲染。因此,用户可以立即阅读并了解页面内容。
但是,它们之间也存在一些本质的区别:
| 顺序 | DOMContentLoaded |
|
|---|---|---|
async |
加载优先顺序。脚本在文档中的顺序不重要 —— 先加载完成的先执行 | 不相关。可能在文档加载完成前加载并执行完毕。如果脚本很小或者来自于缓存,同时文档足够长,就会发生这种情况。 |
defer |
文档顺序(它们在文档中的顺序) | 在文档加载和解析完成之后(如果需要,则会等待),即在 DOMContentLoaded 之前执行。 |
在实际开发中,defer 用于需要整个 DOM 的脚本,和/或脚本的相对执行顺序很重要的时候。
async 用于独立脚本,例如计数器或广告,这些脚本的相对执行顺序无关紧要。
二进制数据
基本的二进制对象是 ArrayBuffer —— 对固定长度的连续内存空间的引用。
如要操作 ArrayBuffer,我们需要使用“视图”对象。
也就是TypedArray
视图对象本身并不存储任何东西。它是一副“眼镜”,透过它来解释存储在 ArrayBuffer 中的字节。
例如:
Uint8Array—— 将ArrayBuffer中的每个字节视为 0 到 255 之间的单个数字(每个字节是 8 位,因此只能容纳那么多)。这称为 “8 位无符号整数”。Uint16Array—— 将每 2 个字节视为一个 0 到 65535 之间的整数。这称为 “16 位无符号整数”。Uint32Array—— 将每 4 个字节视为一个 0 到 4294967295 之间的整数。这称为 “32 位无符号整数”。Float64Array—— 将每 8 个字节视为一个5.0x10-324到1.8x10308之间的浮点数。
因此,一个 16 字节 ArrayBuffer 中的二进制数据可以解释为 16 个“小数字”,或 8 个更大的数字(每个数字 2 个字节),或 4 个更大的数字(每个数字 4 个字节),或 2 个高精度的浮点数(每个数字 8 个字节)。
Fetch
基本语法:
let promise = fetch(url, [options])
url—— 要访问的 URL。options—— 可选参数:method,header 等。
典型的 fetch 请求由两个 await 调用组成:
let response = await fetch(url, options); // 解析 response header
let result = await response.json(); // 将 body 读取为 json
或者以 promise 形式:
fetch(url, options)
.then(response => response.json())
.then(result => /* process result */)
响应的属性:
response.status—— response 的 HTTP 状态码,response.ok—— HTTP 状态码为 200-299,则为true。response.headers—— 类似于 Map 的带有 HTTP header 的对象。
获取 response body 的方法:
response.text()—— 读取 response,并以文本形式返回 response,response.json()—— 将 response 解析为 JSON 对象形式,response.formData()—— 以FormData对象(multipart/form-data编码,参见下一章)的形式返回 response,response.blob()—— 以 Blob(具有类型的二进制数据)形式返回 response,response.arrayBuffer()—— 以 ArrayBuffer(低级别的二进制数据)形式返回 response。
xhr
可以用于跟踪上传文件的进度
WebSocket
WebSocket 是一种在浏览器和服务器之间建立持久连接的现代方式。
- WebSocket 没有跨源限制。
- 浏览器对 WebSocket 支持很好。
- 可以发送/接收字符串和二进制数据。
WebSocket 的 API 很简单。
WebSocket 方法:
socket.send(data),socket.close([code], [reason])。
WebSocket 事件:
open,message,error,close。
WebSocket 自身并不包含重新连接(reconnection),身份验证(authentication)和很多其他高级机制。因此,有针对于此的客户端/服务端的库,并且也可以手动实现这些功能。
Cookie
Cookie 是直接存储在浏览器中的一小串数据。
document.cookie 提供了对 cookie 的访问
- 写入操作只会修改其中提到的 cookie。
- name/value 必须被编码。
- 一个 cookie 最大不能超过 4KB。每个域下最多允许有 20+ 个左右的 cookie(具体取决于浏览器)。
Cookie 选项:
path=/,默认为当前路径,使 cookie 仅在该路径下可见。domain=site.com,默认 cookie 仅在当前域下可见。如果显式地设置了域,可以使 cookie 在子域下也可见。expires或max-age设定了 cookie 过期时间。如果没有设置,则当浏览器关闭时 cookie 就会失效。secure使 cookie 仅在 HTTPS 下有效。samesite,如果请求来自外部网站,禁止浏览器发送 cookie。这有助于防止 XSRF 攻击。
localStorage 和 sessionStorage
Web 存储对象 localStorage 和 sessionStorage 允许我们在浏览器中保存键/值对。
key和value都必须为字符串。- 存储大小限制为 5MB+,具体取决于浏览器。
- 它们不会过期。
- 数据绑定到源(域/端口/协议)。
localStorage |
sessionStorage |
|---|---|
| 在同源的所有标签页和窗口之间共享数据 | 在当前浏览器标签页中可见,包括同源的 iframe |
| 浏览器重启后数据仍然保留 | 页面刷新后数据仍然保留(但标签页关闭后数据则不再保留) |
