源码小栗子

1、实现一个reducer

  Array.prototype.reducer1 = function (callBack, initVal) {
    if (!Array.isArray(this) || this.length <= 0 || typeof callBack !== 'function') {
      return []
    }
    let res = !!initVal ? initVal : this[0]
    const hasInitVal = !!initVal
    for(var i = hasInitVal? 0 : 1; i < this.length; i++) {
      res = callBack(res, this[i], i, this)
    }
    return res
  }

2、手动实现Array.prototype.filter方法

//手动实现Array.prototype.filter方法
function filter(arr, filterCallback) {
    // 首先,检查传递的参数是否正确。
    if (!Array.isArray(arr) || !arr.length || typeof filterCallback !== 'function') 
    {
      return [];
    } else {
      let result = [];
       // 每次调用此函数时,我们都会创建一个 result 数组
       // 因为我们不想改变原始数组。
      for (let i = 0, len = arr.length; i < len; i++) {
        // 检查 filterCallback 的返回值是否是真值
        if (filterCallback(arr[i], i, arr)) { 
        // 如果条件为真,则将数组元素 push 到 result 中
          result.push(arr[i]);
        }
      }
      return result; // return the result array
    }
  }

3、手动实现 Array.prototype.map 方法

function map(arr, mapCallback) {
    // 首先,检查传递的参数是否正确。
    if (!Array.isArray(arr) || !arr.length || typeof mapCallback !== 'function') { 
      return [];
    } else {
      let result = [];
      // 每次调用此函数时,我们都会创建一个 result 数组
      // 因为我们不想改变原始数组。
      for (let i = 0, len = arr.length; i < len; i++) {
        result.push(mapCallback(arr[i], i, arr)); 
        // 将 mapCallback 返回的结果 push 到 result 数组中
      }
      return result;
    }
  }

4、实现一个repeat

String.prototype.repeat = function (times) {
  let str = ''
  while(times) {
    str += this;
    times--
  }
  return str
}

var str = 'cheese'
console.log(str.repeat(3))

5、实现一个trim

String.prototype.trim = function() {
  return this.replace(/^\s+/, '').replace(/\s+$/, '');
}

6、实现最大请求并发限制

利用任务队列

var urls = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
const limit = 5;

function sendRequest(urls, limit, callback) {
    function _send(urls) {
        const url = urls.shift();
        if (url) {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    console.log(`当前发送:${url}`);
                    resolve(url);
                }, 1000)
            })
                .finally(() => {
                    if (urls.length > 0) {
                        return _send(urls)
                    }
                })
        }
    }
  
    let asyncList = [];
    while (limit--) {
        asyncList.push(_send(urls));
    }
    return Promise.all(asyncList).then(callback);
}

sendRequest(urls, limit, function () {
    console.log('all urls sended!')
});

7、控制最大并发数(字节原题)

利用任务队列

参考:https://juejin.cn/post/6970642160676765732

class Scheduler {
    constructor() {
        this.tasks = [], // 待运行的任务
        this.usingTask = [] // 正在运行的任务
    }
    // promiseCreator 是一个异步函数,return Promise 
  	// 相当于不阻塞主线程的操作
    add(promiseCreator) {
        return new Promise((resolve, reject) => {
            promiseCreator.resolve = resolve
            if (this.usingTask.length < 2) {
                this.usingRun(promiseCreator)
            } else {
                this.tasks.push(promiseCreator)
            }
        })
    }
    usingRun(promiseCreator) {
        this.usingTask.push(promiseCreator)
        promiseCreator().then(() => {
            promiseCreator.resolve()
            let index = this.usingTask.findIndex(promiseCreator)
            this.usingTask.splice(index, 1)
            if (this.tasks.length > 0) {
                this.usingRun(this.tasks.shift())
            }
        })
    }
}
const timeout = (time) => new Promise(resolve => {
    setTimeout(resolve, time)
})
const scheduler = new Scheduler()
const addTask = (time, order) => {
    scheduler.add(() => timeout(time)).then(() => console.log(order))
}
addTask(400, 4)
addTask(200, 2)
addTask(300, 3)
addTask(100, 1)
// 2, 4, 3, 1
function createPoolRequest(prams) {
  const { maxReq } = prams

  let tasks = []
  let runingtasks = []

  function runingTask (info) {
    runingtasks.push(info)
    ajax(info).then(() => {
      info.resolve(res)
      runingTask.splice(runingTask.findIndex(item => info.url === item.url), 1)
      if (tasks.length > 0) {
        runingTask(tasks.shift())
      }
    })
  }

  return (url) => {
    return new Promise((resolve, reject) => {
      if (runingTask.length < maxReq) {
        runingTask({url, resolve})
      } else {
        tasks.push({url, resolve})
      }
    })
  }
}

