JavaScript:原生JS实现图片懒加载 获取当前页面滚动条纵坐标的位置scrollTop
1 var heightTop = document .documentElement.scrollTop || document .body.scrollTop;
实现代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 <!DOCTYPE html> <html> <head> <meta charset="utf-8" > <title>LazyLoad</title> <style type="text/css" > *{ margin :0 ; padding: 0 ; list-style: none; } #list img{ width : 500 px; height: 500 px;} </style> </head> <body> <ul id="list" > <li><img _src ="images/1.jpg" alt ="pic" /> </li> <li><img _src ="images/2.jpg" alt ="pic" /> </li> <li><img _src ="images/3.jpg" alt ="pic" /> </li> <li><img _src ="images/4.jpg" alt ="pic" /> </li> <li><img _src ="images/5.jpg" alt ="pic" /> </li> <li><img _src ="images/6.jpg" alt ="pic" /> </li> <li><img _src ="images/7.jpg" alt ="pic" /> </li> <li><img _src ="images/8.jpg" alt ="pic" /> </li> </ul> <script type="text/javascript" > <script> var oImg = document .getElementsByTagName('img' ); fn(); window .onscroll = function ( ) { fn(); }; function fn ( ) { for (let i=0 ; i<oImg.length; i++ ) { let oImgTo = oImg[i].offsetTop; let clientH = document .documentElement.clientHeight; let scrollT = document .documentElement.scrollTop || document .body.scrollTop; if (clientH + scrollT >= oImgTo ) { oImg[i].src = oImg[i].getAttribute('_src' ); } } } function throttle (method,delay ) { var timer = null ; return function ( ) { clearTimeout (timer); timer=setTimeout (function ( ) { method.apply(this , arguments ); },delay); } } window .onscroll = throttle(lazyload,200 ); </script> </body> </html>
原生js实现ajax 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 const p = new Promise (resolve,reject) => { const xhr = new XMLHttpRequest(); xhr.onreadystatechange = function ( ) { if (xhr.readyState == 4 ) { if (xhr.status === 200 ) { resolve(JSON .prase(xhr.responseText)) } else if (xhr.status === 404 ) { reject(new Error ("404" )) } } }; xhr.open("get" ,"a.txt" ,true ); xhr.send(null ); }
1 2 3 4 5 xhr.open("POST" , options.url, true ); xhr.setRequestHeader("Content-Type" , "application/x-www-form-urlencoded" ); xhr.send(params);
扁平化和去重 扁平化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 function Flat5 (arr ) { var newArr =[]; for (let i in arr ) { if (arr[i] instanceof Array ) { newArr = newArr.concat(Flat5(arr[i])); }else { newArr.push(arr[i]); } } return newArr; } Array .prototype.myFlat = function (num = 1 ) { if (!Number (num) || Number (num) < 0 ) { return this ; } let arr = this .concat(); while (num > 0 ) { if (arr.some(x => Array .isArray(x))) { arr = [].concat.apply([], arr); } else { break ; } num--; } return arr; }; function flatDeep (arr, d = 1 ) { return d > 0 ? arr.reduce((acc, val ) => acc.concat(Array .isArray(val) ? flatDeep(val, d - 1 ) : val), []) : arr.slice(); }; arr.myFlat(Infinity ); var arr1 = [[1 , 2 ],[3 , 4 , 5 ], [6 , 7 , 8 , 9 ]]; console .log(Flat1(arr1));
去重 1 2 3 4 5 6 7 8 9 10 11 12 13 const result = Array .from(new Set (originalArray));const result = [];for (let v of originalArray) { if (!result.includes(v)) { result.push(v); } } let arr = [1 , 2 , 2 , 3 , 4 , 5 , 5 , 6 ];let newArr = arr.filter((x, index,self )=> self.indexOf(x)===index) console .log(newArr)
深拷贝和浅拷贝 浅拷贝 1 2 const arr2 = [].concat(arr1);
深拷贝 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 JSON .parse(JSON .stringify(a))function deepCopy (obj ) { if (obj === null || typeof obj !== 'object' ) { return obj } let copy = Array .isArray(obj) ? [] : {} Object .keys(obj).forEach(key => { copy[key] = deepCopy(obj[key]) }) return copy } delete $obj.c.ddeepCopy($obj) function deepClone (obj ) { if (typeof obj !== 'object' ) { return obj } let copy = Array .isArray(obj)?[]:{}; for (let key in obj ) { if (obj.hasOwnProperty(key) ) { copy[key] = deepClone(obj[key]) } } return copy }
事件委托 1 2 3 4 5 6 7 8 9 10 11 12 window .onload = function ( ) { var oUl = document .getElementById("ul1" ); oUl.onclick = function (ev ) { var ev = ev || window .event; var target = ev.target || ev.srcElement; if (target.nodeName.toLowerCase() == 'li' ) { alert(123 ); alert(target.innerHTML); } } }
防抖节流 防抖
事件被触发 n 秒后执行的回调 如果在这 n 秒内又触发 则重新计时
函数防抖就是法师发技能的时候要读条,技能读条没完再按技能就会重新读条
1 2 3 4 5 6 7 8 9 10 function debounce (fun, delay ) { let timer; return function ( ) { clearTimeour(timer) timer = setTimeout (() => { fun.apply(this , arguments ) }, delay) } }
节流
一事件在单位时间内 多次触发 仅一次有效
函数节流就是fps游戏的射速,就算一直按着鼠标射击,也只会在规定射速内射出子弹
1 2 3 4 5 6 7 8 9 10 11 function throttle (fn, delay ) { let canRun = true ; return function ( ) { if (!canRun) return ; canRun = false ; setTimeout (()=> { fn.apply(this , arguments ) canRun = true ; }, delay) } }
Promise 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 function myPromise (constructor ) { let self=this ; self.status="pending" self.value=undefined ; self.reason=undefined ; function resolve (value ) { if (self.status==="pending" ) { self.value=value; self.status="resolved" ; } } function reject (err ) { if (self.status==="pending" ) { self.reason=reason; self.status="rejected" ; } } try { constructor (resolve,reject ); }catch (e ) { reject(e); } }
然后还要挂载then调用
1 2 3 4 5 6 7 8 9 10 11 12 myPromise.prototype.then=function (onFullfilled,onRejected ) { let self=this ; switch (self.status ) { case "resolved" : onFullfilled(self.value); break ; case "rejected" : onRejected(self.reason); break ; default : } }
Promise.all Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 function diyPromiseAll (arr ) { let res_arr = []; let promiseIndx = 0 ; return new Promise ((resolve, reject ) => { function dealPromise ( ) { if (promiseIndx === arr.length - 1 ) { arr[promiseIndx].then(res => { res_arr.push(res); resolve(res_arr); }) } else { arr[promiseIndx].then(res => { res_arr.push(res); promiseIndx++; dealPromise(); }) } } dealPromise(); }) }
promise.rece(): 顾名思义,Promse.race就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。
call、apply、bind、sleep call后面传递的参数是以逗号的形式分开的,apply传递的参数是数组形式。(apply是以A开头,所以这里可以跟Array有关联,即参数为数组) bind返回的是一个函数形式,如果要执行,则后面要再加一个小括号,例如:bind(obj,参数1,参数2)(),bind只能以逗号分隔形式,不能是数组形式。
bind 1 2 3 4 5 6 7 8 9 Function .prototype.myBind = function (ctx=window , ...args1 ) { let self = this function bFn (...args2 ) { return self.apply(this instanceof bFn ? this : ctx, args1.concat(args2)) } bFn.prototype = this .prototype return bFn }
call 1 2 3 4 5 6 7 Function .prototype.myCall = function (ctx=window , ...args ) { ctx.fn = this let result = ctx.fn(...args) delete ctx.fn return result }
apply 1 2 3 4 5 6 7 Function .prototype.myApply = function (ctx=window , arr ) { ctx.fn = this let result = ctx.fn(...arr) delete ctx.fn return result }
new 1 2 3 4 5 6 7 8 9 10 11 12 function myNew (fn, ...args ) { let obj = Object .create(fn.prototype); let result = fn.apply(obj, args) return typeof result === 'object' ? result : obj }
trim 1 2 3 String .prototype.trim=function ( ) { return this .replace(/(^\s*)|(\s*$)/g , "" ); }
sleep 1 2 3 4 5 function sleep (duration ) { return new Promise (function (resolve ) { setTimeout (resolve, duration); }) }
instantof 1 2 3 4 5 6 7 8 9 10 11 12 function myInstance (left, right ) { var proto = left.__proto__; var prototype = right.prototype; if (proto === null ) { return false ; } else if (proto === prototype) { return true ; } else { return myInstance(proto, right); } }
快排 1、通过下表取排序区间的第0个数为基数
2、排序区间基数以后,从右往左,寻找比基数小的,从左往右,寻找比基数大的,原地交换;
3、重复步骤2直到 i >= j;
4、将基数与下标为 i 的元素原地交换,从而实现划分;
5、递归排序基数左边的数,递归排序基数右边的数,返回数组。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 var quickSort = function (ary, left, right ) { if (left >= right ) { return ary; } let i = left, j = right, base = ary[left]; while (i < j) { while (i<j && ary[j] >= base) { j--; } while (i<j && ary[i] <= base) { i++ } if (i<j) { var temp = ary[i]; ary[i] = ary[j]; ary[j] = temp; } } ary[left] = ary[i]; ary[i] = base; quickSort(ary, left, i-1 ); quickSort(ary, i+1 , right); return ary; }
两个有序数组的合并 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function sort1 (a,b ) { var i=0 ,j=0 ,k=0 ; var result=[] while (i<a.length&&j<b.length ) { if (a[i]<b[j] ) { result[k++]=a[i++]; }else { result[k++]=b[j++]; } } while (i<a.length ) { result[k++]=a[i++]; } while (j<b.length ) { result[k++]=b[j++] } return result };
爬楼梯 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 function Fibonacci (n ) { if (n==0 || n==1 ) return n; return Fibonacci(n-1 ) + Fibonacci(n-2 ); } function Fibonacci (n ) { let qian = 0 , hou = 1 ; if (n === 0 ) return 0 ; if (n === 1 ) return 1 ; for (let i = 2 ;i<=n; ++i ) { let x = qian +hou; qian = hou; hou = x; } return hou; }
判断单链表是否有环 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function judge (list ) { let fast = list.next.next, slow = list.next; while (list) { if (fast == slow) { return true ; } fast = fast.next.next; slow = slow.next; } return false ; }
有效括号 首先,我们创建一个数组,以存放与左括号配对的右括号。我们遍历括号字符串,判断该符号是否为左括号,如果是,就将其相应的右括号压入(push)结果数组中;如果不是,就将结果数组的值弹出(pop),看弹出的值是否和符号位相同,如果不同,就代表未正确配对。当括号字符串遍历完之后,我们根据结果数组是否为空就能确保代码运行正确。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var isValid = function (s ) { var rightSymbols = []; for (var i = 0 ; i < s.length; i++) { if (s[i] == "(" ){ rightSymbols.push(")" ); }else if (s[i] == "{" ) { rightSymbols.push("}" ); }else if (s[i] == "[" ) { rightSymbols.push("]" ); }else if (rightSymbols.pop() != s[i] ) { return false ; } } return !rightSymbols.length; };
LRU(最近最少使用) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class LRUCache { constructor (capacity ) { this .capacity = capacity this .map = new Map () } get (key ) { let val = this .map.get(key) if (typeof val === 'undefined' ) { return -1 } this .map.delete(key) this .map.set(key, val) return val } put (key, value ) { if (this .map.has(key)) { this .map.delete(key) } this .map.set(key, value) let keys = this .map.keys() while (this .map.size > this .capacity) { this .map.delete(keys.next().value) } } }
两个二叉树是否相等 1 2 3 4 5 6 7 8 9 10 11 function compareTree (root1, root2 ) { if (root1 == root2) return true ; if ((root1 == null && root2 != null ) || (root1 != null && root2 == null )) return false ; if (root1.value != root2.value) return false ; var leftBoolean = compareTree(root1.left, root2.left); var rightBoolean = compareTree(root1.right, root2.right); return leftBoolean && rightBoolean; }
二叉树的前序、中序、后序遍历 前序(根左右),中序(左根右),后序(左右根)。根据根 的位置来的
重建的时候根据根位置找到树的左子树和右子树,然后让左右子树继续根据根节点位置找的新的左右子树
后序dfs
1 2 3 4 5 var maxDepth = function (root ) { if (!root) return 0 ; return Math .max(maxDepth(root.left), maxDepth(root.right)) + 1 ; }
array.slice()留头不留尾
两个栈实现队列操作 入队操作
出队操作
将栈1的元素挪到栈2中
把栈2顶端的数据出栈即可
随后将栈2里的数据再挪到栈1里面(还原数据以方便后续入队)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 let arr1 = []let arr2 = []function push (node ) { arr1.push(node) } function pop ( ) { if (!arr2.length) { while (arr1.length ) { arr2.push(arr1.pop()) } } return arr2.pop() }
拖拽实现 实现思路:
鼠标按下开始拖拽
记录摁下鼠标时的鼠标位置以及元素位置
拖动鼠标记下当前鼠标的位置
鼠标当前位置-摁下时鼠标位置= 鼠标移动距离
元素位置= 鼠标移动距离+鼠标摁下时元素的位置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 class Drag { constructor (el ) { this .el = el; this .startOffset = {}; this .startPoint = {}; let move = (e ) => { this .move(e); }; let end = (e ) => { document .removeEventListener("mousemove" , move); document .removeEventListener("mouseup" , end); }; el.addEventListener("mousedown" , (e ) => { this .start(e); document .addEventListener("mousemove" , move); document .addEventListener("mouseup" , end); }) } start (e ) { let { el } = this ; this .startOffset = { x: el.offsetLeft, y: el.offsetTop } this .startPoint = { x: e.clientX, y: e.clientY } } move (e ) { let { el, startOffset, startPoint } = this ; let newPoint = { x: e.clientX, y: e.clientY } let dis = { x: newPoint.x - startPoint.x, y: newPoint.y - startPoint.y, } el.style.left = dis.x + startOffset.x + "px" ; el.style.top = dis.y + startOffset.y + "px" ; } } (function ( ) { let box = document .querySelector("#box" ); let dragbox = new Drag(box); })()
手写订阅发布 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Subject { observers = [] addObserver (observer ) { this .observers.push(observer) } removeObserver (observer ) { let index = this .observers.indexOf(observer) if (index > -1 ) { this .observers.splice(index, 1 ) } } notify ( ) { this .observers.forEach(observer => { observer.update() }) } } class Observer { update ( ) {} subscribeTo (subject ) { subject.addObserver(this ) } }
统计次数最多的三个节点 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 const allTag = [...document.getElementsByTagName('*' )]; console .log('所有的标签' , allTag); const allTagMap = allTag.map((item, index )=> { return (item.tagName) }); var obj = {}; allTagMap.map((item, index )=> { if (item in obj ) { obj[item]+=1 ; }else { obj[item]=1 ; } }); function sortTag (obj ) { return Object .keys(obj).sort((a,b )=> obj[b]-obj[a]); } var resultSortTag = sortTag(obj); var theFirstsThree = {}; for (var i = 0 ; i<3 ; i++ ) { var qian = resultSortTag[i]; theFirstsThree[qian] = obj[qian]; } console .log('前三个标签是:' , theFirstsThree);
柯里化函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function add (num ) { let sum=0 ; sum = sum+num; let tempFun=function (numB ) { if (arguments .length===0 ) { return sum; }else { sum= sum+ numB; return tempFun; } } return tempFun; } var result=add(2 )(3 )(4 )(5 )();
全排列 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 var a = [1 , 2 , 3 ];function swap (a, p, q ) { var t = a[p]; a[p] = a[q]; a[q] = t; } function pai (a, p, q ) { if (p == q) { console .log(a); } else { for (var i = p; i < q; i++) { swap(a, i, p); pai(a, p + 1 , q); swap(a, i, p); } } } pai(a, 0 , a.length);