③ 对返回值进行按位取反(所有正整数的按位取反是其本身+1的负数,所有负整数的按位取反是其本身+1的绝对值,零的按位取反是 -1。其中,按位取反也会对返回值进行强制转换,将字符串5转化为数字5,然后再按位取反。
false被转化为0,true会被转化为1。
其他非数字或不能转化为数字类型的返回值,统一当做0处理)
const visibleIndex = newSet(); //全局创建一个不重复的集合 let ob = newIntersectionObserver((entries) => { for (const e of entries) { const index = e.target.dataset.index; //isIntersecting为true就代表在视口内 if (e.isIntersecting) {
visibleIndex.add(index);
} else {
visibleIndex.delete(index);
}
} debounceLoadPage();// 防抖后的loadpage
});
3.获取集合的最大及最小的索引
functiongetRange() { if (visibleIndex.size === 0) return [0, 0]; const max = Math.max(...visibleIndex); const min = Math.min(...visibleIndex); return [min, max];
}
4.加载视口内的元素的资源
functionloadPage() { // 得到当前能看到的元素索引范围 const [minIndex, maxIndex] = getRange(); const pages = newSet(); // 不重复的页码集合 for (let i = minIndex; i <= maxIndex; i++) {
pages.add(getPage(i, SIZE));// 遍历将侦查器集合范围内的所在页面都加入到pages的集合内
} // 遍历页码集合 for (const page of pages) { const [minIndex, maxIndex] = getIndexRange(page, SIZE);//获取页码的索引范围 if (contain.children[minIndex].dataset.loaded) { //如果页码最小索引的元素有自定义属性就跳过,代表加载过 continue;
}
contain.children[minIndex].dataset.loaded = true;//如果没有就代表没有加载过,添加上自定义属性 //将当前页码传给获取资源的函数 getVideo(page, SIZE).then((res) => { //拿到当前页面需要的数据数组,遍历渲染到页面上 for (let i = minIndex; i < maxIndex; i++) { const item = contain.children[i];
item.innerHTML = `<img src="${res[i - minIndex].cover}" alt="">`;
}
});
}
}
<body> <divclass="contain"></div> <divclass="btn"> <buttonclass="full-rounded"> <span>刚刚看过</span> <divclass="border full-rounded"></div> </button> </div> <scriptsrc="./api.js"></script> <scriptsrc="./index.js"></script> <script> constSIZE = 15; let contain = document.querySelector(".contain"); let btn = document.querySelector(".btn"); // 页码 let i = 1;
const visibleIndex = newSet();
// 视口观察器 let ob = newIntersectionObserver((entries) => { for (const e of entries) { const index = e.target.dataset.index; if (e.isIntersecting) { // 将在视口内的元素添加到集合内
visibleIndex.add(index);
} else { // 将不在视口内的元素从集合内删除
visibleIndex.delete(index);
}
} debounceLoadPage();
});
functiongetRange() { if (visibleIndex.size === 0) return [0, 0]; const max = Math.max(...visibleIndex); const min = Math.min(...visibleIndex); return [min, max];
}
第一次先点击快照记录初始的内存情况,然后我们多次点击按钮后再次点击快照,记录此时的内存情况,发现从原来的1.1M内存空间变成了1.4M内存空间,然后我们选中第二条快照记录,可以看到右上角有个All objects的字段,其表示展示的是当前选中的快照记录所有对象的分配情况,而我们想要知道的是第二条快照与第一条快照的区别在哪,所以选择Object allocated between Snapshot1 and Snapshot2即展示第一条快照和第二条快照存在差异的内存对象分配情况,此时可以看到Array的百分比很高,初步可以判断是该变量存在问题,点击查看详情后就能查看到该变量对应的具体数据了
let left = startPos.current.left; let top = startPos.current.top; const width = Math.abs(e.clientX - startPos.current.left); const height = Math.abs(e.clientY - startPos.current.top);
// 当后面位置小于前面位置的时候,需要把框的坐标设置为后面的位置 if (e.clientX < startPos.current.left) {
left = e.clientX;
}
if (e.clientY < startPos.current.top) {
top = e.clientY;
}
/**
* Union type with pipe operator
* @typedef {Date | string | number} MixDate
*/
/**
* @param {MixDate} date
* @returns {void}
*/ functionshowDate(date) { // date is Date if (date instanceofDate) date; // date is string elseif (typeof date === 'string') date; // date is number else date;
}
/**
* Restrict template by types
* @template {string|number|symbol} T
* @templateY
* @param {T} key
* @param {Y} value
* @returns {{ [K in T]: Y }}
* @example signature:
* function toObject<T extends string | number | symbol, Y>(key: T, value: Y): { [K in T]: Y; }
*/ functiontoObject(key, value) { return { [key]: value };
}
类型守卫:
/**
* @param {any} value
* @return {value is YOUR_TYPE}
*/ functionisYourType(value) { let isType; /**
* Do some kind of logical testing here
* - Always return a boolean
*/ return isType;
}