自定义工具函数

1.函数柯里化

复制代码
function carry(func) {
    return function carried(...args) {
        if (args.length >= func.length) {
            return func.apply(this, args);
        } else {
            return function(...args2) {
                return carried.apply(this, args.concat(args2));
            }
        }
    }
}

function sum(a, b) {
    return a + b;
}
const _sum = carry(sum);
console.log(_sum(1, 2), _sum(1)(2));
复制代码

2.函数嵌套调用

复制代码
// 书写函数 compose 的实现,使得 compose(f,g,h)() 的输出结果是 1,3,5,6,4,2
function compose(...funcs) {
    // f(g(h(xx)))
    const _funcs = funcs.filter(f => typeof f === 'function');
    function next(funcs2) {
        if (funcs2.length === 1) {
            return funcs2[0].bind(this, (()=>{}));
        } else {
            const f = funcs2.shift();
            return f.bind(this, next(funcs2));
        }
    }
    return next(_funcs);
}

function f(next) { console.log(1); next(); console.log(2) }
function g(next) { console.log(3); next(); console.log(4) }
function h(next) { console.log(5); next(); console.log(6) }

compose(f,g,h)() 
复制代码

3.深拷贝实现

复制代码
const copied = new WeakMap();
function deepClone(obj) {
    if (obj === null || typeof obj !== 'object') {
        return obj;
    }
    if (copied.has(obj)) {
        // 如果已经拷贝过,则返回之前拷贝的对象引用
        return copied.get(obj);
    }
    const cloneObj = {};
    cloneObj.__proto__ = obj.__proto__;
    copied.set(obj, cloneObj);
    // 遍历keys
    const keys = Reflect.ownKeys(obj);
    for(let i = 0; i < keys.length; i++) {
        const value = obj[keys[i]];
        if (value instanceof Object) {
            if (typeof value === 'function') {
                cloneObj[keys[i]] = value.bind(cloneObj);
            } else if (value instanceof Date) {
                cloneObj[keys[i]] = new Date(value.valueOf());
            } else if (value instanceof RegExp) {
                cloneObj[keys[i]] = new RegExp(value.valueOf());
            } else if (value instanceof String) {
                cloneObj[keys[i]] = new String(value.valueOf());
            } else if (value instanceof Boolean) {
                cloneObj[keys[i]] = new Boolean(value.valueOf());
            } else if (value instanceof Number) {
                cloneObj[keys[i]] = new Number(value.valueOf());
            } else {
                cloneObj[keys[i]] = deepClone(value);
            }
        } else {
            cloneObj[keys[i]] = value;
        }
    }
    return cloneObj;
} 
复制代码

4.其他工具函数

复制代码
/**
 * @pram element 必传,要获取样式的元素
 * @pram attribute 必传,要获取的样式属性
 * @pram pseudo_elements 可选,默认值null,要获取样式的元素的伪元素,ie8及以下浏览器不生效
 * */
function getStyle(element, attribute, pseudo_elements = null){
    return window.getComputedStyle ?
        getComputedStyle(element,pseudo_elements)[attribute] : //ie9及以上的浏览器
        element.currentStyle[attribute]; //ie支持
}

/**
 * @pram element 要绑定拖拽事件的元素
 * */
function bindDrag(element){
    element.onmousedown = (e)=>{
        //如果支持setCapture则调用setCapture,来让element拦截并执行浏览器中所有的事件 ie8及以下浏览器拦截默认事件的解决方案
        element.setCapture && element.setCapture()
        e = e || window.event
        //鼠标相对于元素的位置
        let left = e.clientX -  e.target.offsetLeft
        let top = e.clientY -  e.target.offsetTop
        //为元素开启绝对定位方便移动
        element.style.position = 'absolute'
        //当鼠标按下时,给页面绑定onmousemove事件
        document.onmousemove = (event)=>{
            //获取鼠标移动事件对象
            event = event || window.event
            //当鼠标移动时,被拖拽元素跟着鼠标移动
            //设置元素的水平偏移量
            element.style.left = event.clientX - left + (document.scrollLeft||0) + 'px'
            //设置元素的垂直偏移量
            element.style.top = event.clientY - top + (document.scrollTop||0) + 'px'
        };
        //当鼠标按下时,给页面绑定onmouseup事件
        document.onmouseup = (event)=>{
            //获取鼠标移动事件对象
            event = event || window.event
            //固定元素位置
            //设置元素的水平偏移量
            element.style.left = event.clientX - left + (document.scrollLeft||0) + 'px'
            //设置元素的垂直偏移量
            element.style.top = event.clientY - top +( document.scrollTop||0) + 'px'
            //当鼠标抬起时,解绑页面的onmousemove事件和onmouseup事件
            document.onmouseup = document.onmousemove = null
            //如果支持releaseCapture则调用releaseCapture,来让element取消拦截
            element.releaseCapture && element.releaseCapture()
        };
        //拦截浏览器的默认行为,对ie8及以下不生效
        return false;
    };
}

