手动封装一些方法

85 阅读3分钟

防抖

/*
	防抖的思路
		1.清理定时器生成新定时器最后输出了再清理定时 timer变为null
		2.direction控制头输出还是尾输出
*/

let btn = document.getElementsByClassName('btn')[0];
//防抖
const debounce = function debounce(fn, interval, direction) {
    //定时器初始化为null	之后有没有设置定时器就看 timer是不是null
    let timer = null;
    //参数类型错误判断
    if (typeof fn !== 'function') throw new TypeError(`fn is not function!!!`);
    if (typeof interval === 'boolean') direction = interval;
    if (typeof direction !== 'boolean') direction = false;
    if (typeof interval !== 'number') interval = 500;
    return function execute(...args) {
        //头输出标记
        let ishead = direction === true && timer === null;
        timer = mycleartimer(timer);
        timer = setTimeout(() => {
            //时间到了一定要清除定时器
            timer = mycleartimer(timer);
            //然后判断是否要输出
            if (!direction) {
                fn.call(this,...args);
                //如果direction 是true 这里不清理定时器头输出就只能用一次 因为timer!=null
            };
        }, interval)
        //头输出
        if (ishead) fn();
    }
}

const fn = function fn(e) {
    console.log(e,this)
}

//清除定时器
const mycleartimer = function mycleartimer(timer) {
    if (typeof timer !== 'null') {
        clearTimeout(timer);
        return null
    }
    return timer
}

btn.addEventListener("click", debounce(fn, 500, false));

节流

/*
	思路 1.remaining = wait - (now - previous) 这个remaining其实就是为了弥补第一次
			原因 :第一次点击不是立刻执行了吗小于500嘛
				  再点击timer为null生成定时器了   问题?	比如我第一次刚点立马执行 第二次点击在300ms 如果定时器设置wait就会
											  在800ms触发第二次,这样就不能实现500ms触发一次
											  所以我们需要remaining = wait - (now - previous)
											  	意思是 还差多少到500ms	所以给定时器设置remaining
				之后一直点remaining都是500 
		2.没超过就设置定时器
		
*/
let btn = document.getElementsByClassName('btn')[0];

const fn = function fn(){
	console.log(11)
}

// 清除定时器
const clearTimer = function clearTimer(timer){
	if(timer!=='null'){
		clearTimeout(timer);
		return null;
	}
	return timer;
}

const throttle = function throttle(fn,wait){
	let timer = null,
		previous = 0;
	return function operate(){
		let now = +new Date(),
		remaining = wait - (now - previous);
		if(remaining < 0){
            //第一次执行 (立即执行)
			timer = clearTimer(timer);
			fn();
			previous = +new Date();
		}else if(timer === null){
			timer = setTimeout(() => {
				timer = clearTimer(timer);
                previous = +new Date();
				fn();
                //用remaining不用wait就是为了弥补第一次
			},remaining)
		}
		
	}
}

btn.addEventListener("click", throttle(fn, 1000));

检测是否是一个函数

// 检测是否是一个函数
const isFunction = function isFunction(obj){
    return typeof obj ==='function'
}
console.log(isFunction(()=>{}));//=>true

检测是否是一个window对象

// 检测是否是一个window对象
var isWindow = function isWindow(obj) {
    // window.window===window
    return obj != null && obj === obj.window;
};

标准的检测数据类型的办法

/*
	正则表达式取出来
*/
let toType = function toType(obj){
    let reg = /^\[object ([a-zA-Z0-9]+)\]$/i;
    return reg.exec(({}).toString.call(obj))[1].toLowerCase()
}

console.log(toType(null));
console.log(toType(1));
console.log(toType({}));
console.log(toType(function (){}));

检测是否为数组或者类数组

const isArrayLike = function isArrayLike(obj){
    if(obj == null) {
        return false
    }
    return toType(obj) === "array" || toType(obj) === 'object' && obj.hasOwnProperty(length) && obj.hasOwnProperty(obj.length-1)
}

console.log(isArrayLike([]))

检测是否为纯粹的对象「直属类是Object || Object.create(null)」

