跳至主要內容
WeakMap与Map的区别

WeakMap与Map的区别

WeakMap

  1. key必须是对象
  2. key是弱引用
弱引用与强引用
  • 弱引用:不会影响垃圾回收机制。即: WeakMap 的 key 不再存在任何引用时,会被直接回收。

  • 强引用:会影响垃圾回收机制。存在强应用的对象永远不会被回收。

对比示例

<script>

    let obj1 = {
        name: '张三'
    }
    let obj2 = {
        name: '张三'
    }

    // 强引用
    const map = new Map()
    // 弱引用
    const weakMap = new WeakMap()
    map.set(obj1,'value')
    weakMap.set(obj2,'value')

    obj1 = null
    obj2 = null

    console.log('map',map) // Map(1) {{…} => 'value'}
    console.log('weakMap',weakMap) // WeakMap {} 空
    
    /**
    此时 WeakMap 中不存在任何值,即: obj2不存在其他引用时, WeakMap 不会阻止垃圾回收,基于obj2的引用将会被清除。这就证明了 WeakMap 的 弱引用特性。
    */
</script>

yyshino小于 1 分钟FrontEndJS
手写reduce

MDN参考

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce

语法

reduce(callbackFn)
reduce(callbackFn, initialValue)

yyshino大约 2 分钟FrontEndJS手写系列
手写call、apply、bind

手写call、apply、bind

总结

  • 三者都可以改变函数的this对象指向
  • 三者第一个参数都是this要指向的对象,如果如果没有这个参数或参数为undefinednull,则默认指向全局window
  • 三者都可以传参,但是apply是数组,而call是参数列表,且applycall是一次性传入参数,而bind可以分为多次传入
  • bind是返回绑定this之后的函数,applycall 则是立即执行

yyshino大约 2 分钟FrontEndJS手写系列
并发请求
    /**
     * 在某些场景下,页面的请求数可能会有很多,
     * 比如:抓取、分片上传等,如果我们需要等一个请求完成后,
     * 再发起下一个请求,是必效率会比较低。
     * 为了提升效率,我们可以同时发出多个请求,但数量又不能太多,
     * 如若某请求完成,剩余等待的请求继续补位执行,
     * 将请求的结果(不论成功或失败),按原有数组的顺序返回。
     */

    /**
     * 11-并发事件
     * @param {string[]} urls 请求地址数组
     * @param {number} max 最大并发数
     */
    function consurRequest(urls, max) {
        return new Promise((resolve,reject) => {
            // 判断传入urls长度,为空直接返回[]
            if(urls.length === 0){
                resolve([])
                return
            }

            const results = []
            let count = 0 // 标识请求的完成数量
            let index = 0 // 下一个请求

            // 发送请求
            async function request(){
                // 退出逻辑
                if(index === urls.length){
                    return
                }

                // 存储 index,保持后续请求结果数组与urls数组对应
                const i = index
                const url = urls[index]
                index++
                try {
                    const resp = await fetch(url)
                    // resp加入到 results中
                    results[i] = resp
                } catch (err) {
                    // err 加入到results
                    results[i] = err
                    console.log('err',err)
                } finally {
                    // 判断是否所以的请求都完成
                    count++
                    // if(count === urls.length){
                    if(count === urls.length){
                        resolve(results)
                        return
                    }
                    request()
                }
            }

            const times = Math.min(max,urls.length)
            let promiseList = []

            for(let i = 0; i < times; i++){
                promiseList.push(request())
            }

            Promise.race(promiseList).then(() => {
            }).catch((err) => {
                reject(err)
            })
        })
    }

yyshino大约 1 分钟FrontEndJS手写系列
Vue响应式实现

原理

ProxyObject.defineProperty

  1. Proxy
    1. Proxy 将代理一个对象(被代理对象),得到一个新的对象(代理对象),同时拥有被代理对象中所有的属性。
    2. 当想要修改对象的指定属性时,我们应该使用代理对象进行修改
    3. 代理对象 的任何一个属性都可以触发 handlergettersetter
  2. Object.defineProperty
    1. Object.defineProperty 为指定对象的指定属性设置属性描述符
    2. 当想要修改对象的指定属性时,可以使用原对象进行修改
    3. 通过属性描述符,只有 被监听 的指定属性,才可以触发 gettersetter

yyshino大约 2 分钟FrontEndJS
手写Promise相关方法

Promise.all

特点:

  • Promise.all() 方法接收一个promise的iterable类型(MDN)
  • 只返回一个promise实例
  • 当传入的参数promise全部成功时,最后的结果才会成功(成功的结果是所有的promise的成功的结果组成的数组),只要有一个promise失败,all返回的实例就是一个失败的promise(失败的结果是传入的参数中的第一个失败的promise的结果)
let p1 = new Promise(resolve => {
    setTimeout(resolve, 200, 1)
});
let p2 = new Promise((resolve, reject) => reject(2));
let p3 = 3;
console.log(Promise.all([p1, p2, p3]));//all方法
let myAll = function(parr) {
    let result = [],//最后成功的结果
        count = 0,//累加器,与len比较判断是否全部成功了
        len = parr.length;
    return new Promise((resolve, reject) => {
        for (let p of parr) {// 依次测试传入的参数(转化为promise)是否是成功的
            Promise.resolve(p).then(res => {
                result[count] = res;// 成功就加入到结果中
                count++;// 累加器加一
                if (count == len) {// 如果相等,说明都成功了,可以走成功resolve
                    resolve(res);
                }
            }, err => {
            // 只要有一个失败了,直接走失败reject
                reject(err);
            })
        }
    })
}
console.log(myAll([p1, p2, p3]));

yyshino大约 3 分钟FrontEndJS手写系列
手写常用排序算法

冒泡排序

在未排序区域中,从前向后不断对比相邻数据,将较大值不断向后移动,直至移动到未排序区域的最后一位。

    const arr = [2, 44, 1, 0, -22, 56, -78];
    // arr.sort((a,b)=>a-b)
    function bubbleSort(arr){
        let tmp;
        for(let i=arr.length; i>0; i--){// 较大的arr[j]会冒泡到arr的尾部
            for(let j=0; j<i-1; j++){
                if(arr[j]>arr[j+1]){// 前一个元素比或一个大,则向后冒泡(交换)
                    tmp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = tmp;
                }
            }
        }
        return arr;
    }
    console.log(bubbleSort(arr));// [-78, -22, 0, 1, 2, 44, 56]

yyshino大约 4 分钟FrontEnd算法JS算法
堆栈

堆栈的区别

  1. 栈(操作系统):由操作系统自动分配释放存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈( 简单数据类型存放到栈里面 )
  2. 堆(操作系统):存储复杂类型(对象),一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收( 复杂数据类型存放到堆里面)

yyshino小于 1 分钟FrontEndJS