const request = createPoolRequest({
  pool: 3
})
request('/user').then((res)=> {
  console.log(res)
})

8、实现一个promise.all

const a = new Promise(function(resolve, reject) {
    resolve('a resolve');
})
const b = new Promise(function(resolve, reject) {
    resolve('b resolve')
})

Promise.all1 = function (arr) {
  return new Promise((resolve, reject) => {
    const res = []  
    let index =0  
    let fullCount = 0 //已完成promise的个数
    for(const p of arr){。//创建一个块级作用域
      const resultIndex = index++。//保存入参的顺序
      Promise.resolve(p).then((val)=>{ /
        res[resultIndex] = val  // 保证执行结果按顺序返回 
        fullCount++
        if(index === fullCount){. //如果已完成的个数等于输入个数,resolve
          resolve(res)
        }
      }).catch((err)=>{
        reject(err) //一旦解析失败,reject
      })
    }
  })
}

Promise.all1([a,b]).then(res => {
    console.log(res, 'cheese成功啦')
})

9、实现一个bind

Function.prototype.bind2 = function (context, ...args) {

    if (typeof this !== "function") {
        throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
    }

    var fn = this;

    var fNOP = function () { };

    var fBound = function (...bindArgs) {
        // 当作为构造函数时,this 指向实例,此时结果为 true,将绑定函数的 this 指向该实例,可以让实例获得来自绑定函数的值
        // 以上面的是 demo 为例,如果改成 `this instanceof fBound ? null : context`,实例只是一个空对象,将 null 改成 this ,
      	// 实例会具有 habit 属性
        // 当作为普通函数时,this 指向 window,此时结果为 false,将绑定函数的 this 指向 context
        fn.apply(this instanceof fNOP ? this : context, args.concat(bindArgs));
    }

    fNOP.prototype = this.prototype;
    fBound.prototype = new fNOP();
    return fBound;
}
测试用例
var value = 2;
var foo = {
  value: 1
};

function bar(name, age) {
  this.habit = 'shopping';
  console.log(this.value);
  console.log(name);
  console.log(age);
}

bar.prototype.friend = 'kevin';
var bindFoo = bar.bind(foo, 'daisy');

var obj = new bindFoo('18');
// undefined
// daisy
// 18a
console.log(obj.habit);
console.log(obj.friend);

10、实现一个call/apply

  Function.prototype.call1 = function (context, ...args) {
    if(typeof this !== 'function') {
        throw new TypeError('Error')
    }
    var newContext = context || window;
    newContext.fn = this;
    var result 
    if(args) {
        result = newContext.fn(...args);
    } else {
        result = newContext.fn();
    }
    delete newContext.fn;
    return result;
  }

11、React实现省市级联

参考:封装react组件——三级联动 - 南韵 - 博客园

12、订阅发布模式

参考:发布-订阅模式

const JasonMa_PubSub = {
  //存储事件及方法
  listenStore: {},
  //订阅/监听
  on: function(method, cb) {
    //如果已监听过这个方法,就push这个回调函数;如果没监听就创建键值对,值为一个数组用于存储当前回调函数
    if (this.listenStore[method]) {
      this.listenStore[method].push(cb);
    } else {
      this.listenStore[method] = [cb];
    }
  },
  //发布/触发
  emit: function(method, ...args) {
    //获取到监听方法对应的回调函数数组,逐个触发
    const fnList = this.listenStore[method];
    if (!fnList || fnList.length === 0) {
      return false;
    } else {
      fnList.forEach(cb => {
        cb.apply(this, args);
      });
    }
  },
  //关闭订阅
  off: function(method) {
    const fnList = this.listenStore[method];
    if (fnList && fnList.length !== 0) {
      delete this.listenStore[method];
    }
  },
  //只订阅一次
  once: function(method, cb) {
    let onceFn = (...args) => {
      cb.apply(this, args); //执行发布
      this.off(method); //停止订阅
    };
    this.on(method, onceFn); //注册重构后的一次监听事件
  }
};

