·vincent

Javascript中常见API的实现原理

基础五

Javascript

异步队列控制

js
1async function asyncPool(poolLimit, tasks) {
2    const results = []; // 存储所有任务的结果
3    const executing = new Set(); // 当前正在执行的任务
4
5    for (const task of tasks) {
6        // 如果当前并发数达到限制,等待其中一个任务完成
7        if (executing.size >= poolLimit) {
8            await Promise.race(executing);
9        }
10
11        // 启动新任务
12        const p = task()
13            .then((result) => {
14                results.push(result); // 存储任务结果
15                executing.delete(p); // 任务完成后从执行队列中移除
16            })
17            .catch((error) => {
18                console.error('Task failed:', error); // 捕获任务错误
19                executing.delete(p); // 任务失败后从执行队列中移除
20            });
21
22        executing.add(p); // 将任务添加到执行队列
23    }
24
25    // 等待所有任务完成
26    await Promise.all(executing);
27    return results;
28}
29
30// 示例
31(async () => {
32    const tasks = [
33        () => new Promise((resolve) => setTimeout(() => resolve('Task 1'), 1000)),
34        () => new Promise((resolve) => setTimeout(() => resolve('Task 2'), 2000)),
35        () => new Promise((resolve) => setTimeout(() => resolve('Task 3'), 1500)),
36        () => new Promise((resolve) => setTimeout(() => resolve('Task 4'), 500)),
37    ];
38
39    const results = await asyncPool(2, tasks); // 限制并发数为 2
40    console.log(results); // ['Task 1', 'Task 2', 'Task 3', 'Task 4']
41})();

call的实现

js
1Function.prototype.call = function(context,...args){
2    let cxt = context || window;
3    let func = Symbol() 
4    cxt[func] = this;
5    args = args ? args : []
6    const res = args.length > 0 ? cxt[func](...args) : cxt[func]();
7    delete cxt[func];
8    return res;
9}

apply的实现

js
1Function.prototype.apply = function(context,args = []){
2    let cxt = context || window;
3    let func = Symbol()
4    cxt[func] = this;
5    const res = args.length > 0 ? cxt[func](...args) : cxt[func]();
6    delete cxt[func];
7    return res;
8}

bind的实现

js
1Function.prototype.bind = function (context, ...args) {
2    const fn = this
3    args = args ? args : []
4    return function newFn(...newFnArgs) {
5        if (this instanceof newFn) {
6            return new fn(...args, ...newFnArgs)
7        }
8        return fn.apply(context, [...args,...newFnArgs])
9    }
10}

寄生式组合继承

js
1function Person(obj) {
2    this.name = obj.name
3    this.age = obj.age
4}
5Person.prototype.add = function(value){
6    console.log(value)
7}
8var p1 = new Person({name:"zhangsan", age: 18})
9
10function Person1(obj) {
11    Person.call(this, obj)
12    this.sex = obj.sex
13}
14
15Person1.prototype = Object.create(Person.prototype);
16Person1.prototype.constructor = Person1;
17
18Person1.prototype.play = function(value){
19    console.log(value)
20}
21var p2 = new Person1({name:"lisi", age: 18, sex: "男"})
22

ES6继承

js
1class Person{
2  constructor(name='zhangsan',age=18){
3    this.name = name;
4    this.age = age;
5  }
6  desc(){
7    console.log(`${this.name} ${this.age}`)
8  }
9}
10
11class Man extends Person{ 
12   constructor(name = 'lisi',age = 18){ 
13     super(name, age); 
14   } 
15   desc(){
16      super.eat() 
17   } 
18}

new的实现

js
1function new(ctor,...args){
2    if(typeof ctor !== 'function'){
3      throw 'the first param must be a function';
4    }
5    var newObj = Object.create(ctor.prototype);
6    var ctorReturnResult = ctor.apply(newObj, args);
7    var isObject = typeof ctorReturnResult === 'object' && ctorReturnResult !== null;
8    var isFunction = typeof ctorReturnResult === 'function';
9    if(isObject || isFunction){
10        return ctorReturnResult;
11    }
12    return newObj;
13}
14let c = new(Ctor);

instanceof的实现

js
1function myInstanceOf(a,b){
2    let left = a.__proto__;
3    let right = b.prototype;
4    while(true){
5        if(left == null){
6            return false
7        }
8        if(left == right){
9            return true
10        }
11        left = left.__proto__
12    }
13}
14function myInstanceof(left, right) {
15    let proto = Object.getPrototypeOf(left),
16    prototype = right.prototype; 
17    while (true) {
18        if (!proto) return false;
19        if (proto === prototype) return true;
20        proto = Object.getPrototypeOf(proto);
21    }
22}

