30 个有用的 JavaScript 代码片段
在过去的几个月里,我在开发离线浏览器工具时,我自己反复搜索我的JavaScript 文件以检索旧的代码片段。
因此,我认为使用以下常用 JavaScript 方法的编译列表作为参考可能会让那些与我有类似用例的其他人受益。
我总共整理了30个我认为比较有用的 JavaScript 代码段。
文章目录
- 1.文件内容上传
- 2. 保存文件内容
- 3.复制到剪贴板
- 4.查找并替换全部
- 5. 生成随机十六进制颜色
- 6. 突出显示 JSON 语法
- 7. 通知未保存的更改
- 8. 异步上传多个文件
- 9. insertAdjacentHTML — 开始之前 | 开始之后 | 前言 | 尾声
- 10. 检查 JSON 字符串是否有效
- 11. 将原始 HTML 字符串编码为 Unicode 实体
- 12. 将 XML 转换为 JSON
- 13. 创建一个 <img> DOM 元素
- 14. 删除所有嵌套子节点
- 15. 选择文本并将其复制到剪贴板 — 表单输入和其他 HTML DOM 元素
- 16. 将 JSON 对象数组转换为 CSV 文本
- 17.DOMContentLoaded 事件监听器
- 18. 将多个事件绑定到 HTML 元素
- 19.清除浏览器缓存
- 20. 以编程方式触发 HTML 事件
- 21. 将 async-await 与 for 循环结合使用
- 22. 将字符串转换为帕斯卡大小写(带空格)
- 23. 将 Uint8Array 转换为 Base64 字符串
- 24.将Base64字符串转换为Uint8Array
- 25.获取浏览器垂直滚动条宽度
- 26. 将年、月和日添加到 Date() 对象
- 27.从数组中删除无效值,例如null和undefined
- 28. 数组中的唯一值
- 29. 通过解析字符串创建新的 HTML DOM 元素
- 30. 打印网页
1.文件内容上传
var selectContent = document.getElementById("selectContent");
var contentForSelection = document.getElementById("contentForSelection");
selectContent.onchange = function(e) {
if (!window.FileReader) {
alert("Your browser does not support HTML5 'FileReader' function required to open a file.");
} else {
let fileis = this.files[0];
let fileredr = new FileReader();
fileredr.onload = function(fle) {
let filecont = fle.target.result;
contentForSelection.value = filecont;
};
//fileredr.readAsArrayBuffer(fileis);
fileredr.readAsText(fileis);
}
};

在上面的示例中,由于我选择导入的文件是文本格式,因此使用方法 readAsText 而不是 readAsArrayBuffer。使用 readAsArrayBuffer 的实例包括读取图像流或读取 ZIP 存档文件。成功导入后,文件内容将自动呈现到元素 id 为“contentForSelection”的文本区域中。
2. 保存文件内容
var saveBtn = document.getElementById("saveBtn");
var contentForSelection = document.getElementById("contentForSelection");
saveBtn.onclick = function() {
let txtContent = contentForSelection.value;
if (!window.Blob) {
alert("Your browser does not support HTML5 'Blob' function required to save a file.");
} else {
let textblob = new Blob([txtContent], {
type: "text/plain"
});
let dwnlnk = document.createElement("a");
dwnlnk.download = "output.txt";
dwnlnk.innerHTML = "Download File";
if (window.webkitURL != null) {
dwnlnk.href = window.webkitURL.createObjectURL(textblob);
}
dwnlnk.click();
}
};

上述代码片段通常在在线笔记应用程序中实现,以便用户导出其输出。或者,在数据/代码格式化程序等网络实用程序中,通常也会提供[保存]功能,以允许用户将后续格式化的文本内容保存到本地存储文件中。
3.复制到剪贴板
复制到剪贴板是基于浏览器的设置中的另一个经典功能。通常,如果转换后的输出仅用于 1-Off 任务,则无需将输出保存到文件,而使用以下 JS 代码片段会更合适:
var copyBtn = document.getElementById("copyBtn");
var contentForSelection = document.getElementById("contentForSelection");
copyBtn.onclick = function(evt) {
copyBtn.nextElementSibling.innerHTML = "";
copyTransformedOutput("contentForSelection");
let smallEle = evt.currentTarget.nextElementSibling;
smallEle.innerHTML = "<span style='color:green'> Copied to Clipboard!</span>";
};
function copyTransformedOutput(inputEleId) {
let copyText = document.getElementById(inputEleId);
copyText.select();
copyText.setSelectionRange(0, 99999); /* For mobile devices */
navigator.clipboard.writeText(copyText.value);
}
请注意,我选择在成功复制代码片段后显示一条消息“已复制到剪贴板”。
因此,转换后的输出随后可以粘贴到其他地方,而无需存储到本地文件中以供使用。
4.查找并替换全部
虽然在最新的 JavaScript 控制台中,此功能当前是内置的,但由于其实现的独创性和简单性,了解以下 JavaScript 函数仍然是相关且有用的:
function replaceAll(inputStr, toReplace, replaceWith) {
return inputStr.split(toReplace).join(replaceWith);
}
例如,如果我想在文本区域中将“id”替换为“ID”:

代码片段的其余部分如下:
var replaceBtn = document.getElementById("replaceBtn");
replaceBtn.onclick = function() {
let toFind = document.getElementById("ToFind").value;
let replaceWith = document.getElementById("ReplaceWith").value;
contentForSelection.value = replaceAll(contentForSelection.value, toFind, replaceWith);
};
5. 生成随机十六进制颜色
我发现这种 JavaScript 方法没有得到充分重视的一种情况是,当我必须将多条驾驶路线渲染到同一个 Web 应用程序上时:

显然微分了一个无限数。具有不同颜色的重叠驾驶路线对于任何观看者来说都更容易比较和对比地图可视化上显示的各种路线。因此,动态生成不同的颜色是必要的,可以通过以下方式实现:
function generateRandomHexColor() {
let colorGenerated = "#" + (Math.random() * 0xfffff * 1000000).toString(16).slice(0, 6);
if (colorGenerated !== "#0000ff" && colorGenerated !== "#ff0000") {
return colorGenerated;
}
colorGenerated = "#" + (Math.random() * 0xfffff * 1000000).toString(16).slice(0, 6);
}
6. 突出显示 JSON 语法
对于地图服务提供商返回的每条路线,我都合并了路线 JSON 数据输出的导出功能。因此,为了区分 JSON 对象中的 String、Float、Integer、Boolean 等对象类型,我选择对其进行颜色编码,如下所示:

上述效果可以通过CSS和JavaScript来实现。
JavaScript 代码:
function syntaxHighlight(json) {
json = json.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function(match) {
var cls = "number";
if (/^"/.test(match)) {
if (/:$/.test(match)) {
cls = "key";
} else {
cls = "string";
}
} else if (/true|false/.test(match)) {
cls = "boolean";
} else if (/null/.test(match)) {
cls = "null";
}
return "<span class='" + cls + "'>" + match + "</span>";
});
}
CSS代码:
.string {
color: green;
}
.number {
color: darkorange;
}
.boolean {
color: blue;
}
.null {
color: magenta;
}
.key {
color: red;
}
7. 通知未保存的更改
window.addEventListener('beforeunload', (event) => {
event.preventDefault();
event.returnValue = '';
});

上面的代码片段对于用户在输入字段中输入了未保存的数据并且在页面卸载时会丢失的情况特别有用。在上图中,用户上传多个图像文件后,浏览器会提示用户是否已保存图像输出以防止数据丢失。
8. 异步上传多个文件
function readFileAsB64(file) {
return new Promise((resolve, reject) => {
let fileredr = new FileReader();
fileredr.onload = () => resolve([fileredr.result, file.name]);
fileredr.onerror = (err) => reject(err);
fileredr.readAsDataURL(file);
});
}
var uploadFile = document.getElementById('uploadFile'); // input[type='file']
uploadFile.addEventListener('change', (ev) => {
if (!window.FileReader) {
alert('Your browser does not support HTML5 "FileReader" function required to open a file.');
} else {
let filesArr = ev.target.files;
let fileReaders = [];
for (let f in filesArr) {
if (!isNaN(f)) fileReaders.push(readFileAsB64(filesArr[f]))
}
Promise.all(fileReaders).then((outputArrs) => {
for (let o in outputArrs) {
if (!isNaN(o)) {
let fileArr = outputArrs[o]; // [fileredr.result, file.name]
/* TO DO LOGIC HERE */
let image = new Image();
image.src = fileArr[0];
image.title = fileArr[1];
image.height = 100;
document.body.appendChild(image);
}
}
});
}
});
上面的代码片段确保在浏览器继续执行注释后的代码逻辑之前,所有上传的图像文件都已编码为 Base64 字符串(fileredr.readAsDataURL(file);):