export default JasonMa_PubSub;

13、红绿灯

// 方法一:
let arr = ['红灯', '绿灯', '黄灯']
let result = [];
async function led(i) {
    return new Promise((resolve) => {
        setTimeout(() => {
            console.log(arr[i])
            resolve(arr[i])
        }, i * 1000)
    }).then((res) => {
        result.push(res)
        if (result.length%3 === 0) {
            setTimeout(function () {
                lights();
            }, 1000)
        }
    })
}

function lights() {
    for (let i = 0; i < 3; i++) {
        led(i)
    }
}
lights()

//方法二:
var arr = ['red', 'yellow', 'green'];
var tasks = [];
var test = function() {
    for(var i = 0; i < arr.length; i++ ) {
        ((j) => {
            tasks.push(
                new Promise(resolve => {
                    setTimeout(() => {
                        console.log(arr[j]);
                        resolve();
                    }, j * 1000)
                })
            )
        }
    
        )(i)
    }
    Promise.all(tasks).then(() => {
        setTimeout(() => {
            test();
        }, 1000);
    })
}
test();

//方法三:
let arr = ['红灯', '绿灯', '黄灯']
function sleep(time) {
    return new Promise(resolve => {
        setTimeout(resolve, time)
    })
}
async function lights() {
    for (let i = 0; i < 3; i++) {
        await sleep(1000)
        console.log(arr[i])
        if(i == 2) i = -1;
    }
}
lights()

//方法四:
let arr = ['红灯', '绿灯', '黄灯']
function sleep(time) {
    return new Promise(resolve => {
        setTimeout(resolve, time)
    })
}
async function lights() {
    let i = 0;
    while(true) {
        await sleep(1000)
        console.log(arr[i]) 
        i++;
        i = i%3
    }
}
lights()

14、promise实现链式调用

class Promise {
    constructor(executer) { //构造函数constructor里面是个执行器
        this.status = 'pending'; //默认的状态 pending
        this.value = undefined //成功的值默认undefined
        this.reason = undefined //失败的值默认undefined
        //状态只有在pending时候才能改变
        let resolve = value => {
            //判断只有等待时才能resolve成功
            if (this.status == 'pending') {
                this.status = 'resolve';
                this.value = value;
            }
        }
        //判断只有等待时才能reject失败
        let reject = reason => {
            if (this.status == 'pending') {
                this.status = 'reject';
                this.reason = reason;
            }
        }
        try {
            //把resolve和reject两个函数传给执行器executer
            executer(resolve, reject);
        } catch (e) {
            reject(e); //失败的话进catch
        }
    }
    then(onFufilled, onReject) {
        //如果状态成功调用onFufilled
        if (this.status == 'resolve') {
            onFufilled(this.value);
        }
        //如果状态失败调用onReject
        if (this.status == 'reject') {
            onReject(this.reason);
        }
    }
}

15、实际场景问题(正则

1、container只有纯文本内容,不包含其他dom元素
2、识别所有以http://、https://或者www.开始的链接
3、所有www.开头的链接,默认使用 http 协议
4、所有链接在新窗口打开

function link() {
    var t=document.getElementById('jsContainer')
    var reg=/(https?:\/\/)?(www\.\w+(\.(com|cn))*([?]\w+=\w*(&\w+=\w*)*)?(#\w+)?)/g
    var textArr=[]
    textArr=t.innerHTML.match(reg)?Array.from(t.innerHTML.match(reg)):[]
    textArr.forEach(item=>{
        if(item.indexOf('www.')===0){
            t.innerHTML=t.innerHTML.replace(item,`<a href="http://${item}" target="_blank">${item}</a>`)
        }
        else{
            t.innerHTML=t.innerHTML.replace(item,`<a href="${item}"  target="_blank">${item}</a>`)
        }
    })
}

16、自定义hook

import React, { useState, useEffect } from 'react';
 
function FriendStatus(props) {
  const [isOnline, setIsOnline] = useState(null);  
  useEffect(() => {    
    function handleStatusChange(status) {      
      setIsOnline(status.isOnline);    
    }    
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);  
    return () => {      
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);    
    };  
  });
  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值