Object.create()的实现

js
1
2function myCreate(obj){
3    function C(){};
4    C.prototype = obj;
5    return new C()
6}
7
8if (typeof Object.create !== "function") {
9    Object.create = function (proto, propertiesObject) {
10        if (typeof proto !== 'object' && typeof proto !== 'function') {
11            throw new TypeError('Object prototype may only be an Object: ' + proto);
12        } else if (proto === null) {
13            throw new Error("This browser's implementation of Object.create is a shim and doesn't support 'null' as the first argument.");
14        }
15
16        if (typeof propertiesObject !== 'undefined') throw new Error("This browser's implementation of Object.create is a shim and doesn't support a second argument.");
17
18        function F() {}
19        F.prototype = proto;
20
21        return new F();
22    };
23}

实现 Object.assign

js
1Object.assign2 = function(target, ...source) {
2    if (target == null) {
3        throw new TypeError('Cannot convert undefined or null to object')
4    }
5    let ret = Object(target) 
6    source.forEach(function(obj) {
7        if (obj != null) {
8            for (let key in obj) {
9                if (obj.hasOwnProperty(key)) {
10                    ret[key] = obj[key]
11                }
12            }
13        }
14    })
15    return ret
16}

Ajax的实现

js
1function ajax(url,method,body,headers){
2    return new Promise((resolve,reject)=>{
3        let req = new XMLHttpRequest();
4        req.open(methods,url);
5        for(let key in headers){
6            req.setRequestHeader(key,headers[key])
7        }
8        req.onreadystatechange(()=>{
9            if(req.readystate == 4){
10                if(req.status >= '200' && req.status <= 300){
11                    resolve(req.responseText)
12                }else{
13                    reject(req)
14                }
15            }
16        })
17        req.send(body)
18    })
19}

实现防抖函数(debounce)

js
1let debounce = (fn,time = 1000) => {
2    let timeLock = null
3    return function (...args){
4        clearTimeout(timeLock)
5        timeLock = setTimeout(()=>{
6            fn(...args)
7        },time)
8    }
9}

实现节流函数(throttle)

js
1let throttle = (fn,time = 1000) => {
2    let flag = true;
3    return function (...args){
4        if(flag){
5            flag = false;
6            setTimeout(()=>{
7                flag = true;
8                fn(...args)
9            },time)
10        }
11    }
12}

深拷贝

js
1function deepClone(obj,hash = new WeakMap()){
2    if(obj instanceof RegExp) return new RegExp(obj);
3    if(obj instanceof Date) return new Date(obj);
4    if(obj === null || typeof obj !== 'object') return obj;
5    if(hash.has(obj)){
6        return hash.get(obj)
7    }
8    let constr = new obj.constructor();
9    hash.set(obj,constr);
10    for(let key in obj){
11        if(obj.hasOwnProperty(key)){
12            constr[key] = deepClone(obj[key],hash)
13        }
14    }
15    let symbolObj = Object.getOwnPropertySymbols(obj)
16    for(let i=0;i<symbolObj.length;i++){
17        if(obj.hasOwnProperty(symbolObj[i])){
18            constr[symbolObj[i]] = deepClone(obj[symbolObj[i]],hash)
19        }
20    }
21    return constr
22}

数组扁平化的实现(flat)

js
1let arr = [1,2,[3,4,[5,[6]]]]
2console.log(arr.flat(Infinity))
js
1
2function fn(arr){
3   return arr.reduce((prev,cur)=>{
4      return prev.concat(Array.isArray(cur)?fn(cur):cur)
5   },[])
6}

函数柯里化

js
1function sumFn(a,b,c){return a+ b + c};
2let sum = curry(sumFn);
3sum(2)(3)(5)
4sum(2,3)(5)
js
1function curry(fn,...args){
2  let fnLen = fn.length,
3      argsLen = args.length;
4  if(fnLen > argsLen){
5    return function(...arg2s){
6      return curry(fn,...args,...arg2s)
7    }
8  }else{
9    return fn(...args)
10  }
11}

使用闭包实现每隔一秒打印 1,2,3,4

js
1for (var i=1; i<=5; i++) {
2  (function (i) {
3    setTimeout(() => console.log(i), 1000*i)
4  })(i)
5}