/**
 * @pram element 要绑定拖拽事件的元素
 * @pram downCallback 点击之后的回调函数
 * @pram moveCallback 移动过程中的回调函数
 * @pram upCallback 释放鼠标之后的回调函数
 * */
function bindDragExpand(element,downCallback,moveCallback,upCallback){
    element.onmousedown = (e)=>{
        //如果支持setCapture则调用setCapture,来让element拦截并执行浏览器中所有的事件 ie8及以下浏览器拦截默认事件的解决方案
        element.setCapture && element.setCapture();
        e = e || window.event;
        //是否有指定按下时的回调,若有则将e作为参数传递过去并执行,并接收返回值
        let downResult = null 
        if(downCallback) downResult = downCallback(e)
        let moveResult = null
        //当鼠标按下时,给页面绑定onmousemove事件
        document.onmousemove = (event)=>{
            //获取鼠标移动事件对象
            event = event || window.event;
            //将event、moveResult、downResult作为参数传递给moveCallback,并接收返回值
            if(moveCallback) moveResult =  moveCallback(e,event,moveResult,downResult)
        };
        //当鼠标按下时,给页面绑定onmouseup事件
        document.onmouseup = (event)=>{
            //获取鼠标移动事件对象
            event = event || window.event;
            //将event、moveResult、downResult作为参数传递给upCallback,并接收返回值
            upCallback && upCallback(e,event,moveResult,downResult)
            //当鼠标抬起时,解绑页面的onmousemove事件,并固定元素位置
            document.onmouseup = document.onmousemove = null;
            //如果支持releaseCapture则调用releaseCapture,来让element取消拦截
            element.releaseCapture && element.releaseCapture();
        };
        //拦截浏览器的默认行为,对ie8及以下不生效
        return false;
    };
}
/**
 * @pram element  必传,要绑定事件的对象
 * @pram eventName  必传,要绑定的事件名,如click、keyup、mousemove...
 * @pram callback   必传,响应函数
 * @pram isCapture  可选,是否在捕获阶段触发事件,默认值为false,ie8及以下浏览器不生效
 * */
function bind(element,eventName,callback,isCapture = false){
    if(element.addEventListener){
        element.addEventListener(eventName, callback, isCapture);
        if(eventName === 'mousewheel') element.addEventListener('DOMMouseScroll', callback, isCapture);
    }
    else element.attachEvent('on'+eventName, () => callback.call(element));
}

/**
 * @pram element   要执行动画的元素
 * @pram attribute 要变化的属性
 * @pram target    要变化属性的目标值,属性值从当前值变化到目标值
 * @pram speed     属性值变化的速度
 * @pram callback  回调函数,动画执行完毕后执行
 * 只有值的单位是px的属性可用
 * */
function animate(element,attribute = 'left',target,speed = 10,callback = null){
    clearInterval(element.timer);
    let current = parseInt(getStyle(element,attribute));
    if(current>target) speed *= -1; //在目标右侧
    //开启定时器
    element.timer = setInterval(()=>{
        let value = parseInt(getStyle(element,attribute)) + speed;
        if(value < target && speed<0 || value>target && speed>0) value = target;
        element.style[attribute] = value + 'px';
        if(value === target){
            clearInterval(element.timer);
            callback && callback.call(element);
        }
    },16);
}


/**
 * 格式化类:删除多余的空格
 * @pram element 要格式化类的元素
 * */