9. insertAdjacentHTML — 开始之前 | 开始之后 | 前言 | 尾声
回顾第 1) 点中的屏幕截图,可以通过 insertAdjacentHTML(<position>,<HTML String>) 将 HTML 附加到元素:
<Element>.insertAdjacentHTML('beforeend'|'afterbegin'|'beforeend'|'afterend', <HTML String>);
下面是每个选项相对于 <Element>(即 <p></p>)所指的位置的说明:
<!-- beforebegin -->
<p>
<!-- afterbegin -->
foo
<!-- beforeend -->
</p>
<!-- afterend -->
由于在第 1 点)中,目标是附加额外的表行 (<tr></tr>),因此使用了 beforeend 位置。
10. 检查 JSON 字符串是否有效
由于我在业余时间创建的大多数离线浏览器实用程序都要求用户上传数据文件,其中一些文件需要为 JSON 格式,因此这是一种对 JSON 文件进行数据格式验证检查的简单直接的方法是:
function isValidJSON(str) {
try {
JSON.parse(str);
return true;
} catch (e) {
return false;
}
}
// returns a Boolean
11. 将原始 HTML 字符串编码为 Unicode 实体
function encodeHTMLChars(rawStr) {
return rawStr.replace(/[\u00A0-\u9999<>\&]/g, ((i) => `${i.charCodeAt(0)};`));
}
要将文本 <img> 显示到 HTML 页面上,必须按如下方式对字符串进行编码:
var inputHTMLStr='<img>';
var encodedHTMLStr=encodeHTMLChars(inputHTMLStr);
console.log(encodedHTMLStr);
// Output: <img>
当需要在网页上显示 HTML 代码片段时,这通常会派上用场,因为其原始形式(即“<img>”)会被浏览器自动解释为 HTML DOM 元素,而不是用于显示的原始文本。
12. 将 XML 转换为 JSON
2 个最未被充分利用的 JavaScript API 包括:DOMParser() 和 DOMParser.parseFromString()
尽管 xml-js 和 xml2js 等 npm 包很容易获得,但该逻辑可以通过纯 JavaScript 实现,如下所示:
function convertXMLtoJSON(xmlObj) { // adapted from https://davidwalsh.name/convert-xml-json
var obj = {};
if (xmlObj.nodeType == 1) {
if (xmlObj.attributes.length > 0) {
obj['@attributes'] = {};
for (var j = 0; j < xmlObj.attributes.length; j++) {
var attribute = xmlObj.attributes.item(j);
obj['@attributes'][attribute.nodeName] = attribute.nodeValue;
}
}
} else if (xmlObj.nodeType == 3) {
obj = xmlObj.nodeValue;
}
// Iterate through all child nodes
// Use recursive to assign nested nodes
if (xmlObj.hasChildNodes()) {
for (var i = 0; i < xmlObj.childNodes.length; i++) {
var item = xmlObj.childNodes.item(i);
var nodeName = item.nodeName;
if (typeof(obj[nodeName]) === 'undefined') {
obj[nodeName] = convertXMLtoJSON(item);
} else {
if (typeof(obj[nodeName].push) === 'undefined') {
var old = obj[nodeName];
obj[nodeName] = [];
obj[nodeName].push(old);
}
obj[nodeName].push(convertXMLtoJSON(item));
}
}
}
return obj;
}
/* USAGE: Sample xmlText */
var xmlText = '<bookstore><book>' +
'<title>Everyday Italian</title>' +
'<author>Giada De Laurentiis</author>' +
'<year>2005</year>' +
'</book></bookstore>';
var xmlParser = new DOMParser();
var xmlObj = xmlParser.parseFromString(xmlText, 'text/xml');
var jsonObj = convertXMLtoJSON(xmlObj);
console.log(jsonObj);
// Output: {"bookstore":{"book":{"title":{"#text":"Everyday Italian"},"author":{"#text":"Giada De Laurentiis"},"year":{"#text":"2005"}}}}
13. 创建一个 <img> DOM 元素
// Code snippet to render <img> DOM element on the fly
const loadImage = (url) => new Promise((resolve, reject) => {
const img = new Image();
img.addEventListener('load', () => resolve(img));
img.addEventListener('error', (err) => reject(err));
img.src = url;
});
// __USAGE Example__
var uploadFileInput = document.createElement('input');
uploadFileInput.type = 'file';
uploadFileInput.id = 'uploadFileInput';
document.body.appendChild(uploadFileInput);
function readFileAsDataURL(file) {
return new Promise((resolve, reject) => {
let fileredr = new FileReader();
fileredr.onload = () => resolve(fileredr.result);
fileredr.onerror = () => reject(fileredr);
fileredr.readAsDataURL(file);
});
}
uploadFileInput.addEventListener('change', async (evt) => {
var file = evt.currentTarget.files[0];
if (!file) return;
var b64str = await readFileAsDataURL(file);
var _img = await loadImage(b64str);
_img['style']['width'] = `${_img.naturalWidth}px`;
_img['style']['height'] = `${_img.naturalHeight}px`;
_img['style']['margin'] = '2px auto';
_img['style']['display'] = 'block';
document.body.appendChild(_img);
}, false);
注意:虽然大多数 HTML 元素节点的属性(例如 <div> <p>)是可访问的并且不需要“load”事件的侦听器,但 <img> 是此规则的一个例外(另一个唯一的例外是 < 脚本>)
因此,如果 document.createElement(‘img’) 没有返回 Promise:
var loadedImg=document.createElement('img');
loadedImg.src=<dataURL>; // dataURL refers to the encoded image data
变量loadedImg不会被渲染,因为在分配属性src时它仍然是未定义的。
14. 删除所有嵌套子节点
const removeAllChildNodes = ((parentEle) => parentEle.children.length > 0 ? parentEle.removeChild(parentEle.children[0]) : null);
// __USAGE Example__
const _scale = window.devicePixelRatio * 2;
const size = 250;
const fontSize = size / _scale;
var canvasDisplay = document.createElement('div');
canvasDisplay['style']['width'] = `${size+4}px`;
canvasDisplay['style']['height'] = `${size+4}px`;
canvasDisplay['style']['margin'] = '1px auto';
document.body.appendChild(canvasDisplay);
var iconBtn_1 = document.createElement('button');
iconBtn_1.type = 'button';
iconBtn_1.value = '🔍';
iconBtn_1.innerText = '🔍';
document.body.appendChild(iconBtn_1);
var iconBtn_2 = document.createElement('button');
iconBtn_2.type = 'button';
iconBtn_2.value = '💡';
iconBtn_2.innerText = '💡';
document.body.appendChild(iconBtn_2);
function setIcon(icon) {
var canvas = document.createElement('canvas');
canvas.width = size;
canvas.height = size;
canvas['style']['margin'] = '1px auto';
canvas['style']['width'] = `${fontSize}px`;
canvas['style']['height'] = `${fontSize}px`;
canvas['style']['border'] = '1px dotted #6c757d';
canvas['style']['background'] = 'transparent';
var ctx = canvas.getContext('2d');
ctx.scale(_scale, _scale);
ctx.font = `${fontSize}px Segoe Ui Emoji`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.globalAlpha = 1.0;
ctx.fontVariantCaps = 'unicase';
ctx.filter = 'none';
ctx.globalCompositeOperation = 'source-over';
ctx.imageSmoothingEnabled = true;
ctx.imageSmoothingQuality = 'high';
ctx.letterSpacing = '0px';
ctx.lineWidth = 0;
ctx.shadowColor = 'rgba(0, 0, 0, 0)';
ctx.strokeStyle = '#000000';
ctx.fillStyle = '#ffffff';
const _x = ((canvas.width / _scale) / 2);
const _y = ((canvas.height / _scale) / 2);
ctx.fillText(icon, _x, _y);
removeAllChildNodes(canvasDisplay);
canvasDisplay.appendChild(canvas);
}
iconBtn_1.addEventListener('click', () => {
setIcon(iconBtn_1.value);
});
iconBtn_2.addEventListener('click', () => {
setIcon(iconBtn_2.value);
});
使用示例:

注意:函数removeAllChildNodes()使用递归来删除所有嵌套元素。这对于防止先前不需要的子节点与后续附加的子节点累积是必要的,如下所示:

15. 选择文本并将其复制到剪贴板 — 表单输入和其他 HTML DOM 元素
function selectCopyText(nodeId) {
let isVal = true;
let node = document.getElementById(nodeId);
try {
node.select();
try {
node.setSelectionRange(0, 99999);
} catch (err0) {}
} catch (err) {
isVal = false;
if (document.body.createTextRange) {
const range = document.body.createTextRange();
range.moveToElementText(node);
range.select();
} else if (window.getSelection) {
const selection = window.getSelection();
const range = document.createRange();
range.selectNodeContents(node);
selection.removeAllRanges();
selection.addRange(range);
} else {
console.warn("Could not select text in node: Unsupported browser.");
}
} finally {
navigator.clipboard.writeText(isVal ? node.value : node.innerText);
}
}
const strToCopy = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Viverra accumsan in nisl nisi scelerisque eu ultrices. Posuere lorem ipsum dolor sit amet consectetur adipiscing. Sodales ut etiam sit amet nisl purus.';
var _copyBtn = document.createElement('button');
_copyBtn.type = 'button';
_copyBtn.value = 'toCopy';
_copyBtn.innerText = 'Copy Textarea';
var _textarea = document.createElement('textarea');
_textarea.id = 'toCopy';
_textarea['style']['resize'] = 'none';
_textarea['style']['width'] = '100%';
_textarea['style']['height'] = '100px';
_textarea['style']['display'] = 'block';
_textarea.value = strToCopy;
document.body.appendChild(_copyBtn);
document.body.appendChild(_textarea);
var _copyBtn2 = document.createElement('button');
_copyBtn2.type = 'button';
_copyBtn2.value = 'toCopy2';
_copyBtn2.innerText = 'Copy DIV';
var _div = document.createElement('_div');
_div.id = 'toCopy2';
_div['style']['width'] = '100%';
_div['style']['height'] = '100px';
_div['style']['display'] = 'block';
_div['style']['border'] = '1px dashed #000000';
_div.innerText = strToCopy;
document.body.appendChild(_copyBtn2);
document.body.appendChild(_div);
_copyBtn.addEventListener('click', () => {
selectCopyText(_copyBtn.value);
});
_copyBtn2.addEventListener('click', () => {
selectCopyText(_copyBtn2.value);
});
使用示例:

虽然“复制到剪贴板”是最普遍需要的 JavaScript 功能之一,但还值得注意的是,所需的文本内容同样可能包含在表单元素中,例如 – <input type=’text’> <textarea > 或嵌入 HTML DOM 元素中,例如 <div> <p>。
因此,此函数解决了通过检查 HTMLInputElement 或 HTMLDivElement 中是否存在文本内容来确定如何在 JavaScript 中实现文本选择的问题。
然后分别选择属性.value 和.innerText。
16. 将 JSON 对象数组转换为 CSV 文本
function rowJSONToCSV(rowJSONObj) {
let csvOutputStr = '';
let allHeaders = {};
for (let obj of rowJSONObj) {
for (let k in obj) {
allHeaders[k] = '';
}
}
let allHeadersArr = Object.keys(allHeaders);
let headerStr = JSON.stringify(allHeadersArr);
headerStr = headerStr.substring(1, headerStr.length - 1);
csvOutputStr += headerStr + '\n';
for (let obj of rowJSONObj) {
let allValuesArr = [];
for (let headerField of allHeadersArr) {
let rowVal = obj[headerField];
(typeof rowVal !== 'undefined') ? allValuesArr.push(rowVal): allValuesArr.push('NULL')
}
let rowStr = JSON.stringify(allValuesArr);
rowStr = rowStr.substring(1, rowStr.length - 1);
csvOutputStr += rowStr + '\n';
}
return Promise.resolve(csvOutputStr);
}
var uploadFileInput = document.createElement('input');
uploadFileInput.type = 'file';
uploadFileInput.id = 'uploadFileInput';
document.body.appendChild(uploadFileInput);
function readFileAsText(file) {
return new Promise((resolve, reject) => {
let fileredr = new FileReader();
fileredr.onload = () => resolve(fileredr.result);
fileredr.onerror = () => reject(fileredr);
fileredr.readAsText(file);
});
}
uploadFileInput.addEventListener('change', async (evt) => {
var file = evt.currentTarget.files[0];
if (!file) return;
var jsonStr = await readFileAsText(file);
var inputJSONObj = JSON.parse(jsonStr);
var divOne = document.createElement('div');
divOne['style']['font-family'] = 'Consolas';
divOne['style']['height'] = '250px';
divOne['style']['weight'] = '100%';
divOne['style']['margin'] = '2px auto';
divOne['style']['overflow'] = 'auto';
divOne['style']['border'] = '1px dashed #17a2b8';
var csvStrOutput = await rowJSONToCSV(inputJSONObj);
divOne.innerText = csvStrOutput;
document.body.appendChild(divOne);
}, false);
使用示例

