常见的JS手写函数汇总(代码注释、持续更新)

最近在复习面试中常见的JS手写函数,顺便进行代码注释和总结,方便自己回顾也加深记,内容也会陆陆续续进行补充和改善。

一、手写深拷贝

    <script>
        const obj1 = {
            name: 'Leise',
            age: 23,
            address: {
                country: 'China',
                city: 'Guanzhou'
            }
        }
        const obj2 = deepClone(obj1)
        obj2.address.city = 'Hangzhou'
        console.log(obj1.address.city);
        console.log(obj2.address.city);
​
        function deepClone(obj) {
            //判断是否为非对象或者是null
            if (typeof obj !== 'object' || typeof pbj == null) {
                return obj
            }
            // 初始化拷贝结果
            let result
            // 判断是数组还是对象
            if (obj instanceof Array) {
                result = []
            } else {
                result = {}
            }
            for (let key in obj) {
             //保证key不是原型的属性
                if (obj.hasOwnProperty(key)) {
             //  递归调用深拷贝 防止多重嵌套
                    result[key] = deepClone(obj[key])
                }
            }
            // 最后返回结果 
            return result
        }
    </script>
​

 

二、手写bind函数

<script>
    Function.prototype.mybind = function () {
        //原型添加方法mybind
        const args = Array.prototype.slice.call(arguments)
        //将获得参数拆解成数组
        const t = args.shift()
        //获取this(数组第一项,同时剔除第一项,shift可以实现)
        const self = this
        //当前fn1.bind(...)中的fn1
        //console.log(this);
        //function fn1(a, b, c) {
        //console.log("this", this);
         //定义一个变量保留this指向
        //console.log(a, b, c);  }
        return function () {
            //console.log(this);window
            return self.apply(t, args)
            //这个函数需要执行
        }
    }
​
    function fn1(a, b, c) {
        console.log("this", this);
        console.log(a, b, c);
​
    }
    const fn2 = fn1.mybind({
        x: 1,
        y: 2
    }, 10, 20, )
    //bind之后需要执行
    const res = fn2()
    //保存运行后的结果并打印出来
    console.log(res);
</script>

 

三、手写通用事件绑定函数

<script>
    function bindEvent(elem, type, selcetor, fn) {
        //判断三个还是四个,四个则是事件代理
        if (fn == null) {
            fn = selcetor
            selcetor = null
        }
        //开始绑定事件
        elem.addEventListener(type, event => {
            const target = event.target
            //判断是事件代理还是普通绑定
            if (selector) {
                //事件代理
                if (target.matches(selcetor)) {
                    fn.call(target, event)
                } else {
                    fn.call(target.event)
                }
            }
​
        })
    }
​
    function bindEvent(elem, type, selector, fn) {
        // 三个参数和四个参数的判断处理
        if (fn == null) {
            fn = selector
            selector = null
        }
        elem.addEventListener(type, event => {
            const target = event.target
            if (selector) {
​
                // 有selector就是代理
if (target.matches(selector)) {
                    fn.call(target, event)
                }
            } else {
                fn.call(target, event)
            }
        })
    }
​
    const div3 = document.getElementById('div3')
    bindEvent(div3, 'click', 'a',
        function (event) {
            event.preventDefault()
            alert(this.innerHTML)
​
        })
</script>

 

四、手写闭包的简单应用

<script>
    function createCache() {
        // 闭包隐藏数据,只提供 API
        let obj = {}
        return {
            set: function (key, value) {
                obj[key] = value
            },
            get: function (key) {
                return obj[key]
            }
        }
    }
    const c = createCache()
    c.set('a', 100)
    console.log(c.get('a'))
    obj.d = 100 //undefined,必须使用get或者set
</script>

 

五、手写promise

    <script>
        function loadImg(url) {
            return new Promise((resolve, reject) => {
                const img = document.createElement('img')
                img.src = url
                img.onload = () => {
                    resolve(img)
                }
                img.onerror = () => {
                    reject(new Error("图片加载失败"))
                }
            })
        }
        const url1 = 'http://img.mukewang.com/5e5c85e1000116c505400720-156-88.jpg'
        const url2 = 'https://img.mukewang.com/szimg/5dba8cee0969880506000338.jpg'
        loadImg(url1).then((img1) => {
            console.log(img1.width);
            return img1
        }).then((img1) => {
            console.log(img1.height);
            return loadImg(url2)
        }).then(img2 => {
            console.log(img2.width);
        })
    </script>

 

六、手写Ajax

   <script>
        function ajax(url) {
            return new Promise((resolve, reject) => {
​
                //判断谷歌等还是IE
                let xhr
                if (window.XMLHttpRequest) { // code for IE7+, Firefox, Chrome, Opera, Safari
                    xhr = new XMLHttpRequest()
​
                } else { // code for IE6, IE5
                    xhr = new ActiveXObject("Microsoft.XMLHTTP")
                }
                // xhr 具有一个 open 方法,这个方法的作用类似于初始化,并不会发起真正的请求
                // open 方法具有 5 个参数,但是常用的是前 3 个
                // method: 请求方式 —— get / post
                // url:请求的地址
                // async:是否异步请求,默认为 true(异步)
                xhr.open("get", url, true)
                // send 方法发送请求,并接受一个可选参数
                // 当请求方式为 post 时,可以将请求体的参数传入
                // 当请求方式为 get 时,可以不传或传入 null
                // 不管是 get 还是 post,参数都需要通过 encodeURIComponent               编码后拼接
                xhr.send(null)
                //当readyStatus的状态发生改变时,会触发 xhr 的事件onreadystatechange
                xhr.onreadystatechange = () => {
                    //readyStatus: 请求/响应过程的当前活动阶段
                    if (xhr.readyState == 4) {
                    //HTTP 状态在 200-300 之间表示请求成功
                   // HTTP 状态为 304 表示请求内容未发生改变,可直接从缓存中读取
                        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
​
                            let obj = JSON.parse(xhr.responseText)
                            // console.log(obj)
                            // callBack(obj)
                            resolve(obj)
                        } else {
                            reject(new Error("错误"))
                        }
                    }
                }
            })
        }
        const url1 = "http://jsonplaceholder.typicode.com/users"
        const url2 = "/a.json"
        const url3 = "/b.json"
​
        ajax(url1).then(res => {
            console.log(res);
            return ajax(url2)
        }).then(res => {
            console.log(res);
            return ajax(url3)
        }).then(() => {
            console.log("ok");
        }).catch((res) => {
            console.log(res) //设置一个统一出口 如果出现错误就终止
        })
    </script>

 

七、手写防抖

   <script>
        const input1 = document.getElementById('input1')
​
        function debounce(fn, delay) {
            //timer必须在闭包中 才不会被外面修改
            let timer = null
            return function () {
                if (timer) {
                    clearTimeout(timer)
                }
                timer = setTimeout(() => {
                    fn.apply(this, arguments)
                    timer = null
                }, delay);
            }
        }
        input1.addEventListener('keyup', debounce(function () {
            console.log(input1.value);
        }, 500))
    </script>

 

八、手写节流

<script>
    function throttle(fn, delay) {
        let timer = null
        return function () {
            if (timer) {
                return
            }
            timer = setTimeout(() => {
                fn.apply(this, arguments)
                timer = null++
            }, delay);
        }
    }
    const one = document.getElementById('one')
    one.addEventListener('drag', throttle(function (e) {
        console.log(e.offsetX, e.offsetY);
    }, 1000))
</script>

 

 

posted @ 2020-09-09 00:58  Leise  阅读(693)  评论(0编辑  收藏  举报