本篇文章旨在总结javascript的常用方法的实现,不定期积累更新,各路大神如有更加完美的实现,还望不吝赐教
1.事件代理
function delegateEvent(parentEle, childEle, type, fn){
if(parentEle.addEventListener){
parentEle.addEventListener(type, eventHandle, false);
}else if(parentEle.attachEvent){
parentEle.attachEvent('on' + type, eventHandle);
}else{
parentEle['on' + type] = eventHandle;
}
function eventHandle(e){
e = e || window.event;
const { target } = e;
if(matchEle(target, childEle) && fn){
fn.call(target, e);
}
}
function matchEle(target, childEle){
if(childEle.startWith('#')){
return target.id ==== childEle.slice(1);
}
if(childEle.startWith('.')){
return target.className && ~target.className.indexOf(childEle.slice(1))
}
return target.tagName.toLowerCase() === parentEle.toLowerCase();
}
}
2.防抖函数
任务超过一定的时间间隔才会触发,一般用于输入框实时检索
function debounce(delay = 500, fn){
let timer = Date.now();
return function(){
if(timer) clearTimeout(timer);
timer = setTimeout((args)=>{
fn.apply(this, args)
}, delay, [...arguments])
}
}
3.节流函数
任务在固定的时间内只能执行一次,一般用于scroll滚动,动画之类
function throttle(fn, delay = 500){
let canRun = true
return function(){
if(canRun){
canRun = false;
setTimeout((args)=>{
fn.apply(this, args);
canRun = true;
}, delay, [...arguments])
}
}
}
function throttle(fn, delay = 500){
let timer = Date.now()
return function(){
let current = Date.now();
if(current - timer > delay){
fn.apply(this, [...arguments]);
timer = current;
}
}
}
4. 对象数组深拷贝
function deepCopy(obj){
const result = Array.isArray(obj) ? [] : {};
for(let key in obj){
if(obj.hasOwnProperty(key)){
if(typeof obj[key] === 'object' && obj[key] !== null ){
result[key] = deepCopy(obj[key]);
}else{
result[key] = obj[key];
}
}
}
return result;
}
5.数组洗牌算法
function arrayShuffle(arr){
if(!Array.isArray(arr)){
throw new Error('arguments[1] must is array');
}
let m = arr.length;
while(m > 1){
const index = Math.floor(Math.random() * m--);
[arr[index], arr[m]] = [arr[m], arr[index]];
}
return arr;
}
// 概率抽奖
const proList = [
{prizeId: 1, probability:20},
{prizeId: 2, probability:50},
{prizeId: 3, probability:30}
]
function generalLotteryList(proList){
const arr = new Array(100);
let i = 0;
proList.forEach(item=>{
arr.fill(item.prizeId, i, i + item.probability);
i += item.probability;
})
return arrayShuffle(arr);
}
generalLotteryList(proList)
6.多维数组展开
function arrayFlat(arr) {
if (!Array.isArray(arr)) throw new Error('arguments[0] must is array');
let result = [];
for (let i = 0, len = arr.length; i < len; i++) {
result = result.concat(Array.isArray(arr[i]) ? arrayFlat(arr[i]) : arr[i])
}
return result;
}
function arrayFlat(arr){
return [].concat(...arr.map(e => {
return Array.isArray(e) ? arrayFlat(e) : e;
}))
}
function arrayFlat(arr) {
if (!Array.isArray(arr)) throw new Error('arguments[0] must is array');
return arr.reduce((result, val) => {
return result.concat(Array.isArray(val) ? arrayFlat(val) : val)
}, [])
}
function arrayFlat(arr, deep) {
if (!Array.isArray(arr)) throw new Error('arguments[0] must is array');
let result = [];
for (let i = 0, len = arr.length; i < len; i++) {
if (Array.isArray(arr[i]) && deep > 0) {
result = result.concat(arrayFlat(arr[i], deep - 1));
} else {
result.push(arr[i])
}
}
return result;
}
7.对象的深合并
注意区分与Object.assign区别,Object.assign不适合合并多层嵌套对象
function deepAssign(){
const result = {};
function assignValue(key, val){
if(typeof result[key] === 'object' && typeof val === 'object'){
result[key] = deepAssign(result[key], val);
}else{
result[key] = val;
}
}
for(let i=0;i<arguments.length; i++){
if(typeof arguments[i] !== 'object' || typeof arguments[i] === null) return;
for(let key in arguments[i]){
assignValue(key, arguments[i][key]);
}
}
return result;
}
8. 函数柯里化
function carry(fn, n) {
const result = (...allArgs) => allArgs.length === n ?
fn(...allArgs) : (...args) => result(...[...allArgs, ...args])
return result;
}
function f(a, b, c, d) {
console.log(a, b, c, d)
}
const r = carry(f, 4);
r(1, 2)(4, 3)
r(1, 2, 3)(4)
9.获取dom元素位置
function getTagPos(ele, result = [], resultStr = []){
if(!ele) return {
result:result.join('>'),
resultStr: resultStr.join('>')
};
let deep = 0, deepStr = [ele.tagName], current = ele.previousElementSibling;
while(current){
deep++;
deepStr.unshift(current.tagName);
current = current.previousElementSibling;
}
result.unshift(`${ele.tagName}:${deep}`);
resultStr.unshift(deepStr.join('|'));
return getTagPos(ele.parentElement, result, resultStr);
}
{
"result": "HTML:0>BODY:1>DIV:0>DIV:0>DIV:3>DIV:0",
"resultStr": "HTML>HEAD|BODY>DIV>DIV>DIV|DIV|DIV|DIV>DIV"
}
10. compose实现
实现一
function compose(...arrFn){
const len = arrFn.length;
if(len === 0) return args => args;
if(len === 1) return len[0];
return arrFn.reduce((a, b) => {
return (...args)=> a(b(...args))
})
}
function compose(...arrFn){
return (...args)=>{
return arrFn.reverse().reduce((a, b, c)=>{
return c === 0 ? b.apply(null, args) : b.call(null, a);
}, null)
}
}
实现二
function f1(num){
return num + 10;
}
function f2(num){
return num + 20;
}
function f3(num){
return num + 30;
}
function f4(num){
return num + 40;
}
console.log(compose(f4, f3, f2, f1)(4)) //104