演示示例数据文件的链接:icd10_data.json
输出 CSV 文件的链接:icd10_data.csv
基本原理
按照惯例,我倾向于使用插件 json2csv.js(最初来自 https://www.npmjs.com/package/json2csv)来进行 JSON 到 CSV 的转换。
然而,对于超过 50MB 的大文件,递归算法超出了其最大堆栈限制,当我尝试将文件上传到我开发的 Web 实用程序时,我发现了这一点:https://tableau-data-utility。onrender.com/ 在 [Spatial⇢CSV] 选项卡上
由于地理空间数据集往往超过 50MB,实现上述将 JSON 转换为 CSV 的函数解决了递归问题。
局限性
仅适用于深度级别为 1 的嵌套 JSON 对象。如果输入深度级别更高的 JSON 对象,则效果不佳。例如,以下内容将失败,因为第一个条目“喜欢”的深度级别 = 2
[{
"firstName": "John",
"lastName": "Doe",
"likes": {
"pets": ["dogs", "cats"]
}
},
{
"firstName": "Anna",
"lastName": "Smith"
}
]
17.DOMContentLoaded 事件监听器
if (document.readyState === 'complete' || document.readyState !== 'loading' && !document.documentElement.doScroll) {
callback();
} else {
document.addEventListener('DOMContentLoaded', async () => {
/* TO DO LOGIC HERE */
});
}
<!DOCTYPE html>
<html>
<meta charset='UTF-8'>
<head>Demo (5)</head>
<body>
<p>🔄 Refresh webpage to run function "doSomething()".</p>
<script>
if (document.readyState === 'complete' || document.readyState !== 'loading' && !document.documentElement.doScroll) {
callback();
} else {
document.addEventListener('DOMContentLoaded', async () => {
function doSomething() {
alert('Hello!');
}
doSomething();
});
}
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<meta charset='UTF-8'>
<head>
<head>Demo (5)</head>
<script>
function doSomething() {
alert('Hello!');
}
</script>
</head>
<body onload='doSomething()'>
<p>Refresh webpage to run function "doSomething()".</p>
</body>
</html>
使用示例
当网页加载后需要立即执行某个功能时,一种可能的方法是将 onload 事件嵌入到 <body> 标记中:

注意:一个常见的错误是执行 windows.onload 中嵌套的函数:
<!DOCTYPE html>
<html>
<meta charset='UTF-8'>
<head>
<head>Demo (5)</head>
<script>
windows.onload = function() {
function doSomething() {
alert('Hello!');
}
};
</script>
</head>
<body>
<p>Refresh webpage to run function "doSomething()".</p>
</body>
</html>
因此,为了对所有嵌入的 JavaScript 代码片段进行稍微更有条理的分区,请使用以下命令:
document.addEventListener('DOMContentLoaded', function() {
...
});
可以考虑改为:

18. 将多个事件绑定到 HTML 元素
// Binding multiple events to a single element
function addMultipleEvents(eventsArray, targetElem, handler) {
eventsArray.map((event) => targetElem.on(event, handler));
}
// Alt Version: Using 'addEventListener'
function addMultipleEvents(eventsArray, targetElem, handler) {
eventsArray.map((event) => targetElem.addEventListener(event, handler));
}
// Noting the coordinates when map is pan or zoom etc.
// Built with Leaflet.js
var mapUrl = "https://stamen-tiles.a.ssl.fastly.net/toner-hybrid/{z}/{x}/{y}.png";
var map = L.map("map");
var basemap = L.tileLayer(mapUrl, {
detectRetina: true,
maxZoom: 19,
minZoom: 11,
attributionControl: false
}).addTo(map);
function renderImageBounds() {
imgBounds = map.getBounds();
imgBounds_Left.innerHTML = imgBounds._southWest.lng;
imgBounds_Right.innerHTML = imgBounds._northEast.lng;
imgBounds_Bottom.innerHTML = imgBounds._southWest.lat;
imgBounds_Top.innerHTML = imgBounds._northEast.lat;
}
function addMultipleEvents(eventsArray, targetElem, handler) {
eventsArray.map((event) => targetElem.on(event, handler));
}
addMultipleEvents(['zoomend', 'dragend', 'viewreset', 'moveend', 'load', 'resize'], map, renderImageBounds);
使用示例
在我之前构建的网络实用程序中,合并了跟踪所显示地图的地理坐标的功能,如下所示:

19.清除浏览器缓存
清除单个网页浏览器缓存的 JavaScript 如下:
const supportsLocalStorage = () => {
if (!('localStorage' in window)) return false;
try {
localStorage.setItem('check', 'true');
localStorage.getItem('check');
localStorage.removeItem('check');
return true;
} catch (e) {
return false;
}
};
const hasLocalStorage = supportsLocalStorage();
/* Assume there is a <button id='clearCache' type='button'></button> */
/* HTML element in the DOM */
/*const clearCacheBtn = document.getElementById('clearCache');*/
/*clearCacheBtn.addEventListener('click', async()=> {*/
requestAnimationFrame(() => {
if (hasLocalStorage) {
localStorage.clear();
location.reload();
}
});
/*});*/
用例演示
在某些网页上,以前的用户输入会有意保留在浏览器缓存中。 例如,在 JSONEditor.com 上:

但是,当通过 JavaScript 控制台以编程方式清除浏览器缓存时:

20. 以编程方式触发 HTML 事件
// Note: Compatible for both IE8, IE9+ and other modern browsers
function triggerEvent(el, type) {
let e = (('createEvent' in document) ? document.createEvent('HTMLEvents') : document.createEventObject());
if ('createEvent' in document) {
e.initEvent(type, false, true);
el.dispatchEvent(e);
} else {
e.eventType = type;
el.fireEvent('on' + e.eventType, e);
}
}
用例演示
假设以下 HTML 标记文档:
<!DOCTYPE html>
<html>
<head>
<title>Demo trigger() Method</title>
</head>
<body>
<div class='box-1'>
<h1>0</h1>
</div>
<button id="btn1">Increase #1</button>
<div class='box-2'>
<h1>0</h1>
</div>
<button id='btn2'>Increase #2</button>
<script>
/* TO-DO */
</script>
</body>
</html>
上面的triggerEvent()函数可以在上面的2个<script>标签之间实现,如下所示:
function triggerEvent(el, type) {
let e = (('createEvent' in document) ? document.createEvent('HTMLEvents') : document.createEventObject());
if ('createEvent' in document) {
e.initEvent(type, false, true);
el.dispatchEvent(e);
} else {
e.eventType = type;
el.fireEvent('on' + e.eventType, e);
}
}
document.querySelector('#btn1').addEventListener('click', () => {
increase(document.querySelector('.box-1>h1'));
});
document.querySelector('#btn2').addEventListener('click', () => {
triggerEvent(document.querySelector('#btn1'), 'click');
increase(document.querySelector('.box-2>h1'));
});
function increase(obj) {
let text = parseInt(obj.textContent, 10);
obj.textContent = text + 1;
}

虽然, jQuery 插件有包装函数 trigger() ,它输出相同的结果。
<!-- import jQuery plugin -->
<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.6.4/jquery.min.js'></script>
// Sample jQuery code snippet at /* TO-DO */ between the 2 <script> tags:
$('#btn1').click(() => {
increase($('.box-1>h1'));
});
$('#btn2').click(() => {
$('#btn1').trigger('click');
increase($('.box-2>h1'));
});
function increase(obj) {
let text = parseInt(obj.text(), 10);
obj.text(text + 1);
}
在首选更轻量级替代方案的情况下,可以考虑使用 functiontriggerEvent()。
21. 将 async-await 与 for 循环结合使用
下面的代码片段调用 JSON API,其中每次迭代都会解析不同的参数 (i),以按顺序检索 JSON 响应。
(async () => {
// Assume a <table id='datatable'></table> is in the HTML DOM
const datatableTbody = document.querySelector('#datatable tbody');
for (let i = 1; i <= 15; i++) {
const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${i}`);
const result = await response.json();
datatableTbody.insertAdjacentHTML('beforeend', '<tr><td>' + Object.values(result).join('</td><td>') + '</td></tr>');
}
})();
用例演示
通常,当呈现数据记录以进行显示时,每条记录都是通过 API 调用获取的。 通过API返回所需的记录,完整的代码片段如下:
<!DOCTYPE html>
<html>
<head>
<title>async-await in a for-loop</title>
<style>
table {
font-family: arial, sans-serif;
border-collapse: collapse;
width: 100%;
}
td,
th {
border: 1px solid #dddddd;
text-align: left;
padding: 4px;
}
table tbody tr:nth-child(odd) {
background-color: #f1f1f1;
}
</style>
</head>
<body>
<table id='datatable'>
<thead>
<tr>
<th>userId</th>
<th>id</th>
<th>title</th>
<th>completed</th>
</tr>
</thead>
<tbody></tbody>
</table>
<script>
(async () => {
const datatableTbody = document.querySelector('#datatable tbody');
for (let i = 1; i <= 15; i++) {
const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${i}`);
const result = await response.json();
datatableTbody.insertAdjacentHTML('beforeend', '<tr><td>' + Object.values(result).join('</td><td>') + '</td></tr>');
}
})();
</script>
</body>
</html>

