dom操作
dom文档碎片优化节点添加
for (var i = 0; i < 10; i++) {
var oP = document.createElement('p')
oP.innerHTML = i
document.body.appendChild(oP)
}
const fragEle = document.createDocumentFragment()
for (var i = 0; i < 10; i++) {
var oP = document.createElement('p')
oP.innerHTML = i
fragEle.appendChild(oP)
}
document.body.appendChild(fragEle)
for (var i = 0; i < 3; i++) {
var oP = document.createElement('p')
oP.innerHTML = i
document.body.appendChild(oP)
}
var oldP = document.getElementById('box1')
for (var i = 0; i < 3; i++) {
var newP = oldP.cloneNode(false)
newP.innerHTML = i
document.body.appendChild(newP)
}
动态加载js
function loadJS(files, done) {
const head = document.getElementsByTagName('head')[0];
Promise.all(files.map(file => {
return new Promise((resolve) => {
const script = document.createElement('script');
script.type = 'text/javascript';
script.async = true;
script.src = file;
script.addEventListener('load', resolve,false);
head.appendChild(script);
});
})).then(done);
}
loadJS(['./arithmetic.js', './binaryTree.js'],()=>{
console.log("all load");
});
获取元素尺寸位置
const box = document.getElementById('box');
const {x,y,width,height} = box.getBoundingClientRect();
dom节点四大监听
1 异步监测元素可见 IntersectionObserver 懒加载demo
const images = document.querySelectorAll('img');
const observer = new IntersectionObserver((entries,observer)=>{
entries.forEach(entry=>{
if(entry.isIntersecting){
const img = entry.target;
const src = img.dataset.src;
if(src){
img.src = src;
observer.unobserve(img);
}
}
});
},{threshold:0.5});
images.forEach(image=>{
observer.observe(image);
});
2 观察dom,特定属性变动
var insertedNodes = [];
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
for (var i = 0; i < mutation.addedNodes.length; i++) {
var node = mutation.addedNodes[i];
if (node.nodeType === 1) {
insertedNodes.push(node);
}
}
});
});
var config = { attributes: true, childList: true, subtree: true };
observer.observe(document.body, config);
3 观察元素大小变化
const resizeObserver = new ResizeObserver((entries)=>{
entries.forEach(entry=>{
});
});
resizeObserver.observe(document.getElementById('box'));
4 浏览器各项指标监测
const ovserver = new PerformanceObserver((list)=>{
list.getEntries().forEach(entry=>{
console.log(entry);
if(entry.initiatorType === 'img'){
console.log('图片加载时间',entry.duration);
}
if(entry.name === 'first-contentful-paint'){
console.log('首次渲染时间',entry.startTime);
}
});
});
ovserver.observe({entryTypes:['resource','paint']});
平滑滚动到元素视图中
const scrollToElement = (element)=>{
element.scrollIntoView({behavior: 'smooth',block: 'center'});
}
scrollToElement(document.getElementById('box'));
点击元素外事件
const outsideClick = (element,callback)=>{
const outside = (e)=>{
if(!element.contains(e.target)){
callback();
document.removeEventListener('click',outside);
}
}
document.addEventListener('click',outside);
}
获取选定的文本
const getSelectedText = ()=>{
return window.getSelection().toString();
}
getSelectedText();
url处理 常用功能
const baseUrl = (url)=>url.replace(/[?#].*$/, '');
console.log(baseUrl('https://www.baidu.com/s?wd=hello'));
const absoluteUrl = (url)=>/^[a-z][a-z0-9+.-]*:/.test(url);
absoluteUrl('https://www.baidu.com/s?wd=hello');
absoluteUrl('hello.html');
const getURLParamet = (url)=>
(url.match(/([^?=&]+)(=([^&]*))/g) || []).reduce(
(a, v) => (a[v.slice(0, v.indexOf('='))] = v.slice(v.indexOf('=') + 1), a),
{}
);
getURLParamet('https://www.baidu.com/s?wd=hello');
const getAncestors = (el)=>{
const parents = [];
while(el){
parents.unshift(el);
ancestor = el.parentNode;
}
return parents;
}
sse (它允许服务器向客户端推送数据)
if ('EventSource' in window) {
const source = new EventSource('http://localhost:8080/sse');
source.addEventListener('message', function(event) {
console.log(event.data);
});
source.addEventListener('open', function(event) {
console.log('SSE 连接已经打开!');
});
source.addEventListener('close',function(event){
console.log('SSE 连接已经关闭。');
source.close();
source.removeEventListener('message');
source.removeEventListener('open');
source.removeEventListener('close');
source.removeEventListener('error');
});
source.addEventListener('error', function(event) {
if (event.eventPhase === EventSource.CLOSED) {
console.log('SSE 连接已经关闭。');
} else {
console.log('发生了未知错误。');
}
});
}
防抖、节流
function debounce(fn, delay) {
let timer = null;
return function() {
const context = this;
const args = arguments;
clearTimeout(timer);
timer = setTimeout(function() {
fn.apply(context, args);
}, delay);
};
}
function throttle(fn, delay) {
let canRun = true;
return function() {
if (!canRun) return;
canRun = false;
setTimeout(() => {
fn.apply(this, arguments);
canRun = true;
}, delay);
};
}
window.addEventListener('resize', debounce(function() {
console.log('Resize event handler');
}, 200));
window.addEventListener('scroll', throttle(function() {
console.log('Scroll event handler');
}, 200));
js 简化技巧
For循环优化
var arrList = new Array(1, 2, 3, 4, 5);
for (var i = 0; i < arrList.length; i++) {
console.log(i)
}
for (var i = 0; len = arrList.length; i < len; i++) {
console.log(i)
}
arrList.forEach(function(item) {
console.log(item)
})
for (var i = arrList.length; i; i--) {
console.log(arrList[i])
}
去除数组假值
let arr = [0, '', false, null, undefined, NaN,12,-25,0.5];
let filterArr = arr.filter(Boolean);
数组查找某个值是否存在
let arr = [1, 2, 3, 4, 5];
if (~arr.indexOf(4)) {
console.log('存在');
}
if (arr.includes(4)) {
console.log('存在');
}
空值合并运算
let data;
let userName = data ?? 'admin';
let myName = null;
myName ??= 'admin';
console.log(myName,userName);
myName ||= 'leo';
短路求值 false 0 '' null undefined NaN
let valueDL = data || 'new';
let valueDL1 = data && 'new';
多值匹配,简化 if (a === 1 || a === 2 || a === 3)
let value = 'two';
if([1,'one',2,'two',3,'three'].includes(value)){
console.log('value is either 1,2 or 3');
}
查看对象是否有值
Object.keys(obj).length === 0;
日期是否有效
const isDateValid = (...val)=>!Number.isNaN(new Date(...val).valueOf());
isDateValid(2019,1,1);
isDateValid('december 17,1995 03:24:00');
函数强制参数
function foo(bar){
if(bar === undefined){
throw new Error('bar is required');
}
return bar;
}
let mandatory = () => {
throw new Error('bar is required');
}
let foo = (bar = mandatory()) => {
return bar;
};
扁平化数组
let arrFlat = [1, 2, [3], [4, 5]];
let arrFlat2 = arrFlat.flat();
let arrFlat3 = arrFlat.flatMap(x => x);
let arrFlat1 = arrFlat.reduce((acc, val) => acc.concat(val), []);
数组of,from,at
const arr1 = Array.of(1,2,3);
const arr2 = Array.from('123');
const doubled = Array.from([1,2,3],x=>x*2);
const arr3 = [1,2,3];
arr3.at(2);
promise.all实现并发请求
function fetchData(urls) {
const promises = urls.map(url => fetch(url));
return Promise.all(promises).then(res => {
return res.json();
});
}
reduce 常用技巧
let redTotal = [0, 1, 2, 3].reduce((acc, val) => acc + val, 0);
let redFlat = [1, 2, [3, 4]].reduce((acc, val) => acc.concat(val), []);
let numbers = [1, 2, 3, 4, 5];
let odds = numbers.filter(v => v % 2).map(v => v * 2);
let odds2 = numbers.reduce((acc, val) => {
if(val % 2) acc.push(val * 2);
return acc;
}, []);
let names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
let countedNames = names.reduce(
(acc, name) => {
acc[name] = (acc[name] || 0) + 1;
return acc;
}
, {});
const functions = [
async function() { return 1; },
async function() { return 2; },
async function() { return 3; },
];
const results = await functions.reduce((promise, fn)=>{
return promise.then(fn);
},Promise.resolve());
console.log(results);
let str = 'hello';
let revStr = str.split('').reduce((acc, val) => val + acc, '');
let revStr2 = str.split('').reverse().join('');
console.log(revStr);
let arr = [1, 2, 3, 4, 5, 5, 4, 3, 2, 1];
let uniqArr = arr.reduce(
(acc, val) => {
return acc.includes(val) ? acc : acc.push(val);
},
[]
);
let uniqArr2 = [...new Set(arr)];
[...'(())()(()())'].reduce((a,i)=>i==='('?a+1:a-1,0);
数组转换
let arr = [1, 2, 3, 4, 5, 2, 4, 6, 7, 8, 9, 10];
let set = new Set(arr);
let arr2 = [...set];
let arr3 = Array.from(set);
优化查找
let arr4 = [1, 2, 3, 4, 5, 2, 4, 6, 7, 8, 9, 10];
let dataSet = new Set(arr4);
if(dataSet.has(2)){
console.log('2 is in the array');
}
js 取整
Math.floor(Math.random()*50);
~~(Math.random()*50);
高效数组合并
const arr1 = [1,2,3,4,5];
const arr2 = [6,7,8,9,10];
console.log(list1.concat(list2));
console.log(arr1.push.apply(arr1,arr2));
const arr3 = [...arr1,...arr2];
map转换 map转对象,map转数组
let map = new Map().set('a', 1).set('b', 2).set('c', 3);
let obj = Object.fromEntries(map)
let array = Array.from(map);
let myMay = new Map(Object.entries(obj));
单例
class SingleClass{
constructor(){
console.log("SingleClass");
}
static getInstance(){
if(!this.instance){
this.instance = new SingleClass();
}
return this.instance;
}
}
const s1 = SingleClass.getInstance();
const s2 = SingleClass.getInstance();
console.log(s1 === s2);
RGB转16进制
const rgbToHex = (r,g,b)=>"#"+((1<<24)+(r<<16)+(g<<8)+b).toString(16).slice(1);
rgbToHex(255,255,255);
缓存函数结果
function memoize(fn) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
return cache.get(key);
}
const result = fn.apply(this, args);
cache.set(key, result);
return result;
};
}