1 2 3 4 5 6 7
| function myNew(){ var obj = new Object() var constructor = Array.prototype.shift.call(arguments) obj.__propto = contructor.prototype var result = constructor.apply(obj,arguments) return typeof result === "Object" ? result : obj }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class EventBus { constructor(){ this.eventArr = [] } on(eventName,cb){ if(this.eventArr[eventName]) this.eventArr[eventName].push(cb) else this.eventArr[eventName] = [cb] } emit(eventName,params){ if(!this.eventArr[eventName]) console.log("事件不存在") else { this.eventArr[eventName].map(fn => fn(...params)) } } off(eventName){ if(this.eventArr[eventName]){ delete this.eventArr[eventName] } } } const eventBus = new EventBus() export default eventBus
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
| function Promise(executor) { this.PromiseState = "pending"; this.PromiseResult = null; this.callbacks = []; const self = this; function resolve(data) { if (self.PromiseState !== "pending") return; self.PromiseState = "fulfilled"; self.PromiseResult = data; setTimeout(() => { self.callbacks.forEach((item) => { item.onresolved(data); }); }) }
function reject(data) { if (self.PromiseState !== "pending") return; self.PromiseState = "rejected"; self.PromiseResult = data; setTimeout(() => { self.callbacks.forEach((item) => { item.onrejected(data); }); }) } try { executor(resolve, reject); } catch (error) { reject(error); } }
Promise.prototype.then = function (onresolved, onrejected) { const self = this; if (typeof onresolved !== "function") { onresolved = (value) => value; } if (typeof onrejected !== "function") { onrejected = (reason) => { throw reason; }; } return new Promise((resolve, reject) => { function callback(type) { try { let result = type(self.PromiseResult); if (result instanceof Promise) { result.then( (v) => { resolve(v); }, (r) => { reject(r); } ); } else { resolve(result); } } catch (error) { reject(error); } } if (this.PromiseState === "fulfilled") { setTimeout(() => { callback(onresolved); }); } if (this.PromiseState === "rejected") { setTimeout(() => { callback(onrejected); }); } if (this.PromiseState === "pending") { this.callbacks.push({ onresolved: function () { callback(onresolved); }, onrejected: function () { callback(onrejected); }, }); } }); };
Promise.prototype.catch = function (onrejected) { return this.then(undefined, onrejected); };
Promise.resolve = function (value) { return new Promise((resolve, reject) => { if (value instanceof Promise) { value.then( (v) => { resolve(v); }, (r) => { reject(r); } ); } else { resolve(value); } }); };
Promise.reject = function (reason) { return new Promise((resolve, reject) => { reject(reason); }); };
Promise.all = function (promises) { return new Promise((resolve, reject) => { let count = 0; let arr = []; for (let i = 0; i < promises.length; i++) { promises[i].then( (v) => { count++; arr[i] = v; if (count == promises.length) { resolve(arr); } }, (r) => { reject(r); } ); } }); };
Promise.race = function (promises) { return new Promise((resolve, reject) => { for (let i = 0; i < promises.length; i++) { promises[i].then( (v) => { resolve(v); }, (r) => { reject(r); } ); } }); };
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| function all(arr){ let result = [] let count = 0 return new Promise((resolve,reject) => { for(let i = 0;i < arr.length;i++){ Promise.resolve(arr[i]).then(res => { result[count] = res count++ if(count == arr.length) return resolve(result) },err => { reject(err) }) } }) }
let p1 = new Promise(resolve => { setTimeout(resolve,200,1) }); let p2 = new Promise((resolve, reject) => reject(2)) let p3 = 3; console.log(all([p1,p2,p3]))
|