var isPlainObject = function isPlainObject(obj){
    // 不是对象就直接false
    if(toType(obj) !== 'object') return false
    // 实例对象的__proto__为空   或者   实例对象的__proto__ 为 Object的原型对象都返回 true
    return !Object.getPrototypeOf(obj) || Object.getPrototypeOf(obj) === Object.prototype
}

检测是否是空对象

var isEmptyObject = function isEmptyObject(obj) {
    var keys = Object.keys(obj);
    if (typeof Symbol !== "undefined") keys = keys.concat(Object.getOwnPropertySymbols(obj));
    return keys.length === 0;
};

console.log(isEmptyObject({name:'yzl',age:18,[Symbol()]:'111'}))

检测是否为数组

//检测是否是数字
var isNumeric = function isNumeric(obj) {
    return toType(obj) === 'number' && !isNaN(obj)
}

深浅拷贝

/*
	思路 @1  deep标识的是是否是深浅拷贝	 i 标识循环 
		@2 	target标识拷贝到哪个目标上 然后i之后的对象参数都是要循环的
		@3 	如果需要拷贝的copy是一个对象 就让他去递归 递归完给target
		@4 	如果不是个对象就直接添加到targer上
*/
let merge = function merge() {
    let deep = false,
        target = arguments[0],
        i = 1,
        length = arguments.length;
    if (typeof target === 'boolean') {
        deep = target;
        target = arguments[i] || {};
        i++;
    }

    for (; i < length; i++) {
        for (name in arguments[i]) {
            let copy = arguments[i][name];
            if(/^(object||function)$/i.test(toType(copy)) && deep === true){
                // let clone = target[name];
                target[name] = merge(true,target[name],copy);
            }else if(copy != null){
                target[name] = copy
            }
        }
    }
    return target;
}

深浅克隆

/*
	思路 @1 target是要处理的东西
*/
const clone = function clone() {
    let target = arguments[0],
        deep = false,
        length = arguments.length,
        result = {};
    if (typeof target === 'boolean') {
        if (length == 1) return target;
        deep = true;
        target = arguments[1];
    }

    // 如果传的的null 和 undefined 就结束
    if (target == null) return target;
    if (/^(regexp|date|error)$/i.test(toType(target))) {
        if (toType(target) === 'error') target = target.message;
        let ctor = target.constructor;
        return new ctor(target);
    }
    // 处理对象	数组  函数
    for (key in target) {
        let copy = target[key];
        if (deep && toType(copy) === 'object' || toType(copy) === 'array' || toType(copy) === 'function') {
            result[key] = clone(deep, copy);
        } else {
            // 浅拷贝
            result[key] = copy
        }
    }
    return result;
}

let obj = {
    name: 'yzl',
    age: [1,2,3,{
        name:'sjl'
    }],
    arr:[1]
}
let obj2 = clone(obj);
obj.age[3].name = 'lll';
console.log(obj.age[3].name,obj2.age[3].name)	
console.log(obj.arr === obj2.arr)	//=>false
console.log(obj.fn === obj2.fn)		//=>false

数组去重

/*
	方法一 每一个遍历过去 相同的就删除
*/
let arr = [1,5,7,3,2,3,2];
~function () {
    const noRepetition = function noRepetition() {
        for (let i = 0; i < this.length; i++) {
            for (let j = i+1; j < this.length; j++) {
                if(this[i] === this[j]){
                    this.splice(j,1)
                }
            }
        }
        return this
    };

    ['noRepetition'].forEach((v, i) => {
        Array.prototype[v] = eval(v);
    })
}()

console.log(arr.noRepetition())

/*
	方法二 对象去重
*/
let arr = [1,5,7,3,2,3,2];
~function () {
    const noRepetition = function noRepetition() {
        // 对象去重
        let obj = {},newarr = [];
        for (const v of this) {
            obj[v] = 'd'
        }
        for (const key in obj) {
            newarr.push(key);
        }
        return newarr
    };

    ['noRepetition'].forEach((v, i) => {
        Array.prototype[v] = eval(v);
    })
}()

console.log(arr.noRepetition())