前端部分重要知识和方法

117 阅读3分钟

手写 indexOf

     function () {
        // 在函数前加上波浪号,其作用是把函数声明转换为表达式,
        // 就可以直接将下面的代码放入某个函数里运行。
        // 不用indexOf 和 includes

        function myIndexOf(a) {
            // 1、 这个也可以正则实现 下面代码
            // let reg = new RegExp(a)
            // res = reg.exec(this)
            // return res === nu ll ? -1 : res.index
            // 这个也可以正则实现

            let lena = a.length
            y = this.length
            flag = -1
            if (lena > y) return -1
            // 如果输入的字符串大于要检测的字符串直接 -1
            for (var i = 0; i <= y - lena; i++) {
                if (this.substr(i, lena) === a) {
                    // substr() 方法可在字符串中抽取从 start 下标开始的指定数目的字符。
                    flag = i
                    break
                }
            }
            return flag
        }
        String.prototype.myIndexOf = myIndexOf
    }()
    let demo = 'dwanlghMappaw'
    let str = 'h'
    console.log(demo.myIndexOf(str));

手写 instanceof

    // instanceof
    // 1、只要当前类出现在实例的原型上,结果都为 true 
    // 2、由于我们可以肆意的修改原型的指向,所以检测出来的结果是不准确的
    // 3、不能检测基本数据类型

    var arr = []
    console.log(arr);
    function instance_of(example, classFunc) {    // 实例.__proto__ === 类.prototype   => instanceof
        let classFuncPrototype = classFunc.prototype // 这个就代表类的原型
        proto = Object.getPrototypeOf(example) // example.__proto__    实例的.__proto__
        while (true) {  // 我也不知道你要找多少次  while循环
            if (proto === null) { // 找到最顶层为null就说明没找到 返回 false
                return false
            }
            if (proto === classFuncPrototype) {
                return true
            }
            proto = Object.getPrototypeOf(proto)
        }
    }
    console.log(instance_of(arr, Array));
    console.log(instance_of(arr, Object));
    console.log(instance_of(arr, RegExp));

手写call方法

    // 给function的原型上面添加一个 _call 方法
    Function.prototype._call = function (context) {
        //  判断调用者是否是一个函数  this 就是调用者
        if (typeof this != 'function') {
            return
        }
        // 如果有 context 传参就是传参者 没有就是window
        that = context || window
        // 保存当前调用的函数
        that.fn = this   // 吧 this == fns   存到that.fn来
        // 截取传过来的参数
        /*
          arguments
                 a: 1
                 fn: ƒ fns()
        */
        // 通过 slice 来截取传过来的参数
        const local = [...arguments].slice(1)
        // 传入参数调用函数
        let result = that.fn(...local)
        // 删出 fn 属性
        delete that.fn
        return result
    }

    let obj = { a: 1 }
    function fns(a, b) {
        console.log(a, b);
        console.log(this)
    }
    fns._call(obj, 23, 555)

手写apply

    Function.prototype.myApply = function (context) {
        if (typeof this !== 'function') {
            // 判断当前调用者是否为函数
            return
        }
        // 保存传入的this指向
        that = context || window
        // 保存当前调用的函数
        that.fn = this
        let result
        // 这里开始判断传入的参数是否存在,此时参数是一个数组形式[thisArg,[传参]]
        // 那么如果arguments[1]即传参存在的时候,就是需要传参调用保存的函数
        // 如果不存在就直接调用函数
        if (arguments[1]) {
            result = that.fn(...arguments[1])
        } else {
            result = that.fn()
        }
        return result
    }

    let obj = {
        a: 1
    }

    function fn(...val) {
        console.log(this)
        console.log(...val)
    }
    fn.apply(obj, [1, 4, 5, 6, 7, 9])

