• 【js面试系列】手写常见js方法


    防抖

    function debounce(fn, delay) {
        var timer = null;
        return function(...arg) {
            clearTimeout(timer);
            timer = setTimeout(() => {
                fn.apply(this, arg);
            }, delay || 500);
        };
    }
    // 不断触发一个函数,在规定时间内只让最后一次生效,前面都不生效
    // 注意点:
    // 如何在vue中使用  https://zhuanlan.zhihu.com/p/72363385
    // 理解工作原理 this指向 参数 
    

    节流

    function throttle(fn, delay) {
        var timer = null;
        return function(...args) {
            if (!timer) {
                fn.apply(this, args);
                timer = setTimeout(function() {
                    timer=null
                }, delay || 500);
            }
        };
    }
    // 不断触发一个函数后,执行第一次,只有大于设定的执行周期后才会执行第二次
    // 防抖和节流的区别 应用场景
    
    // 函数防抖和函数节流都是防止某一时间频繁触发
    // 函数防抖是单位事件内 只执行最后一次触发的事件
    // 函数节流是单位时间间隔内 只执行一次触发事件
    
    // 比如:
    // LOL技能cd就是用的 节流,
    // 购物车提交订单就是用的 防抖
    

    深拷贝

    function deepClone(obj) {
        // 1.先判断是否为对象类型
        let isObject = (arg) => typeof arg === "object" && arg !== null
        // 2.如果不是,则返回本身
        if (!isObject(obj)) return obj;
        // 3.定义一个变量,判断是数组还是对象
        let cloneObj = Array.isArray(obj) ? [] : {};
        // 4.循环每一个元素,如果满足是自身属性,则每一个值再判断是否为对象类型,如果是则继续递归调用,否则返回本身
        for (let key in obj) {
            cloneObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key];
        }
        // 5.返回创建的变量值
        return cloneObj;
    }
    

    浅拷贝

    function shallowClone(obj) {
        if (typeof obj !== 'object' || obj === null) return obj
        // 3.定义一个变量,判断是数组还是对象
        let cloneObj = Array.isArray(obj) ? [] : {};
        // 4.循环每一个元素,
        for (let key in obj) {
            cloneObj[key] = obj[key]
        }
        // 5.返回创建的变量值
        return cloneObj;
    }
    

    new

    function _new(Fn, ...arg) {
        //基于fn的prototype构建对象的原型
        const thisObj = Object.create(Fn.prototype);
        //将thisObj作为fn的this,继承其属性,并获取返回结果为result
        const result = Fn.apply(thisObj, arg);
        //根据result对象的类型决定返回结果
        return result instanceof Object ? result : thisObj
    }
    

    call

    Function.prototype.myCall = function(obj, ...args) {
        // console.log(obj);
        // console.log(this);
        // if(obj==null||obj==undefined) obj=window //为空时,指向window
        const ctx=obj || window
        ctx.fn = this // this指向调用call的对象,即我们要改变this指向的函数
        return ctx.fn(...args) // 执行函数并return其执行结果
        delete ctx.fn  //删除该方法,不然会对传入的对象造成污染,添加了该方法
    }	
    

    apply

    Function.prototype.myApply = function(obj, args) {
        // console.log(obj);
        // console.log(this);
        // if(obj==null||obj==undefined) obj=window //为空时,指向window
        const ctx=obj || window
        ctx.fn = this // this指向调用call的对象,即我们要改变this指向的函数
        return ctx.fn(...args) // 执行函数并return其执行结果
        delete ctx.fn  //删除该方法,不然会对传入的对象造成污染,添加了该方法
    }	
    

    bind

    Function.prototype.myBind = function(thisArg, ...args) {
        var self = this //保存当前this,指的是当前fn调用者
        const fn = function(...fnArgs) {//提取调用时候的参数
            return self.apply(this instanceof self ? this : thisArg, [...args, ...fnArgs])
        }//且有返回值
        fn.prototype = this.prototype; //继承原型上的属性和方法
        return fn
    }
    // 输入:接受一个或者多个参数,第一个是要绑定的上下文,额外参数当作绑定函数的前置参数。
    // 输出:返回原函数的拷贝,即返回一个函数,这个函数呢具备原函数的功能
    

    instanceof

    // instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
    function myInstanceof(left, right) {
        // 左侧是实例对象
        // 右侧是某个构造函数
    
        if (typeof left !== 'object' || left === null) return false // 基本数据类型直接返回false
    
        let RP = right.prototype; // 构造函数的原型对象
        let LP = Object.getPrototypeOf(left) // 优先用这个方法 去查找实例对象的隐式原型对象
    
        while (true) {
            if (LP === null) return false;
            if (LP === RP) return true;
            LP = Object.getPrototypeOf(LP) // 沿着原型链重新赋值
        }
    }
    

    数组去重

    
    

    数组乱序

    
    

    继承

    
    

    睡眠函数(sleep)

    // 1
    function sleep (time) {
        return new Promise((resolve) => setTimeout(resolve, time));
    }
    
    // 2
    function sleep(delay) {
      var start = (new Date()).getTime();
      while ((new Date()).getTime() - start < delay) {
        continue;
      }
    }
    
    // (async function() {
    //   console.log('Do some thing, ' + new Date());
    //   await sleep(3000);
    //   console.log('Do other things, ' + new Date());
    // })();
    

    函数柯里化(Currying)

    /**
     * @description: 将函数柯里化的工具函数
     * @param {Function} fn 待柯里化的函数
     * @param {array} args 已经接收的参数列表
     * @return {Function}
     */
    const currying = function(fn, ...args) {
        // fn需要的参数个数
        const len = fn.length
        // 返回一个函数接收剩余参数
        return function (...params) {
            // 拼接已经接收和新接收的参数列表
            let _args = [...args, ...params]
            // 如果已经接收的参数个数还不够,继续返回一个新函数接收剩余参数
            if (_args.length < len) {
                return currying.call(this, fn, ..._args)
            }
          	// 参数全部接收完调用原函数
            return fn.apply(this, _args)
        }
    }
    

    数组扁平化(flat)

    let result = [];
    let fn = function(ary) {
        for(let i = 0; i < ary.length; i++) }{
            let item = ary[i];
            if (Array.isArray(ary[i])){
                fn(item);
            } else {
                result.push(item);
            }
        }
    }
    

    lazyMan

    
    

    filter

    
    

    jsonp

    function jsonp (url) {
        /*声明一个唯一的回调函数并挂载到全局上
       *创建一个script标签地址 指向 请求服务器 将回调函数名作参数带到服务器
       *服务器拿到回调名称 并返回前端 该回调的调用 把返回结果当作参数传入
       */
        let script = document.createElement('script')
        let uniqueName = `jsonpCallback${new Date().getTime()}`
        script.src = `url${url.indexOf('?') > -1 ? '&': '?'}callback=${uniqueName}`
        document.body.appendChild(script)
    
        window[uniqueName] = (res) => {
            cb && cb(res)
            document.body.removeChild(script)
            delete window[uniqueName]
        }
    }
    
    // 调用
    jsonp('getList', (res) => {
        console.log(res)
    })
    
    
    // 服务器端
    1. 获取参数, 拿到回调函数名称
    2. 返回参数名的前端回调的调用 并 把要返回的参数作为实参调用
    
    /*弊端 - 只支持get请求,并且不安全,需要服务器支持*/
    
    
    
    function jsonp ({url, query}) {
        let script = document.createElement("script");
        let cb = `jsonpCallBack${new Date().getTime()}${Math.floor(Math.random(5)*100000)}`
        let params = {...query, cb}
    
        let arr = []
        for (let key in params) {
            arr.push(`${key}=${params[key]}`)
        }
    
        script.src = `${url}?${arr.join("&")}`
        document.body.appendChild(script)
    
        return new Promise((resolve, rej) => {
            window[cb] = function (res) {
                resolve(res)
                document.body.removeChild(script)
                delete window[cb]
            }
        })
    }
    
    jsonp({
        url:'/getList',
        query: {name: 'ys',age: 19}
    }).then((res) => {
        console.log(res)
    })
    

    promise

    
    

    promise.all

    
    

    发布订阅(EventEmitter)

    
    
  • 相关阅读:
    ubuntu18.04安装g2o
    akka学习
    spark学习记录-2
    spark学习记录-1
    c++ string需要注意的地方
    clion server激活地址
    【转】c++面试基础
    c++反射概念-简单介绍
    死锁的理解
    c++ 反射类型
  • 原文地址:https://www.cnblogs.com/ycyc123/p/14823892.html
Copyright © 2020-2023  润新知