功能

  • requestAnimationFrame 是一种优化动画渲染的 API。
  • 它告诉浏览器在下一次重绘之前执行指定的回调函数,通常用于实现流畅的动画。
  • 和固定时间间隔的 setTimeoutsetInterval 不同,requestAnimationFrame 会自动与浏览器的刷新率同步(如 60Hz,16.67ms 一帧)。

特点

高效:只在页面处于活动状态时执行回调(后台标签页会暂停,节省资源)。
精准:与显示器的刷新率匹配,避免丢帧。
流畅:浏览器会在合适的时间点调用回调,减少卡顿或跳帧现象。

常见场景

实现 DOM 动画
平滑滚动效果
监控动画帧性能

浏览器的 Web Components 中,Class 是用来定义自定义元素的主要方式,自定义元素支持以下生命周期回调方法:

生命周期回调:connectedCallback 和 disconnectedCallback

  1. connectedCallback
    作用:当自定义元素被插入到文档 DOM 中时,浏览器会自动调用该回调。
    用途:
    初始化 DOM 或状态。
    绑定事件监听器。
    触发外部依赖的加载操作。
    典型场景:
    加载数据、动态渲染子组件。
    初始化第三方库(如动画、图表库等)。
class MyElement extends HTMLElement {
    connectedCallback() {
        console.log('元素已插入到 DOM');
        this.innerHTML = '<p>Hello, World!</p>';
    }
}
customElements.define('my-element', MyElement);
  1. disconnectedCallback
    作用:当自定义元素从文档 DOM 中被移除时,浏览器会调用该回调。
    用途:
    清理 DOM 或状态。
    移除事件监听器,释放资源。
    停止定时器或取消网络请求。
    典型场景:
    停止动画或计时器。
    删除与外部环境相关的绑定操作。
class MyElement extends HTMLElement {
    disconnectedCallback() {
        console.log('元素已从 DOM 中移除');
    }
}
customElements.define('my-element', MyElement);

功能

  • performance.now() 是一种高精度的时间测量方法,返回自页面加载以来的毫秒数(包括小数点后3位)。

  • 它的精度远高于 Date.now(),适合用于测量代码性能或事件耗时。

    特点

  • 起点是浏览器的性能时间起点,不会受系统时间调整的影响。

  • 时间以 DOMHighResTimeStamp 类型返回,单位为毫秒。

常见场景

  • 测量代码性能
  • 计算动画帧之间的时间间隔
  • 精准测量事件延迟

void 的含义

void 是 JavaScript 的一个运算符,用于计算一个表达式但不返回任何值。void 0 常用于生成 undefined 值,以确保其值始终为 undefined

void 0 是一个确保结果为 undefined 的表达式(即使 undefined 被重新赋值也不会影响 void 0 的结果)

在这里,void 0 !== arguments[3] 是为了安全地检查第四个参数是否被定义。

&& (逻辑与)

  • 规则: && 运算符会从左到右依次求值,直到找到第一个 false 值。如果所有表达式都为 true,则返回最后一个表达式的值;如果某个表达式为 false,则直接返回该 false 值,并停止进一步的求值。

  • 应用

var n = 3 < arguments.length && void 0 !== arguments[3] && arguments[3];
  • 解释: 在这里,&& 用于连接多个条件。如果 3 < arguments.length 为 true,继续判断 void 0 !== arguments[3];如果也为 true,再判断 arguments[3] 的值,并将其赋值给 n。如果任何一个条件为 falsen 将会被赋值为该 false 值。

  • 总结: 只有在所有条件都为 true 的情况下,n 才会被赋值为 arguments[3] 的值;否则,n 会被赋值为第一个 false 条件的值。

|| (逻辑或)

  • 规则: || 运算符也从左到右依次求值,但它会返回第一个 true 的表达式值,并停止进一步的求值。如果所有表达式都为 false,则返回最后一个表达式的值。

  • 应用
    如果将 && 替换为 ||

    var n = 3 < arguments.length || void 0 !== arguments[3] || arguments[3];
  • 解释: 在这种情况下,n 将被赋值为第一个 true 条件的值。如果 3 < arguments.length 为 truen 将立即被赋值为 true,并停止进一步判断。如果 3 < arguments.length 为 false,则检查 void 0 !== arguments[3],依此类推。

  • 总结: 只要有一个条件为 truen 就会被赋值为第一个 true 条件的值;如果所有条件都为 falsen 将被赋值为最后一个条件的值。

逗号运算符在 JavaScript 中是一个少见但非常有用的运算符,它允许在一行代码中执行多个表达式,并返回最后一个表达式的值。

逗号运算符的含义

规则: 使用逗号运算符时,表达式会从左到右依次执行,每个表达式都会被计算,但只有最后一个表达式的值会被返回。