手写一个 jsonp

js
1const jsonp = function (url, data) {
2    return new Promise((resolve, reject) => {
3        let dataString = url.indexOf('?') === -1 ? '?' : ''
4        let callbackName = `jsonpCB_${Date.now()}`
5        url += `${dataString}callback=${callbackName}`
6        if (data) {
7            for (let k in data) {
8                url += `${k}=${data[k]}`
9            }
10        }
11        let jsNode = document.createElement('script')
12        jsNode.src = url
13        window[callbackName] = result => {
14            delete window[callbackName]
15            document.body.removeChild(jsNode)
16            if (result) {
17                resolve(result)
18            } else {
19                reject('没有返回数据')
20            }
21        }
22        // js加载异常的情况
23        jsNode.addEventListener('error', () => {
24            delete window[callbackName]
25            document.body.removeChild(jsNode)
26            reject('JavaScript资源加载失败')
27        }, false)
28        // 添加js节点到document上时,开始请求
29        document.body.appendChild(jsNode)
30    })
31}
32jsonp('http://127.0.0.1/jsonp', {
33    a: 1,
34    b: 'hello'
35})
36.then(result => {
37    console.log(result)
38})
39.catch(err => {
40    console.error(err)
41})

手写一个观察者模式

js
1class Subject{
2  constructor(name){
3    this.name = name
4    this.observers = []
5    this.state = 'off'
6  }
7  attach(observer){
8    this.observers.push(observer)
9  }
10
11  setState(newState){
12    this.state = newState
13    this.observers.forEach(o=>{
14      o.update(newState)
15    })
16  }
17}
18
19class Observer{
20  constructor(name){
21    this.name = name
22  }
23
24  update(newState){
25    console.log(`${this.name}say:${newState}`)
26  }
27}
28
29let sub = new Subject('')
30let zhangsan = new Observer('zhangsan')
31let lisi = new Observer('lisi')
32
33sub.attach(zhangsan)
34sub.attach(lisi)
35
36sub.setState('on')

EventEmitter 实现

js
1EventEmitter 实现
2class EventEmitter {
3    constructor() {
4        this.events = {};
5    }
6    on(event, callback) {
7        let callbacks = this.events[event] || [];
8        callbacks.push(callback);
9        this.events[event] = callbacks;
10        return this;
11    }
12    off(event, callback) {
13        let callbacks = this.events[event];
14        this.events[event] = callbacks && callbacks.filter(fn => fn !== callback);
15        return this;
16    }
17    emit(event, ...args) {
18        let callbacks = this.events[event];
19        callbacks.forEach(fn => {
20            fn(...args);
21        });
22        return this;
23    }
24    once(event, callback) {
25        let wrapFun = function (...args) {
26            callback(...args);
27            this.off(event, wrapFun);
28        };
29        this.on(event, wrapFun);
30        return this;
31    }
32}
33

生成随机数的各种方法?

js
1function getRandom(min, max) {
2  return Math.floor(Math.random() * (max - min)) + min   
3}

如何实现数组的随机排序

js
1let arr = [1,2,3,4,5]
2arr.sort(randomSort)
3function randomSort(a, b) {
4  return Math.random() > 0.5 ? -1 : 1;
5}

写一个通用的事件侦听器函数

js
1const EventUtils = {
2  addEvent: function(element, type, handler) {
3    if (element.addEventListener) {
4      element.addEventListener(type, handler, false);
5    } else if (element.attachEvent) {
6      element.attachEvent("on" + type, handler);
7    } else {
8      element["on" + type] = handler;
9    }
10  },
11  removeEvent: function(element, type, handler) {
12    if (element.removeEventListener) {
13      element.removeEventListener(type, handler, false);
14    } else if (element.detachEvent) {
15      element.detachEvent("on" + type, handler);
16    } else {
17      element["on" + type] = null;
18    }
19  },
20  getTarget: function(event) {
21    return event.target || event.srcElement;
22  },
23  getEvent: function(event) {
24    return event || window.event;
25  },
26  stopPropagation: function(event) {
27    if (event.stopPropagation) {
28      event.stopPropagation();
29    } else {
30      event.cancelBubble = true;
31    }
32  },
33  preventDefault: function(event) {
34    if (event.preventDefault) {
35      event.preventDefault();
36    } else {
37      event.returnValue = false;
38    }
39  }
40};

使用迭代的方式实现 flatten 函数

