在JavaScript中,forEach 方法和 for...of 循环都可以用于遍历数组(或类数组对象)中的元素。但是,它们在使用上有一些关键的区别:

for...of 循环

  • 更多控制:for...of 循环提供了对循环的更多控制,包括使用 break, continue 和 return(如果在函数内部)来控制循环流程。
  • 更广泛的适用性:除了数组之外,for...of 可以用来遍历任何实现了迭代协议的对象,包括字符串、Map、Set等。
  • 异步迭代:for...of 循环可以与异步迭代(for await...of)结合使用,便于处理异步迭代对象,如异步生成器函数。
  • 示例:
    for (const link of myLinks) {
    link.onclick = (e) => {
        e.preventDefault();
        const linkData = e.target.getAttribute("data-page");
        getData(linkData);
    };
    }

    forEach 方法

  • 针对数组设计:forEach 方法特定于数组,是 Array 的一个方法。它不适用于没有实现 forEach 方法的其他可迭代对象。
  • 不能使用 break 和 continue:在 forEach 函数中不能使用 break 或 continue 来退出循环或跳过当前迭代。
  • 回调函数的作用域:forEach 允许为回调函数指定一个可选的第二参数,用作回调函数内 this 的值。而在 for...of 循环中,通常通过闭包或外部变量来访问外部作用域。
  • 无法直接使用异步操作:虽然在 forEach 的回调函数中可以执行异步操作,但是 forEach 本身不会等待这些异步操作完成。如果需要处理异步操作,可能需要使用 for...of 循环结合 async/await 或其他方法。
    示例:

    myLinks.forEach((myLink) => {
    myLink.addEventListener("click", function(e) {
        e.preventDefault();
        const linkData = e.target.getAttribute("data-page");
        getData(linkData);
    })
    });
const reqHeaders = new Headers();
// a cached response is okay unless it's more than a week oldreqHeaders.set("Cache-Control", "max-age=604800");

Cache-Control 是一个 HTTP 头部字段,用于定义缓存策略。在客户端和服务端都有广泛的应用。一些常见的 Cache-Control 指令包括:

  • max-age=<seconds>: 指定一个时间长度,在这段时间内,缓存的副本仍然是新鲜的。
  • no-cache: 强制所有缓存了该响应的缓存器在使用已缓存的数据前,发送请求到原始服务器进行验证。
  • no-store: 禁止缓存,表示请求或响应中的信息不应被存储在缓存中。

appendChildappend 在 JavaScript 中都是用来向 DOM 中添加元素的方法,但它们之间存在一些差异:

appendChild

appendChild 方法是 DOM API 的一部分,用于将一个节点作为最后一个子节点添加到指定父节点中。
appendChild 只能接收一个节点作为参数,如果尝试传入非节点(如字符串),将会抛出错误。
appendChild 方法将返回被添加的节点。
使用示例:

const parentElement = document.getElementById('parent');
const newElement = document.createElement('div');
parentElement.appendChild(newElement); // 在parent元素中添加一个新的div作为子节点

append

append 方法是一个较新的 DOM API,它允许你同时向父节点添加多个子节点或字符串。
append 可以接受任意数量的参数,参数可以是 DOM 节点或者是文本。这使得它比 appendChild 更灵活。
append 不会返回任何值。
使用示例(与你提供的代码类似)

const parentElement = document.getElementById('parent');
const newElement = document.createElement('div');
const textContent = 'Hello, World!';
parentElement.append(newElement, textContent); // 在parent元素中添加一个新的div和文本'Hello, World!'作为子节点

Response.blob()方法和Blob()构造函数都可以用来创建Blob对象,但它们的使用场景和目的有所不同。

Response.blob()

Response.blob()是Fetch API的一部分,它是在处理Fetch请求的响应时使用的。当您向一个服务器发送请求并接收到响应时,如果响应数据是二进制数据,您可以使用Response.blob()来获取这些数据的Blob对象。
例如,如果您请求一个图片或视频文件,服务器的响应可以通过Response.blob()转换为Blob对象。转换后的Blob对象可以用于多种用途,比如使用URL.createObjectURL()创建一个URL来显示这个图片或视频。
这个方法是异步的,返回一个Promise对象,这意味着您需要使用.then()方法或async/await语法来处理结果。

fetch('image.png')
  .then(response => response.blob())
  .then(blob => {
    // 使用获取到的blob对象
    const imageUrl = URL.createObjectURL(blob);
    document.querySelector('img').src = imageUrl;
  });

Blob()构造函数