在 t 变量中的应用:

t = ((r.items = t),
    gtm4wp_clear_ecommerce &&
    window[gtm4wp_datalayer_name].push({ ecommerce: null }),
    { event: e, ecommerce: r });
  • 解释: 这里逗号运算符用于执行一系列操作:
  1. r.items = t:将 t 赋值给 r.items,用于将商品列表存入 r 对象中。

  2. gtm4wp_clear_ecommerce && window[gtm4wp_datalayer_name].push({ ecommerce: null }):如果 gtm4wp_clear_ecommercetrue,则将 { ecommerce: null } 推送到 dataLayer,清空之前的电子商务数据。

  3. { event: e, ecommerce: r }:这是逗号表达式的最后一个表达式,它的值将赋值给 t。

  • 总结: 尽管逗号运算符前的每个表达式都会被执行,但最终 t 的值是 { event: e, ecommerce: r } 这个对象。

在变量赋值时使用逗号运算符

  • 可行性: JavaScript 确实允许在变量赋值时使用逗号运算符。这可以在单行代码中执行多个表达式,最后将最后一个表达式的值赋给变量。

  • 使用场景: 这种写法通常用于代码简化或在需要执行一系列操作但只关心最终结果的场合。需要注意的是,虽然这种用法很强大,但过度使用可能会降低代码的可读性。

currentScript 属性是 JavaScript 中 document 对象的一个属性,它返回正在执行的 <script> 元素。这个属性对于动态加载脚本或在脚本内部引用脚本元素本身时非常有用。

应用场景

动态加载脚本:

  • 可以在动态加载的脚本中获取脚本元素本身的属性(如 src、data-* 等),以便进行进一步的逻辑处理。

    模块化脚本:

  • 在模块化脚本中,可以根据脚本元素上的自定义属性来决定脚本的行为。

调试和日志记录:

  • 在大型项目中,特别是加载多个脚本时,可以通过 currentScript 获取当前执行的脚本,帮助调试和日志记录。

 样式和内容注入:

  • 可以在脚本执行时,动态地将样式或内容注入到页面的特定位置,基于脚本标签的位置或属性。

假设有一个动态加载的脚本,它根据 data-theme 属性来设置页面的主题样式。

    <h1 id="title">Hello World!</h1>
    <script src="theme-loader.js" data-theme="dark"></script>
// 获取当前执行的脚本元素
const script = document.currentScript;

// 从脚本元素中获取 data-theme 属性的值
const theme = script.getAttribute("data-theme");

// 定义主题样式
const themes = {
  dark: {
    backgroundColor: "#333",
    color: "#fff",
  },
  light: {
    backgroundColor: "#fff",
    color: "#000",
  },
};

// 应用主题样式
const applyTheme = (themeName) => {
  const themeStyles = themes[themeName];
  if (themeStyles) {
    document.body.style.backgroundColor = themeStyles.backgroundColor;
    document.body.style.color = themeStyles.color;
  } else {
    console.warn(`Theme "${themeName}" is not defined.`);
  }
};

// 调用函数应用主题
applyTheme(theme);

event.target 属性可以用来实现事件委托 (event delegation)。

Event 接口的 target 只读属性是对事件分派到的对象的引用。当事件处理器在事件的冒泡或捕获阶段被调用时,它与 event.currentTarget 不同。

// Make a list
var ul = document.createElement("ul");
document.body.appendChild(ul);

var li1 = document.createElement("li");
var li2 = document.createElement("li");
ul.appendChild(li1);
ul.appendChild(li2);

function hide(e) {
  // e.target 引用着 <li> 元素
  // 不像 e.currentTarget 引用着其父级的 <ul> 元素。
  e.target.style.visibility = "hidden";
}

// 添加监听事件到列表,当每个 <li> 被点击的时候都会触发。
ul.addEventListener("click", hide, false);

Element.closest() 方法用来获取:匹配特定选择器且离当前元素最近的祖先元素(也可以是当前元素本身)。如果匹配不到,则返回 null。

<article>
  <div id="div-01">
    Here is div-01
    <div id="div-02">
      Here is div-02
      <div id="div-03">Here is div-03</div>
    </div>
  </div>
</article>
var el = document.getElementById("div-03");

var r1 = el.closest("#div-02");
// 返回 id 为 div-02 的那个元素

var r2 = el.closest("div div");
// 返回最近的拥有 div 祖先元素的 div 祖先元素,这里的话就是 div-03 元素本身

var r3 = el.closest("article > div");
// 返回最近的拥有父元素 article 的 div 祖先元素,这里的话就是 div-01

var r4 = el.closest(":not(div)");
// 返回最近的非 div 的祖先元素,这里的话就是最外层的 article