js
1var arr = [1, 2, 3, [4, 5], [6, [7, [8]]]]
2function wrap() {
3    var ret = [];
4    return function flat(a) {
5        for (var item of a) {
6                if (item.constructor === Array) {
7                    ret.concat(flat(item))
8                } else {
9                    ret.push(item)
10                }
11        }
12        return ret
13    }
14} 
15console.log(wrap()(arr));

怎么实现一个sleep

js
1function sleep(delay) {
2  var start = (new Date()).getTime();
3  while ((new Date()).getTime() - start < delay) {
4    continue;
5  }
6}
7
8function test() {
9  console.log('111');
10  sleep(2000);
11  console.log('222');
12}
13
14test()

实现正则切分千分位(10000 => 10,000)

js
1let num1 = '1321434322222'
2num1.replace(/(\d)(?=(\d{3})+$)/g,'$1,')
3
4let num2 = '342243242322.3432423'
5num2.replace(/(\d)(?=(\d{3})+\.)/g,'$1,')

对象数组去重

js
1输入:
2[{a:1,b:2,c:3},{b:2,c:3,a:1},{d:2,c:2}]
3输出:
4[{a:1,b:2,c:3},{d:2,c:2}]
js
1function objSort(obj){
2    let newObj = {}
3    Object.keys(obj).sort().map(key => {
4        newObj[key] = obj[key]
5    })
6    return JSON.stringify(newObj)
7}
8
9function unique(arr){
10    let set = new Set();
11    for(let i=0;i<arr.length;i++){
12        let str = objSort(arr[i])
13        set.add(str)
14    }
15    arr = [...set].map(item => {
16        return JSON.parse(item)
17    })
18    return arr
19}

解析 URL Params 为对象

js
1let url = 'http://www.domain.com/?user=zhangsan&id=100&id=200&city=beijing&enabled';
2parseParam(url)
js
1function parseParam(url) {
2  const paramsStr = /.+\?(.+)$/.exec(url)[1];
3  const paramsArr = paramsStr.split('&');
4  let paramsObj = {};
5  paramsArr.forEach(param => {
6    if (/=/.test(param)) {
7      let [key, val] = param.split('=');
8      val = decodeURIComponent(val);
9      val = /^\d+$/.test(val) ? parseFloat(val) : val; 
10
11      if (paramsObj.hasOwnProperty(key)) {
12        paramsObj[key] = [].concat(paramsObj[key], val);
13      } else {
14        paramsObj[key] = val;
15      }
16    } else { 
17      paramsObj[param] = true;
18    }
19  })
20
21  return paramsObj;
22}

模板引擎实现

js
1let template = '我是{{name}},年龄{{age}},性别{{sex}}';
2let data = {
3  name: '姓名',
4  age: 18
5}
6render(template, data);
js
1function render(template, data) {
2  const reg = /\{\{(\w+)\}\}/; 
3  if (reg.test(template)) {
4    const name = reg.exec(template)[1]; 
5    template = template.replace(reg, data[name]); 
6    return render(template, data); 
7  }
8  return template;
9}

转化为驼峰命名

js
1var s1 = "get-element-by-id"
2// 转化为 getElementById
js
1var f = function(s) {
2    return s.replace(/-\w/g, function(x) {
3        return x.slice(1).toUpperCase();
4    })
5}

查找字符串中出现最多的字符和个数

  • 例: abbcccddddd -> 字符最多的是d,出现了5次
js
1let str = "abcabcabcbbccccc";
2let num = 0; let char = '';
3
4str = str.split('').sort().join('');
5
6let re = /\(w)\1+/g; 
7str.replace(re,\($0,$1) => {
8if(num < $0.length){ 
9num = $0.length; 
10char = $1;  
11} }); 
12console.log(`字符最多的是${char},出现了${num}`)

图片懒加载

js
1let imgList = [...document.querySelectorAll('img')]
2let length = imgList.length
3
4const imgLazyLoad = function() {
5    let count = 0
6    return (function() {
7        let deleteIndexList = []
8        imgList.forEach((img, index) => {
9            let rect = img.getBoundingClientRect()
10            if (rect.top < window.innerHeight) {
11                img.src = img.dataset.src
12                deleteIndexList.push(index)
13                count++
14                if (count === length) {
15                    document.removeEventListener('scroll', imgLazyLoad)
16                }
17            }
18        })
19        imgList = imgList.filter((img, index) => !deleteIndexList.includes(index))
20    })()
21}
22
23document.addEventListener('scroll', imgLazyLoad)