目錄
DOM
事件代理
數(shù)組 對象
扁平化
去重 -?unique()
拷貝
淺拷貝
深拷貝(copy()函數(shù)實(shí)現(xiàn)落追、JSON.stringify)
字符串
去除空格 -?trim()
字符串全排列
廣度優(yōu)先實(shí)現(xiàn)
深度優(yōu)先實(shí)現(xiàn)
排序和查找
插入排序
歸并排序
快速排序
二分查找
找出出現(xiàn)次數(shù)最多的元素 -?getMostItem()
功能函數(shù)實(shí)現(xiàn)
setTimeout實(shí)現(xiàn)setInterval
函數(shù)柯里化
防抖 節(jié)流
數(shù)據(jù)結(jié)構(gòu)
單鏈表
設(shè)計(jì)模式
發(fā)布訂閱模式
JS原生API實(shí)現(xiàn)
bind()?call()?apply()
InstanceOf
new
reduce()?forEach()
Promise
HTTP請求
AJAX封裝
JSONP
DOM
事件代理
document.getElementById("father-id").onclick=function(event){
event=event||window.event
lettarget=event.target||event.srcElement
//可以自己打印一下event.target.nodeName,看看是什么
if(target.nodeName.toLowerCase()==='xxx'){
//事件內(nèi)容
}
}
數(shù)組 對象
扁平化
functionflatten(arr){
letresult=[]
for(leti=0,len=arr.length;i
if(Array.isArray(arr[i]))?{
result=result.concat(flatten(arr[i]))
}else{
result.push(arr[i])
}
}
returnresult
}
去重 -?unique()
functionunique(arr){
letappeard=newSet()
returnarr.filter(item=>{
//創(chuàng)建一個(gè)可以唯一標(biāo)識對象的字符串id
letid=item+JSON.stringify(item)
if(appeard.has(id))?{
returnfalse
}else{
appeard.add(id)
returntrue
}
})
}
拷貝
淺拷貝
functioncopy(obj){
letresult=Array.isArray(obj)?[]:{}
Object.keys(obj).forEach(key=>result[key]=obj[key])
returnresult
}
otherStar={...star}
Object.assign({},star)
深拷貝
copy()函數(shù)實(shí)現(xiàn)
處理了循環(huán)引用和key為symbol類型的情況
functioncopy(obj,appeard=new?Map()){
if(!(objinstanceofObject))returnobj//如果是原始數(shù)據(jù)類型
if(appeard.has(obj))returnappeard.get(obj)//如果已經(jīng)出現(xiàn)過
letresult=Array.isArray(obj)?[]:{}
appeard.set(obj,result)//將新對象放入map
//遍歷所有屬性進(jìn)行遞歸拷貝
;[...Object.keys(obj),...Object.getOwnPropertySymbols(obj)]
.forEach(key=>result[key]=copy(obj[key],appeard))
returnresult
}
JSON.stringify
只能處理純JSON數(shù)據(jù)
有幾種情況會發(fā)生錯(cuò)誤
包含不能轉(zhuǎn)成 JSON 格式的數(shù)據(jù)
循環(huán)引用
undefined,NaN, -Infinity, Infinity 都會被轉(zhuǎn)化成null
RegExp/函數(shù)不會拷貝
new Date()會被轉(zhuǎn)成字符串
new=JSON.parse(JSON.stringify(old))
字符串
去除空格 -?trim()
functionmyTrim(str){
returnstr.replace(/(^\s+)|(\s+$)/g,'')//將前空格和后空格替換為空
}
functionmyTrim(str){//記錄前后空格的個(gè)數(shù),最后對字符串進(jìn)行截取
letfirst=0,last=str.length
for(letiinstr)?{
if(str[i]==='?')?{
first++
}else{
break
}
}
for(leti=last;i>first;i--)?{
if(str[i]==='?')?{
last--
}else{
break
}
}
returnstr.substr(first,last-first)
}
字符串全排列
廣度優(yōu)先實(shí)現(xiàn)
functioncombine(str){//抽出一個(gè)字符s,對其余的進(jìn)行排列,將s放在每種排列開頭
if(str.length===1)return[str]
letresults=[]
for(letiinstr)?{
for(letsofcombine(str.slice(0,i)+str.slice(1+(+i))))?{
results.push(str[i]+s)
}
}
//可能會出現(xiàn)類似"aa"=>[aa,aa,aa,aa]的情況,需要去重
return[...newSet(results)]
}
深度優(yōu)先實(shí)現(xiàn)
functioncombine(str){//記錄已經(jīng)使用過的字符,深度優(yōu)先訪問所有方案
letresult=[]
;(function_combine(str,path=''){
if(str.length===0)returnresult.push(path)
for(letiinstr)?{
_combine(str.slice(0,i)+str.slice((+i)+1,str.length),path+str[i])
}
})(str)
//可能會出現(xiàn)類似"aa"=>[aa,aa,aa,aa]的情況,需要去重
return[...newSet(result)]
}
排序和查找
插入排序
functionsort(arr){//原地
for(letiinarr)?{//選一個(gè)元素
while(i>0&&arr[i]
[arr[i],arr[i-1]]=[arr[i-1],arr[i]]
i--
}
}
}
歸并排序
functionsort(arr){
if(arr.length===1)returnarr
//分成兩部分
letmid=Math.floor(arr.length/2)
let[part1,part2]=[sort(arr.slice(0,mid)),sort(arr.slice(mid))]
//對比+合并
letresult=[]
while(part1.length>0&&part2.length>0)
result.push((part1[0]
return[...result,...part1,...part2]
}
快速排序
functionsort(arr){
if(arr.length<=1)returnarr
//選基準(zhǔn)值
letmid_pos=arr.length>>1
letmid=arr.splice(mid_pos,1)[0]
letleft=[],right=[]
//和基準(zhǔn)值比較,分別插入left,right數(shù)組
arr.forEach(item=>(item<=mid?left:right).push(item))
return[...sort(left),mid,...sort(right)]//遞歸調(diào)用排序
}
二分查找
functionsearch(arr,target){//循環(huán)寫法,不斷移動左右指針,縮小范圍
letleft=0,right=arr.length-1
while(left<=right)?{
constmid_pos=Math.floor((left+right)/2)
constmid_val=arr[mid_pos]
if(target===mid_val)?{
returnmid_pos
}elseif(target>mid_val)?{
left=mid_pos+1
}else{
right=mid_pos-1
}
}
return-1
}
找出出現(xiàn)次數(shù)最多的元素 -?getMostItem()
functiongetMost(arr){
//計(jì)數(shù)
letmap=newMap()
arr.forEach(item=>{
if(map.has(item))?{
map.set(item,map.get(item)+1)
}else{
map.set(item,1)
}
})
//找出出現(xiàn)最多
let[max_vals,max_num]=[[arr[0]],map.get(arr[0])]
map.forEach((count,item)=>{
if(count>max_num){
max_vals=[item]
max_num=count
}else{
max_vals.push(item)
}
})
returnmax_vals
}
console.log(getMost(['1','2','3','3','55','3','55','55']))
功能函數(shù)實(shí)現(xiàn)
setTimeout實(shí)現(xiàn)setInterval
functionmyInterval(fn,interval,...args){
letcontext=this
setTimeout(()=>{
fn.apply(context,args)
myInterval(fn,interval,...args)//別忘了為它傳入?yún)?shù)
},interval)
}
myInterval((num)=>console.log(num),500,10)
函數(shù)柯里化
functionsum(...args1){
returnfunction(...args2){
return[...args1,...args2].reduce((p,n)=>p+n)
}
}
console.log(sum(1,2,2)(7))
防抖 節(jié)流
實(shí)現(xiàn)了兩個(gè)加工方法,返回一個(gè)加工后的防抖/節(jié)流函數(shù)
防抖
functiondebounce(fn,delay){
lettimer=null
returnfunction(){
if(timer)?clearTimeout(timer)
timer=setTimeout(()=>fn.call(...arguments),delay)//別忘了為它傳入?yún)?shù)
}
}
節(jié)流
functionthrottle(fn,delay){
letflag=true
returnfunction(){
if(!flag)return
flag=false
setTimeout(()=>{
fn(...arguments)//別忘了為它傳入?yún)?shù)
flag=true
},delay)
}
}
數(shù)據(jù)結(jié)構(gòu)
單鏈表
functionNode(element){//結(jié)點(diǎn)類
[this.element,this.next]=[element,null]
}
classLinkList{//鏈表類
constructor()?{
this.length=0
this.head=newNode()
this.tail=newNode()
this.head.next=this.tail
}
get_all()?{
letresult=[]
letnow=this.head
while(now.next!==this.tail)?{
now=now.next
result.push(now.element)
}
returnresult
}
unshift(element)?{//開頭添加
letnode=newNode(element)
node.next=this.head.next
this.head.next=node
}
shift(){//開頭刪除
letnode=this.head.next
this.head.next=this.head.next.next
returnnode.element
}
}
letlist=newLinkList()
list.unshift(15)
list.unshift(16)
list.unshift(17)
console.log(list.shift())//17
console.log(list.get_all())//[?16,?15?]
設(shè)計(jì)模式
發(fā)布訂閱模式
classObserver{
constructor()?{
this.events={}//事件中心
}
publish(eventName,...args)?{//發(fā)布=>調(diào)用事件中心中對應(yīng)的函數(shù)
if(this.events[eventName])
this.events[eventName].forEach(cb=>cb.apply(this,args))
}
subscribe(eventName,callback)?{//訂閱=>向事件中心中添加事件
if(this.events[eventName])?{
this.events[eventName].push(callback)
}else{
this.events[eventName]=[callback]
}
}
unSubscribe(eventName,callback)?{//取消訂閱
if(events[eventName])
events[eventName]=events[eventName].filter(cb=>cb!==callback)
}
}
JS原生API實(shí)現(xiàn)
bind()?call()?apply()
apply()
Function.prototype.myApply=function(context,args){
context.fn=this//為context設(shè)置函數(shù)屬性
letresult=context.fn(...args)//調(diào)用函數(shù)
deletecontext.fn//刪除context的函數(shù)屬性
returnresult
}
call()
//除了...args
//和apply都一樣
Function.prototype.myCall=function(context,...args){
context.fn=this
letresult=context.fn(...args)
deletecontext.fn
returnresult
}
bind()
Function.prototype.myBind=function(context,args1){//使用[閉包+apply]實(shí)現(xiàn)
return(...args2)=>this.apply(context,[...args1,...args2]);
}
InstanceOf
functionmyInstanceOf(son,father){//沿著父親的原型鏈向上查找是否有兒子的原型
while(true)?{
son=son.__proto__
if(!son)returnfalse
if(son===father.prototype)returntrue
}
}
myInstanceOf([],Array)//?true
new
functionmyNew(constructor_fn,...args){
//構(gòu)造新的空對象
letnew_obj={}
new_obj.__proto__=constructor_fn.prototype
letresult=constructor_fn.apply(new_obj,args)
//如果構(gòu)造函數(shù)沒有返回一個(gè)對象,則返回新創(chuàng)建的對象
//如果構(gòu)造函數(shù)返回了一個(gè)對象,則返回那個(gè)對象
//如果構(gòu)造函數(shù)返回原始值,則當(dāng)作沒有返回對象
returnresultinstanceofObject?result:new_obj
}
functionAnimal(name){
this.name?=?name;
}
letanimal?=?myNew(Animal,'dog');
console.log(animal.name)//?dog
reduce()?forEach()
reduce()
api用法:
arr.reduce(function(prev,?cur,?index,?arr){},?initialValue)
實(shí)現(xiàn):
Array.prototype.myReduce=function(fn,init_val){
let[val,idx]=init_val?[init_val,0]:[this[0],1]//設(shè)置初始值
for(leti=idx,len=this.length;i
val=fn(val,this[i],i,this)//循環(huán)并迭代結(jié)果
}
returnval
}
console.log([1,2,3,4,5].reduce((pre,item)=>pre+item,0))//?15
forEach()
api用法:
[1,3,5,7,9].myForEach(function(item,index,arr){
console.log(this)
},15)
實(shí)現(xiàn):
Array.prototype.myForEach=function(fn,temp_this){
for(leti=0,len=this.length;i
fn.call(temp_this,this[i],i,this)//循環(huán)數(shù)組元素,為回調(diào)函數(shù)傳入?yún)?shù)
}
}
Promise
Promise.all()
Promise.prototype.all=function(promiseList){
returnnewPromise((resolve,reject)=>{
if(promiseList.length===0)returnresolve([])
letresult=[],count=0
promiseList.forEach((promise,index)=>{
Promise.resolve(promise).then(value=>{
result[index]=value
if(++count===promiseList.length)?resolve(result)
},reason=>reject(reason))
})
})
}
ES6所有API完整實(shí)現(xiàn)
通過Promise/A+ test測試
實(shí)現(xiàn)細(xì)節(jié)過多,還請參照Promise/A+規(guī)范閱讀
也可以直接參考我關(guān)于promise的筆記
深入理解promise
https://blog.csdn.net/weixin_43758603/article/details/109641486
classPromise{
constructor(task)?{
this.status="pending"
this.value=undefined
this.reason=undefined
this.fulfilled_callbacks=[]
this.rejected_callbacks=[]
try{
task(this._resolve,this._reject)
}catch(error)?{
this._reject(error)
}
}
then(onFulfilled,onRejected){
if(this.status==='fulfilled')?{
letpromise2=newPromise((resolve,reject)=>{
setTimeout(()=>{
try{
if(!this._isFunction(onFulfilled))?{
resolve(this.value)
}else{
this._resolvePromise(promise2,onFulfilled(this.value))
}
}catch(error)?{
reject(error)
}
},0)
})
returnpromise2
}elseif(this.status==='rejected')?{
letpromise2=newPromise((resolve,reject)=>{
setTimeout(()=>{
try{
if(!this._isFunction(onRejected))?{
reject(this.reason)
}else{
this._resolvePromise(promise2,onRejected(this.reason))
}
}catch(error)?{
reject(error)
}
},0)
})
returnpromise2
}elseif(this.status==='pending')??{
letpromise2=newPromise((resolve,reject)=>{
this.fulfilled_callbacks.push(()=>{
try{
if(!this._isFunction(onFulfilled))?{
resolve(this.value)
}else{
this._resolvePromise(promise2,onFulfilled(this.value))
}
}catch(error)?{
reject(error)
}
})
this.rejected_callbacks.push(()=>{
try{
if(!this._isFunction(onRejected))?{
reject(this.reason)
}else{
this._resolvePromise(promise2,onRejected(this.reason))
}
}catch(error)?{
reject(error)
}
})
})
returnpromise2
}
}
catch=onRejected=>this.then(null,onRejected)
finally=onFinished=>this.then(onFinished,onFinished)
staticdeferred(){
letdeferred={}
deferred.promise=newPromise((resolve,reject)=>{
deferred.resolve=resolve
deferred.reject=reject
})
returndeferred
}
staticresolve(value)?{
if(valueinstanceofPromise)returnvalue
returnnewPromise(resolve=>resolve(value))
}
staticreject=reason=>{returnnewPromise((resolve,?reject)=>reject(reason))}
staticall(promiseList)?{
returnnewPromise((resolve,reject)=>{
if(promiseList.length===0)returnresolve([])
letresult=[],count=0
promiseList.forEach((promise,index)=>{
Promise.resolve(promise).then(value=>{
result[index]=value
if(++count===promiseList.length)?resolve(result)
},reason=>reject(reason))
})
})
}
staticrace(promiseList)?{
returnnewPromise((resolve,reject)=>{
if(promiseList.length===0)returnresolve()
promiseList.forEach(promise=>{
Promise.resolve(promise)
.then(value=>resolve(value),reason=>reject(reason))
})
})
}
staticallSettled(promiseList)?{
returnnewPromise(resolve=>{
letresult=[],count=0
if(len===0)returnresolve(result)
promiseList.forEach((promise,i)=>{
Promise.resolve(promise).then(value=>{
result[i]={
status:'fulfilled',
value:value
}
if(++count===promiseList.length)?resolve(result)
},reason=>{
result[i]={
status:'rejected',
reason:reason
}
if(++count===promiseList.length)?resolve(result)
})
})
})
}
_resolve=value=>{
if(this.status!=='pending')return
setTimeout(()=>{
this.status?='fulfilled'
this.value?=?value
this.fulfilled_callbacks.forEach(cb=>cb(this.value))
},0)
}
_reject=reason=>{
if(this.status!=='pending')return
setTimeout(()=>{
this.reason?=?reason
this.status?='rejected'
this.rejected_callbacks.forEach(cb=>cb(this.reason))
},0)
}
_isFunction=f=>Object.prototype.toString.call(f).toLocaleLowerCase()==='[object?function]'
_isObject=o=>Object.prototype.toString.call(o).toLocaleLowerCase()==='[object?object]'
_resolvePromise(promise,x){
if(promise===x)?{
promise._reject(newTypeError('cant?be?the?same'))
return
}
if(xinstanceofPromise)?{
if(x.status==='fulfilled')?{
promise._resolve(x.value)
}elseif(x.status==='rejected')?{
promise._reject(x.reason)
}elseif(x.status==='pending')?{
x.then(value=>{
this._resolvePromise(promise,value)
},reason=>{
promise._reject(reason)
})
}
return
}
if(this._isObject(x)||this._isFunction(x))?{
letthen
try{
then=x.then
}catch(error)?{
promise._reject(error)
return
}
if(this._isFunction(then))?{
letcalled=false
try{
then.call(x,value=>{
if(called)return
called=true
this._resolvePromise(promise,value)
},reason=>{
if(called)return
called=true
promise._reject(reason)
})
}catch(error)?{
if(called)return
promise._reject(error)
}
}else{
promise._resolve(x)
}
}else{
promise._resolve(x)
}
}
}
module.exports?=Promise
HTTP請求
AJAX封裝
functionajax(method,url,params,callback){
//對參數(shù)進(jìn)行處理
method=method.toUpperCase()
letpost_params=null
letget_params=''
if(method==='GET')?{
if(typeofparams==='object')?{
lettempArr=[]
for(letkeyinparams)?{
tempArr.push(`${key}=${params[key]}`)
}
params=tempArr.join('&')
}
get_params=`?${params}`
}else{
post_params=params
}
//發(fā)請求
letxhr=newXMLHttpRequest()
xhr.onreadystatechange=function(){
if(xhr.readyState!==4)return
callback(xhr.responseText)
}
xhr.open(method,url+get_params,false)
if(method==='POST')
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
xhr.send(post_params)
}
ajax('get','https://www.baidu.com',{id:15},data=>console.log(data))
JSONP
functionjsonp(url,?params_obj,?callback){
//創(chuàng)建一個(gè)供后端返回?cái)?shù)據(jù)調(diào)用的函數(shù)名
letfuncName?='jsonp_'+?Data.now()?+Math.random().toString().substr(2,5)
//將參數(shù)拼接成字符串
if(typeofparams==='object')?{
lettemp=[]
for(letkeyinparams)?{
temp.push(`${key}=${params[key]}`)
}
params=temp.join('&')
}
//在html中插入<script>資源請求標(biāo)簽
letscript=document.createElement('script')
script.src=`${url}?${params}&callback=${funcName}`
document.body.appendChild(script)
//在本地設(shè)置供后端返回?cái)?shù)據(jù)時(shí)調(diào)用的函數(shù)
window[funcName]=data=>{
callback(data)
deletewindow[funcName]
document.body.removeChild(script)
}
}
//使用方法
jsonp('http://xxxxxxxx',{id:123},data=>{
//獲取數(shù)據(jù)后的操作
})
js插入html中標(biāo)簽的內(nèi)容
后端返回的<script>資源的內(nèi)容
funcName('datadatadatadatadatadatadatadata')