function formatClass(element){
    //去掉多余的空格
    element.className = element.className.trim().split(' ').filter((item)=>{
        return item.length > 0;
    }).join(' ');
}
/**
 * 查找元素是否含有指定的一些类,返回返回含有的和含有的类
 * @pram element 要查找类的元素
 * @pram classArr 要查找的类
 * */
function queryClass(element,...classArr){
    formatClass(element);
    //定义返回值
    const result = {
        include:[],
        not:[]
    }
    //遍历
    classArr.forEach((item)=>{
        let reg = new RegExp('\\b'+item+'\\b');
        if(reg.test(element.className)) result.include.push(item);
        else result.not.push(item);
    });
    return result;
}
/**
 * 为元素添加指定的一些类,返回添加成功和添加失败的类
 * @pram element 要添加类的元素
 * @pram classArr 要添加的类
 * */
function addClass(element,...classArr){
    const query = queryClass(element,...classArr);
    //定义返回值
    const result = {
        failed:[...query.include],
        succeeded:[...query.not]
    }
    //添加可以添加的类
    element.className += ' ' + result.succeeded.join(' ');
    return result;
}
/**
 * 删除元素指定的一些类,返回删除成功和删除失败的类
 * @pram element 要删除类的元素
 * @pram classArr 要删除的类
 * */
function removeClass(element,...classArr){
    //定义返回值
    const result = {
        failed:[],
        succeeded:[]
    }
    //遍历
    classArr.forEach((item)=>{
        let reg = new RegExp('\\b'+item+'\\b');
        if(reg.test(element.className)) {
            result.succeeded.push(item);
            element.className = element.className.replace(reg, '');
        }
        else result.failed.push(item);
    });
    formatClass(element);
    return result;
}
/**
 * 切换元素指定的一些类,返回切换成功和切换失败的类
 * 切换:如果含有该类,则删除;如果不含该类则添加
 * @pram element 要切换类的元素
 * @pram classArr 要切换的类
 * */
function toggleClass(element,...classArr){
    //定义返回值
    const result = {
        add:[],
        remove:[]
    }
    classArr.forEach((item)=>{
        let reg = new RegExp('\\b'+item+'\\b');
        if(reg.test(element.className)) {
            result.remove.push(item);
            element.className = element.className.replace(reg, '');
        }
        else result.add.push(item);
    });
    formatClass(element);
    element.className += ' ' + result.add.join(' ');
    return result;
}

/**
 * 传入一些数据,返回这些数据的数据类型数组,不传则返回空数组
 * @pram data :需要判断数据类型的数据,可以传多个
 * */
function getDataType(...data){
    const result = []
    data.forEach((item)=>{
        if(typeof item === 'object'){
            if( item === null) result.push('null')
            else if(item instanceof Array) result.push('array')
            else result.push('object')
        }
        else result.push(typeof item)
    })
    return result
}

/**
 * 获取传入的画笔对象的画布区域或ImageData区域的点(x,y)的颜色信息
 * @pram object 画笔对象或ImageData对象
 * @pram x 要获取的像素点的横轴坐标
 * @pram y 要获取的像素点的纵轴坐标
 * */
function getPxInfo(object,x,y){
    let imageData
    if(object.getImageData){//传入的是画笔
        imageData = object.getImageData(0,0,object.canvas.width,object.canvas.height)
    }
    else if(object.width && object.height && object.data){//传入的是ImageData对象
        imageData = object
    }
    else {//传入的是非法对象
        console.error('传入的object既不是画笔对象也不是ImageData对象!')
        return []
    }
    let {width,height,data} = imageData
    if(height<y){
        console.error('要获取的像素点不在指定区域!')
        return []
    }
    return [
        data[4*(y*width+x)],
        data[4*(y*width+x)+1],
        data[4*(y*width+x)+2],
        data[4*(y*width+x)+3]
    ]
}
/**
 * 设置画布区域的ImageData对象的点(x,y)的颜色为color,设置成功返回true,设置失败返回false
 * @pram ImageData 要设置像素点的区域,默认为null,如不传则默认该区域为整个画笔区域
 * @pram x 要设置的像素点的横轴坐标
 * @pram y 要设置的像素点的纵轴坐标
 * @pram color 要设置的像素点的颜色,默认为黑色不透明
 * */