1 2 3 4 5 6 7 8 9 10 11
| function race(arr){ return new Promise((resolve,reject) > { for(let i = 0;i < arr.length;i++){ Promise.resolve(arr[i]).then(res => { resolve(res) },err => { reject(err) }) } }) }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| function any(arr){ let result = [] let count = 0 for(let i = 0;i < arr.length;i++){ return new Promise((resolve,reject) => { Promise.resolve(arr[i]).then(res => { resolve(res) },err =>{ result[count] = err count++ if(count === arr.length) reject(result) }) }) } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| function allSettled(arr){ let result = [] let count = 0 return new Promise((resolve,reject) => { for(let i = 0;i < arr.length;i++){ Promise.resolve(arr[i]).then(res =>{ result[count] = { status:'fullfilled', result:res } count++ if(count === arr.length) resolve(result) },err =>{ result[count] = { status:'rejected', result:err } count++ if(count === arr.length) reject(result) }) } }) }
|
1 2 3 4 5 6 7 8 9
| function Instanceof(left,right){ let left = left._proto_ while(left){ if(left === right) return true left = left._proto_ } return false }
|
1、Object.is
Object.is主要解决一下两个问题:
+0 === -0 //true,正常理解应该为false
NaN === NaN //false,正常理解应该为true
1 2 3 4 5 6 7
| const is = (x,y) => { if(x === y){ return x !== 0 || y !== 0 || 1/x === 1/y }else { return x !== x && y !== y } }
|
2、Object.assign
该方法用于将所有可枚举属性的值从一个或多个元对象复制到目标对象,它将返回目标对象(浅拷贝)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| Object.defineProperty(object,'assign',{ value:function(target,...args){ if(target === null || targte === undefined){ return new TypeError('Cannot convert undefined or null to object') } const targetObj = Object(target) for(const sourceObj of args){ if(sourceObj !== null) { for(const key in sourceObj){ if(Object.prototype.hasOwnproperty.call(sourceObj,key)){ targetObj[key] = sourceObj[key] } } } } return targetObj }, enumerable:false, writable:true, configurable:true })
|
防抖实现
所谓防抖,就是指触发事件后 n 秒后才执行函数,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
节流实现
所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。 节流会稀释函数的执行频率。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| function debounce(fn,delay){ var timeout = null return function(){ clearTimeout(timeout) timeout = setTimeout(() => { fn.apply(this,arguments) }, delay); } } function fn1(){ console.log(aaa) } window.addEventListener("scroll",debounce(fn1,5000))
function throttle(fn,delay){ let isOpen = true return function(){ if(!isOpen) return isOpen = false setTimeout(function(){ fn.call(this,arguments) isOpen = true }) } function fn2(){ console.log('bbb') } window.addEventListener("resize",throttle(fn2,5000))
|
- 数组扁平化:数组扁平化就是把多维数组转化成一维数组。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| let arr = [1,2,3,[4,5,[6,7]]] console.log(arr.flat()) console.log(arr.flat(3))
function flatten(arr){ return arr.reduce((pre,cur) => { return pre.concat(Array.isArray(cur) ? flatten(cur) : cur) },[]) }
function flatten(arr){ while(arr.some(item => Array.isArray(item) === true)){ arr = [].concat(...arr) } return arr }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| let copyObj = Object.assign({},obj)
import _ from "lodash" let copyObj = _.clone(obj)
let copyObj = {...obj}
let arr = [1,2,3,4] let copyArr = arr.concat()
let arr = [1,2,3,4] let copyArr = arr.slice()
function simpleClone(target) { if(typeof target !== "object" || target === null) return target var obj = Array.isArray(target) ?[] : {} for ( var i in target) { if(Object.prototype.hasOwnProperty.call(target,key)){ obj[i] = target[i]; } } return obj; }
|
深拷贝:在堆中重新分配内存,不同的地址,相同的值,互不影响
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
import _ from "lodash" let copyObj = _.cloneDeep(obj)
function deepClone(target,hash = new WeakMap()){ if(typeof(target) !== "object") return target var cloneTarget = target instanceof Array ? [] : {} if(hash.get(target)) return hash.get(target) else hash.set(target,cloneTarget) let symbolKeys = Object.getOwnpropertySymbols(target) if(symbolKeys.length){ symbolKeys.forEach(key => { if(typeof target[key] == "object" && target[key] !== null){ cloneTarget[key] = deepClone(target[key],hash) }else cloneTarget[key] = target[key] }) } for (const key in target) { if (target.hasOwnProperty(key)) { cloneTarget[key] = typeof(target[key]) === "object" ? deepClone(target[key],hash) : target[key] } } return cloneTarget }
|
这三个方法都可以显式指定调用函数的this指向,其中apply方法接收两个参数:一个是this绑定的对象,一个是参数数组。call方法接收的参数一个是this绑定的对象,后面的其余参数是传入函数执行的参数,参数是以列举的形式传进去的;bind方法通过传入一个对象返回一个this绑定了传入对象的新函数,这个函数的this指向除了使用new时会被改变,其他情况下都不会改变。
1 2 3 4 5 6 7 8 9
| function myApply(){ if(typeof this !== "function") return console.log("type error") let context = argements[0] let self = this context.fn = self context.fn(...arguments[1]) delete context.fn }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| function myCall(){ if(typeof this !== "function) return console.log("type error") const args = Array.prototype.slice.call(auguments) //新this的值 let context = args.shift() //旧this就是要执行的函数 let self = this //把函数作为新this的方法,这样调用时this默认指向新this context.fn = self context.fn(...args) //函数执行完毕后删除新this中的fn方法 delete context.fn }
|
原理:通过apply或call方法实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| Function.prototype.bind = function(){ const arg = Array.prototype.slice.call(arguments) const t = arg.shift() const self = this return function(newArg){ arg = arg.concat.calll(Array.prototype.slice.call(newArg)) return self.apply(t,arg) }
|
- 用setTimeout实现setInterval:
1 2 3 4 5 6 7
| function mySetTimeout(fn,millisec){ function interval(){ setTimeout(interval,millisec) fn() } setTimeout(interval,millisec) }
|
- 使用requestAnimationFrame实现定时器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| function setIntervalPrecision(callback,delay){ let obj = window.intervalPrecisionObj || (window.intervalPrecisionObj = {num:0}) obj.num++ obj['n' + obj.num] = true let intervalId = obj.num let startTime = +new Date() let count = 0 delay = delay | 0 (function loop(){ if(!obj['n' + intervalId]) return if(+new Date() > startTime + delay * (count + 1)){ count++ callback(count) } requestAnimationFrame(loop) })() return intervalId }
function clearIntervalPrecision(intervalId){ if(window.intervalPrecisionObj){ delete window.intervalPrecisionObj['n' + intervalId] } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| const jsonp = ({ url, params, callbackName }) => { const generateUrl = () => { let dataSrc = "" for(let key in params){ if(Object.prototype.hasOwnProperty.call(params,key)){ dataSrc += `${key}${params[key]}&` } } dataSrc += `callback=${callbackName}` return `${url}?${dataSrc}` } return new Promise((resolve,reject) => { const scriptEle = document.createElement('script') scriptEle.src = generateUrl() document.body.appenChild(scriptEle) window[callbackName] = data => { resolve(data) document.removeChild(scriptEle) } }) }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| var AJAX = { get : function(url,callback){ var xhr = new XMLHttpRequst() xhr.open("GET",url,false) xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ if(xhr.status === 200){ console.log(responseText) } } xhr.onerror = function() { console.error(this.statusText); }; xhr.responseType = "json"; xhr.setRequestHeader("Accept", "application/json"); xhr.send() xhr.abort() } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| 1、使用工厂函数CanceToken创建cancel token const CancelToken = axios.CancelToken const source = CancelToken.source() axios.get("user",{ cancelToken:source.token }) source.cancel("参数是可选的")
const CancelToken = axios.CancelToken let cancel axios.get("user",{ cancelToken:new CancelToken(function executor(c){ cancel = c }) }) cancel()
const controller = new AbortController() axios.get("user",{ signal:controller.signal }).then((res) =>{ ... }) controller.abort()
|
柯里化:指的是一个接受多个参数的函数转变为接受一个参数返回一个函数的固定形式,从而便于再次调用。
实现参数定长的柯里化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| function curry(fn){ const argLen = fn.length const presetArgs = [].slice.call(arguments,1) return function(){ cosnt resetArgs = [].slice.call(arguments) const allArgs = [...presetArgs,...resetArgs] if(allArgs.length >= argLen){ return fn.apply(this,allArgs) }else{ return curry.call(null,fn,...allArgs) } } }
|
实现参数不定长的柯里化:
1 2 3 4 5 6 7 8 9 10 11 12
| function curry(fn){ const presetArgs = [].slice.call(auguments,1) function curried(){ const resetArgs = [].slice.call(auguments) const allArgs = [...presetArgs,...resetArgs] return curry.apply(null,fn,arguments) } curried.toString = function(){ return fn.apply(null,presetArgs) } }
|
作用:
1、使函数的职责单一化,将每次传入的参数在单一的函数中进行处理后在下一个函数中使用处理后的结果,而不是所有的参数一次传入:
1 2 3 4 5 6 7 8 9 10 11
| function add(x){ x ++ return function(y){ y *= 2 return function(z){ z++ return x + y + z } } } console.log(add(1)(2)(3))
|
2、进行参数复用,如先传入一个后续调用都需要的函数参数,在之后使用返回的函数时就不需要再传入此参数
1 2 3 4 5 6 7 8
| function fn(num){ retrun function(count){ return num - count } } let sub = fn(100) console.log(sub(10)) console.log(sub(20))
|
3、打印日志时实现柯里化:
1 2 3 4 5
| function log(data,importance,message){ alert(`[${data.getHours()}:${data.getMinutes()}][${importance} ${message}]`) let logNow = log(new Date()) } logNow("Info","message")
|
例子:实现一个add 函数,同时支持add(1, 2, 3); add(1, 2)(3); add(1)(2, 3);
1 2 3 4 5 6 7 8 9 10 11
| const curry = (fn,...args) => { return args.length >= fn.length ? fn(...args) : (..._args) => curry(fn,...args,..._args) } function add(x,y,z){ return x + y + z } const add = curry(add) console.log(add(1,2,3)) console.log(add(1,2)(3)) console.log(add(1)(2)(3))
|