手写 bind

    Function.prototype._bind = function (context) {
        // 当调用用了_bind 函数  this 指向调用 _bind 的那个函数
        // this 不是 function 不让使用 抛出类型错误
        if (typeof this != 'function') {
            throw new TypeError('Error')
        }
        // 获取参数 除了传过来的第一项我全都要
        const args = [...arguments].slice(1)
        // 吧 function 进行一个缓存
        fn = this

        // 返回一个函数 因为 bind 不是立即调用的
        return function Fn() {
            // 判断  this 原型链上是否又该类型的原型 Fn
            return fn.apply(this instanceof Fn ? new fn(...arguments) : context, args.concat(...arguments))
        }

    }

    let obj = {
        a: 1
    }

    function fn(...val) {
        console.log(this)               // obj
        console.log(...val)   // 231, 31242344, 432
    }
    fn._bind(obj, 231, 31242344, 432)()

简易版Promise.all

    function PromiseAll(promiseArray) {    //返回一个Promise对象
        return new Promise((resolve, reject) => {
            if (!Array.isArray(promiseArray)) {                        //传入的参数是否为数组
                return reject(new Error('传入的参数不是数组!'))
            }
            const res = []
            let counter = 0                         //设置一个计数器
            for (let i = 0; i < promiseArray.length; i++) {
                Promise.resolve(promiseArray[i]).then(value => {
                    counter++                  //使用计数器返回 必须使用counter
                    res[i] = value
                    if (counter === promiseArray.length) {
                        resolve(res)
                    }
                }).catch(e => reject(e))
            }
        })
    }

    const s1 = new Promise((res, rej) => {
        setTimeout(() => {
            res('p1')
        }, 1000)
    })
    const s2 = new Promise((res, rej) => {
        setTimeout(() => {
            res('p2')
        }, 2000)
    })
    const s3 = new Promise((res, rej) => {
        setTimeout(() => {
            res('p3')
        }, 3000)
    })
    const test = PromiseAll([s1,s2, s3])
        .then(res => console.log(res))
        .catch(e => console.log(e))

    console.log(test);

数字千位分割

const format = (n) => {
        let num = n.toString() // 拿到传进来的 number 数字 进行 toString
        let len = num.length // 在拿到字符串的长度
        // 当传进来的结果小于 3 也就是 千位还把结果返回出去 小于3 不足以分割
        if (len < 3) {
            return num
        } else {
            let render = len % 3 //传入 number 的长度 是否能被 3 整除
            console.log(render)
            /*
            match() 方法可在字符串内检索指定的值,或找到一个或多个正则表达式的匹配。
            该方法类似 indexOf() 和 lastIndexOf(),但是它返回指定的值,而不是字符串的位置。
            var str = '123123000'
            str.match(/\w{3}/g).join(',') // 123,123,000
            */
            if (render > 0) { // 说明不是3的整数倍
                return num.slice(0, render) + ',' + num.slice(render, len).match(/\d{3}/g).join(',')
            } else {
                return num.slice(0, len).match(/\d{3}/g).join(',')
            }
        }
    }

    let str = format(298000)
    console.log(str)

防抖

<body>
    防抖: <input id="input" type="text">
</body>
<script>
    // 监听拿到input输入的值
    input.addEventListener('input', function (e) {
        val(e.target.value)
    })
    // 防抖的核心代码
    function fn(time, fun) {
        let flag // 定义状态
        return function (value) {
            clearTimeout(flag)// 在执行之前 清除 定时器的 flag 不让他执行
            flag = setTimeout(() => {
                fun(value)
            }, time)
        }
    }
    let val = fn(1000, function (val) {
        console.log(val)
    })
</script>

节流

<body>
    <button id="button">手在快1秒执行一次</button>
</body>
<script>
    /*
        定时器版本的
          fns 回调函数
          time 间隔时间
        function throttle(fns, time) {
        let flag // 定义一个空状态
        return function () { // 内部函数访问外部函数形成闭包
            if (!flag) { // 状态为空执行
                flag = setTimeout(() => {
                    fns.apply(this, arguments) // 改变this指向 吧 event 事件对象传出去
                    flag = null
                }, time)
            }
        }
       }
    */

    function throttle(fun, time) {
        let flag = 0
        return function () {
            let now = +new Date().valueOf()
            // 当前的值 减去上一次的值 >= 传过来的事件 执行
            if (now - flag >= time) {
                fun.apply(this, arguments)
                flag = now
            }
        }
    }
    
    button.onclick = throttle((e) => {
        console.log(e)
    }, 1000)
</script>