function setImageDataPxInfo(imageData,x,y,color = [0,0,0,255]){
    if(!(imageData.width && imageData.height && imageData.data)){//传入的不是ImageData对象
        console.error('传入的imageData对象不是ImageData对象!')
        return false
    }
    let {width,height} = imageData
    if(height<=y||width<=x){
        console.error('要设置的像素点不在指定区域!')
        return false
    }
    for (let i = 0; i < 4; i++) imageData.data[4*(y*width+x)+i] = color[i]
    return true
}
/**
 * 设置传入的ctx或ImageData区域的点(x,y)的颜色信息,设置成功返回true,设置失败返回false
 * @pram ctx 画笔对象
 * @pram x 要设置的像素点的横轴坐标,默认为0
 * @pram y 要设置的像素点的纵轴坐标,默认为0
 * @pram color 要设置的像素点的颜色,默认为黑色不透明
 * @pram ImageData 要设置像素点的区域,默认为null,如不传则默认该区域为整个画笔区域
 * @pram x0 设置后区域的放置起始点的横轴坐标,默认为0
 * @pram y0 设置后区域的放置起始点的纵轴坐标,默认为0
 * */
function setPxInfo(ctx,x = 0,y = 0,color = [0,0,0,255],imageData = null,x0 = 0,y0 = 0){
    if(!ctx.canvas) {
        console.error('传入的ctx不是画笔对象!')
        return false
    }
    if(!imageData){
        imageData = ctx.getImageData(0,0,ctx.canvas.width,ctx.canvas.height)
    }
    else if(!(imageData.width && imageData.height && imageData.data)){//传入的不是ImageData对象
        console.warn('传入的imageData对象不是ImageData对象!')
    }
    else if(!(x0<ctx.canvas.width&&y0<ctx.canvas.height)){
        console.warn('传入的起始位置错误!')
    }
    let {width,height} = imageData
    if(height<=y){
        console.error('要设置的像素点不在指定区域!')
        return false
    }
    //检查color格式是否正确
    if(!(color instanceof Array)){//不是数组
        console.error('传入的color不是数组!')
        return false
    }
    else{
        for (let i = 0; i < 4; i++) {
            if(!(typeof color[i] === 'number')||color[i]>255||color[i]<0){
                console.warn(`color[${i}]的数据格式不对,已被重置为0!`)
                color[i] = 0

            }
            imageData.data[4*(y*width+x)+i] = color[i]
        }
        if(color.length>4){
            console.warn(`‘color’数组的数据只有前面四个有效!`)
        }
    }
    ctx.putImageData(imageData,x0,y0)
    return true
}


/**
 * 给指定的画布区域打上马赛克
 * @pram ctx 画笔对象
 * @pram x 打码起始点的横轴坐标
 * @pram y 打码起始点的纵轴坐标
 * @pram width 打码区域的宽度
 * @pram height 打码区域的高度
 * @pram grade 模糊程度,默认为10
 * */
function addMosaic(ctx,x,y,width,height,grade = 10){
    let imageData = ctx.getImageData(x,y,width,height)
    for (let i = 0; i < Math.ceil(width / grade); i++) {
        for (let j = 0; j < Math.ceil(height / grade); j++) {
            let limit = [
                grade*i + grade > width ? width - grade*i : grade,
                grade*j + grade > height ? height - grade*j : grade
            ]
            let random1 = Math.floor(Math.random()*limit[0])
            let random2 = Math.floor(Math.random()*limit[1])
            let color = getPxInfo(imageData,i*grade+random1,j*grade+random2)
            for (let k = 0; k < limit[0] ; k++) {
                for (let l = 0; l < limit[1]; l++) {
                    setImageDataPxInfo(imageData,i*grade+k,j*grade+l,color)
                }
            }
        }
    }
    ctx.putImageData(imageData,0,0)
}
//打码动画函数,time为每个码的时间
function addMosaicAnimation(ctx,x,y,width,height,grade = 10,time){
    let j = 0,i = 0,flag = 1
    setInterval(()=>{
        if(!(i < Math.ceil(height / grade))||i<0) {
            flag*=-1
            j++
        }
        if(!(j < Math.ceil(width / grade))) return
        let limit = [
            grade*i + grade > width ? width - grade*i : grade,
            grade*j + grade > height ? height - grade*j : grade
        ]
        let random1 = Math.floor(Math.random()*limit[0])
        let random2 = Math.floor(Math.random()*limit[1])
        let imageData = ctx.getImageData(i*limit[0],j*limit[1],limit[0],limit[1])
        let color = getPxInfo(imageData,random1,random2)
        for (let k = 0; k < limit[0] ; k++) {
            for (let l = 0; l < limit[1]; l++) {
                setPxInfo(ctx,k,l,color,imageData,i*limit[0],j*limit[1])
            }
        }
        i+=flag
    },time)
}
/**
 * 计算两个日期之间的天数
 * @param dateString1  开始日期 yyyy-MM-dd
 * @param dateString2  结束日期 yyyy-MM-dd
 * @returns {number} 如果日期相同 返回一天 开始日期大于结束日期,返回0
 */
