·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)