Blob()构造函数用于直接在JavaScript中创建一个新的Blob对象。您可以提供一个数组作为第一个参数,数组中的每个元素都会成为Blob对象的一部分。这些元素可以是字符串、ArrayBuffer或者另一个Blob对象等。第二个参数是一个可选的对象,指定了Blob对象的属性,比如type属性来指定MIME类型。
这个构造函数主要用于在程序中动态创建二进制数据。您可以使用它来创建文件、处理文本或生成媒体内容等。

const blobParts = ['<q id="a"><span id="b">hey!</span></q>']; // 一个包含单个字符串的数组
const blob = new Blob(blobParts, { type: "text/html" }); // 得到blob
// 使用创建的blob对象
const url = URL.createObjectURL(blob);
document.querySelector('iframe').src = url;

Blob(Binary Large Object)对象表示了一个不可变的、原始数据的类文件对象。Blob对象可以表示存储在内存中的大量数据,比如图片、视频、音频或其他二进制格式的文件。通过JavaScript,我们可以用Blob来处理这些数据,实现多种功能,比如文件下载、上传、处理和转换等。

Blob的应用场景

1. 创建和下载文件

您可以使用Blob来动态创建文件内容,并允许用户下载这些文件。例如,您可以将一个文本数组转换成Blob对象,然后通过创建一个指向该Blob的URL,并将其设置为标签的href属性,实现文件的下载功能。

2. 上传文件

在前端,Blob可以用于上传文件。Blob对象可以通过AJAX或Fetch API上传到服务器。这对于上传图片或视频文件等大型文件特别有用,因为Blob可以将文件作为二进制数据传输,提高效率。

3. 从Blob对象创建URL

可以使用URL.createObjectURL()方法从Blob对象创建一个URL。这个URL可以用于在网页上显示Blob数据,例如显示图片或视频。