function getDaysBetween(dateString1,dateString2){
    var  startDate = Date.parse(dateString1);
    var  endDate = Date.parse(dateString2);
    if (startDate>endDate){
        return 0;
    }
    if (startDate==endDate){
        return 1;
    }
    var days=(endDate - startDate)/(1*24*60*60*1000);
    return  days;
}
复制代码

 

本文作者:何以之

本文链接:https://www.cnblogs.com/serendipity-echo/articles/18668611

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   何以之  阅读(2)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起
  1. 1 残酷游戏 卫兰
  2. 2 明知做戏 吴雨霏
  3. 3 你,好不好? 周兴哲
  4. 4 我可以 蔡旻佑
  5. 5 云烟成雨 房东的猫
  6. 6 说散就散 JC 陈咏桐
  7. 7 我配不上你 夏天Alex
  8. 8 不再联系 夏天Alex
  9. 9 等我先说 夏天Alex
  10. 10 我知道他爱你 夏天Alex
  11. 11 多想在平庸的生活拥抱你 隔壁老樊
  12. 12 这一生关于你的风景 隔壁老樊
  13. 13 我曾 隔壁老樊
  14. 14 关于孤独我想说的话 隔壁老樊
  15. 15 过客 周思涵
  16. 16 备爱 周思涵
  17. 17 嚣张 en
  18. 18 海口 后弦
明知做戏 - 吴雨霏
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

作词 : 夏至(蔡冕丽)

作曲 : 方文良

编曲 : 吴国恩

等你的汽水喝一半给你加片薄冰

等你的桌面满泄我总会打理重整

不想纯情

不够聪明

你未发现我的身影

得我帮你依照编码整理家里电影

只会得我一个帮你选购喜爱铃声

天天如常

估你心情

等一个眼神求证

一闪擦过如流星

怎么我为我做过的感到惊怕

就像爱吗我也不肯定恐怕

我以为存在吗

千变万化

从来不肯开口可相信吗

离谱吗

请你不要阻我喜欢你

明明是爱但你未说话你扮作闪避

这个沉默冷静的你亳无办法处理

其实我亦怕是错摸心理

总有天会等到好天气

游行示爱大叫着你在某大遍草地

等你无用退避不过仍然害羞的你

还是顾忌太不争气

明知做戏

即使你未太在意不感到惊讶

现在要说爱你请准备招架

勇气还存在吗

不要害怕

随时真的胆敢亲手送花

离谱吗

请你不要阻我喜欢你

明明是爱但你未说话你扮作闪避

这个沉默冷静的你亳无办法处理

其实我亦怕是错摸心理

总有天会等到好天气

游行示爱大叫着你在某大遍草地

等你无用退避不过仍然害羞的你

还是顾忌太不争气

明知做戏

不过不要阻我紧张你

如何令你愉快让我办妥为你准备

喜爱沉默冷静的你还是自信的你

仍愿意为你造一些惊喜

总有天会等到好天气

游行示爱大叫着你在某大遍草地

等你无用退避不过途人目光不理

期待贴着你的手臂

无须做戏

等你喜爱等你不爱就凭摘毫验证

想爱不爱偏爱不理亦同样难划清

天天如常

估你心情

不想扑索来求证

争取过趁还年青

终于你下决定来答应

太动听