22. 将字符串转换为帕斯卡大小写(带空格)
由于 JavaScript 没有内置函数将每个单词的首字母转换为大写,因此可以应用以下代码片段:
const toPascalCase = (str) => ((str.toLowerCase()).replace(/\w+/g, ((str) => (str.charAt(0).toUpperCase() + str.substr(1)).replace(/\r/g, ''))));
// Usage:
// let str = 'HeLLO world';
// console.log(toPascalCase(str));
// Result: 'Hello World'
用例演示
当从 API 返回的字母大小写不一致时,为了视觉一致性,以帕斯卡大小写显示某些标签可能更合适。
例如,在我的一个业余项目中——一个 Bus ETA Web 应用程序,检索所有公交车站描述的 API 的字母大小写不一致:

23. 将 Uint8Array 转换为 Base64 字符串
除了纯文本之外,JavaScript 还读取其他格式的文件输入,例如 ArrayBuffers(尤其是多媒体上传)。 从 ArrayBuffer 检索文件数据作为 Base64 编码字符串 (DataURL) 的函数如下:
// Uint8Array to Base64 Encoded String
const convertBitArrtoB64 = (bitArr) => ( btoa( bitArr.reduce((data, byte) => data + String.fromCharCode(byte), '') ) );
用例演示
对于某些库,所有处理的文件输入仅输出为 Uint8Array。 一个例子是 FFmpeg.wasm(归功于吴杰罗姆),我在一个网络应用程序中实现了它,用于对音频编解码器进行转码。 在这个副项目中的用法如下:
// `data` is output as Uint8Array
// assuming input format is mp3, `outputFileExt`='mp3'
const data = ffmpeg.FS('readFile', `output${outputFileExt}`);
let b64Str = convertBitArrtoB64(data);
// assuming converted output format is mp4, `outputFileMimeType` = 'mp4'
let encodedData = `data:${outputFileMimeType};base64,${b64Str}`;
// To generate download link and save output
let dwnlnk = document.createElement('a');
dwnlnk.download = `${saveFilename}${outputFileExt}`;
dwnlnk.href = encodedData;
dwnlnk.click();
24.将Base64字符串转换为Uint8Array
反之,Uint8Array→DataURL转换的逆过程如下:
// Base64 Encoded String to Uint8Array
const convertB64ToBitArr = (b64Str) => ( Uint8Array.from(atob( (b64Str.includes(';base64,') ? (b64Str.split(','))[1] : b64Str) ), (v) => v.charCodeAt(0)) );
25.获取浏览器垂直滚动条宽度
function getScrollbarWidth() {
const docEle = document.documentElement;
const cssOverflowY = docEle.style.overflowY; // stores prev value
docEle.style.overflowY = 'scroll'; // force scrollbar to appear
const scrollbarWidth = window.innerWidth - docEle.clientWidth;
docEle.style.overflowY = cssOverflowY; // reset to prev value
return scrollbarWidth;
}
const sbWidth = getScrollbarWidth(); // 17
/* comments */
// In which case, scrollbar width is 17px for my browser
// and width of elements should factor in this value in its css attributes
26. 将年、月和日添加到 Date() 对象
虽然 JavaScript 没有特定于 Date() 对象的时间单位减法/加法的内置方法,但可以使用辅助方法来构造以下实用函数。
function addYears(date, n) {
const dateCopy = new Date(date);
dateCopy.setFullYear(dateCopy.getFullYear() + n);
return dateCopy;
}
function addMonths(date, n) {
const dateCopy = new Date(date);
dateCopy.setMonth(dateCopy.getMonth() + n);
return dateCopy;
}
function addDays(date, n) {
const dateCopy = new Date(date);
dateCopy.setDate(dateCopy.getDate() + n);
return dateCopy;
}
使用示例:
const currentDate=new Date();
console.log(`Current date: ${currentDate}`);
console.log(`Current date + 11 years: ${addYears(currentDate, 11)}`);
console.log(`Current date + 11 months: ${addMonths(currentDate, 11)}`);
console.log(`Current date + 11 days: ${addDays(currentDate, 11)}`);
/* Sample output */
// Current date: Fri Sep 22 2023 23:52:57 GMT+0800 (Singapore Standard Time)
// Current date + 11 years: Fri Sep 22 2034 23:52:57 GMT+0800 (Singapore Standard Time)
// Current date + 11 months: Thu Aug 22 2024 23:52:57 GMT+0800 (Singapore Standard Time)
// Current date + 11 days: Tue Oct 03 2023 23:52:57 GMT+0800 (Singapore Standard Time)
27.从数组中删除无效值,例如null和undefined
const removeInvalidVals = ((arr) => arr.filter(ele => (ele !== null && typeof ele !== 'undefined') ? true : false));
上面的函数从数组中删除空值和未定义的值。 一个常见的用例是从 API 调用的 JSON 响应中排除无效值。
使用示例:
let arr = [1, 3, undefined, 5, null, null, 8];
arr = removeInvalidVals(arr);
console.log(arr);
/* Expected output */
// [1, 3, 5, 8]
28. 数组中的唯一值
操作数组的另一个方便的实用函数是删除其中的重复值 。
const uniqueArr = ((arr) => (Array.from(new Set(arr))));
使用示例:
let arr = [1, 1, 3, 2, 5, 3, 4, 7, 7, 7, 8];
arr = uniqueArr(arr);
console.log(arr);
/* Expected output */
// [1, 3, 2, 5, 4, 7, 8]
29. 通过解析字符串创建新的 HTML DOM 元素
HTML <template> 标签用于保存 HTML 内容以供稍后呈现。 下面的函数 htmlToElement() 不是使用 createElement() 在 JavaScript 中从头开始创建元素,而是直接从 HTML 字符串创建子节点。
function htmlToElement(html) {
if (!(document.createElement("template").content)) {
alert('Your browser does not support "template".');
return;
}
let documentFragment = document.createDocumentFragment();
let template = document.createElement('template');
template.innerHTML = html.trim();
for (let i = 0, e = template.content.childNodes.length; i < e; i++) {
documentFragment.appendChild(template.content.childNodes[i].cloneNode(true));
}
return documentFragment;
}
使用示例
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='utf-8'>
</head>
<body>
<div id='pageContainer'></div>
</body>
</html>
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='utf-8'>
</head>
<body>
<div id='pageContainer'></div>
</body>
</html>

30. 打印网页
/* Assume there is a <button> HTML element in the DOM */
// <button id='printPage' type='button'>Print</button>
const printPageBtn = document.getElementById('printPage');
printPageBtn.addEventListener('click', () => {
requestAnimationFrame(() => {
window.print();
});
});