const blob = new Blob([document.querySelector('textarea').value], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
document.querySelector('img').src = url;

4. 处理媒体文件

Blob非常适合于处理媒体文件,比如图片,MP4视频等。例如,您可以读取用户选择的图片文件,并使用Blob来预览图片;或者,您可以通过JavaScript处理视频文件,比如截取视频的一部分或更改视频的编码格式。

5. 缓存数据

Blob也可以用于前端的数据缓存。对于从服务器获取的大型数据(如JSON数据、图片或视频文件),您可以将其存储为Blob,然后在本地缓存。当需要这些数据时,可以直接从Blob读取,避免重复从服务器加载数据,提高应用性能。

使用 Parcel 插件处理静态文件

npm install parcel-plugin-static-files-copy --save-dev

在项目根目录创建一个 static 文件夹,并将 flowers.jpg 文件放入其中。

创建或更新 package.json 文件:

{
  "scripts": {
    "start": "parcel basic-fetch.html"
  },
  "staticFiles": {
    "staticPath": "static",
    "staticOutPath": "./"
  }
}

将 flowers.jpg 文件移动到 static 文件夹中:
...
运行项目

在JavaScript中,for...in和for...of是两种不同的循环语句,它们被用于遍历不同类型的数据结构。

for...in

描述:for...in循环用于遍历一个对象的属性。
行为:它迭代对象的所有可枚举属性,包括原型链上继承的属性。
适用场景:
当需要遍历对象属性名时使用。
适合用于对象自定义属性的迭代。
不推荐用于数组的迭代,因为它不仅遍历数组索引,还可能遍历自定义属性及原型链上的属性。

for...of

描述:for...of循环用于遍历可迭代对象的元素,如数组、字符串、Map、Set等。
行为:它迭代对象的值,而不是属性名。
适用场景:
当需要遍历数组、字符串、类数组对象(如NodeList)、Map、Set、以及实现了可迭代协议的自定义对象的值时使用。
适合用于遍历各种集合对象中的元素值。
不适用于普通对象,因为普通对象默认不是可迭代的。

// for...in 示例
const obj = { a: 1, b: 2, c: 3 };
for (const prop in obj) {
  console.log(`obj.${prop} = ${obj[prop]}`);
}

// for...of 示例
const arr = [1, 2, 3, 4, 5];
for (const value of arr) {
  console.log(value);
}

在for...in示例中,将会输出对象obj的每个属性和值。而在for...of示例中,将会输出数组arr中的每个数字值。
注意
使用for...in遍历数组时应当小心,因为该方法遍历的是对象的键,而不是值。如果数组对象上有附加属性或者数组原型被扩展,则这些属性也会被遍历。这不是遍历数组元素的推荐方法。而for...of则提供了一种简单而直接的方式来迭代数组元素。
总结来说,for...in主要用于遍历对象的属性,而for...of主要用于遍历具有迭代行为的集合对象的元素值。选择哪个循环语句取决于你的具体需求和正在操作的数据类型。

textContent、innerHTML和insertAdjacentHTML是JavaScript中用于操作DOM元素内容的三种不同方法。每种方法都有其特定的用途和行为。
textContent
描述:textContent属性用于获取或设置指定节点及其后代的文本内容。
特点:当设置内容时,它会替换元素的所有子节点,并且只能设置文本内容,不能解析HTML标签。
使用场景:适用于当你只需要操作文本,而不需要HTML标签时。这种方法防止了HTML注入,更加安全。
innerHTML
描述:innerHTML属性用于获取或设置HTML或XML元素中的HTML内容。
特点:可以解析HTML标签,并将其渲染成对应的元素。使用此属性设置HTML内容时,浏览器会解析字符串并创建新的DOM树。
使用场景:当你需要包含HTML标签的内容时使用,但需要注意避免跨站脚本(XSS)攻击。
insertAdjacentHTML
描述:insertAdjacentHTML方法将指定的文本解析为HTML或XML,并将生成的节点插入到DOM树中的指定位置。
特点:它不会重新解析调用它的元素(从而不会破坏元素内部已经存在的DOM结构),而只是添加新的元素,这使得它相对于innerHTML来说性能更优。
参数:接受两个参数,第一个是插入位置('beforebegin'、'afterbegin'、'beforeend'、'afterend'),第二个是要插入的HTML字符串。
使用场景:适用于需要将内容插入到元素内部或周围,而不是替换元素内部所有内容的情况。更适合动态添加内容,因为它允许更细致地控制插入的位置。

insertAdjacentHTML方法的使用场景包括但不限于以下几种:
动态内容插入:当你需要在页面上动态地插入新的HTML元素或内容时,insertAdjacentHTML可以让你指定插入的位置,而不需要替换或重写现有的元素内部HTML。
性能优化:如果你需要向页面中频繁添加元素,insertAdjacentHTML通常比innerHTML更高效,因为它不需要重新解析调用它的元素的内部HTML,这可以减少重绘和重排带来的性能开销。
避免直接DOM操作开销:直接使用DOM方法(如createElement和appendChild)创建和添加复杂的HTML结构可能很繁琐。相比之下,insertAdjacentHTML可以一次性插入整个HTML片段。
维持现有脚本和监听器:在不需要或不想干扰元素内部现有子节点的事件监听器或脚本运行的情况下,使用insertAdjacentHTML可以插入新内容而不影响现有内容。
页面模板填充:当使用模板文字来生成HTML内容时,可以使用insertAdjacentHTML将生成的内容插入到页面的指定位置。
快速原型和测试:在开发过程中,当需要快速测试或原型设计时,insertAdjacentHTML可以方便快速地将HTML片段加入页面。
插入位置参数
insertAdjacentHTML方法接收两个参数:第一个参数是一个表示相对位置的字符串,第二个参数是要插入的HTML字符串。第一个参数可以是以下四个值之一:
'beforebegin':在当前元素之前插入HTML。
'afterbegin':在当前元素的第一个子节点之前插入HTML。
'beforeend':在当前元素的最后一个子节点之后插入HTML。
'afterend':在当前元素之后插入HTML。
实例
假设你有一个列表,并且想要在列表的末尾添加新的列表项,可以使用insertAdjacentHTML如下:

var list = document.getElementById('myList');
list.insertAdjacentHTML('beforeend', '<li>新的列表项</li>');

这将在现有列表的最后添加一个新的

  • 元素,而不会干扰到列表中已有的其他列表项及其绑定的事件。

  • 
    // one-liner version
    // retains latin-1 supplement chars as well as latin extended-a and latin extended-b
    
    Shopify.handleize = function (str) {
        return str.toLowerCase().replace(/[^\w\u00C0-\u024f]+/g, "-").replace(/^-+|-+$/g, "");
    };
    
    // from https://github.com/Shopify/liquid/blob/63eb1aac69a31d97e343822b973b3a51941c8ac2/performance/shopify/shop_filter.rb#L100
    Shopify.handleize = function (str) {
        str = str.toLowerCase();
    
        var toReplace = ['"', "'", "\\", "(", ")", "[", "]"];
    
        // For the old browsers
        for (var i = 0; i < toReplace.length; ++i) {
            str = str.replace(toReplace[i], "");
        }
    
        str = str.replace(/\W+/g, "-");
    
        if (str.charAt(str.length - 1) == "-") {
            str = str.replace(/-+\z/, "");
        }
    
        if (str.charAt(0) == "-") {
            str = str.replace(/\A-+/, "");
        }
    
        return str
    };