美文网首页
手撕前端面试代码题

手撕前端面试代码题

作者: friendshi洛初Udo邭 | 来源:发表于2020-12-21 13:05 被阅读0次

    目录

    DOM

    事件代理

    数组 对象

    扁平化

    去重 - unique()

    拷贝

    浅拷贝

    深拷贝(copy()函数实现、JSON.stringify)

    字符串

    去除空格 - trim()

    字符串全排列

    广度优先实现

    深度优先实现

    排序和查找

    插入排序

    归并排序

    快速排序

    二分查找

    找出出现次数最多的元素 - getMostItem()

    功能函数实现

    setTimeout实现setInterval

    函数柯里化

    防抖 节流

    数据结构

    单链表

    设计模式

    发布订阅模式

    JS原生API实现

    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'){

    //事件内容

    }

    }

    数组 对象

    扁平化

    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=>{

    //创建一个可以唯一标识对象的字符串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()函数实现

    处理了循环引用key为symbol类型的情况

    functioncopy(obj,appeard=new Map()){

    if(!(objinstanceofObject))returnobj//如果是原始数据类型

    if(appeard.has(obj))returnappeard.get(obj)//如果已经出现过

    letresult=Array.isArray(obj)?[]:{}

    appeard.set(obj,result)//将新对象放入map

    //遍历所有属性进行递归拷贝

    ;[...Object.keys(obj),...Object.getOwnPropertySymbols(obj)]

    .forEach(key=>result[key]=copy(obj[key],appeard))

    returnresult

    }

    JSON.stringify

    只能处理纯JSON数据

    有几种情况会发生错误

    包含不能转成 JSON 格式的数据

    循环引用

    undefined,NaN, -Infinity, Infinity 都会被转化成null

    RegExp/函数不会拷贝

    new Date()会被转成字符串

    new=JSON.parse(JSON.stringify(old))

    字符串

    去除空格 - trim()

    functionmyTrim(str){

    returnstr.replace(/(^\s+)|(\s+$)/g,'')//将前空格和后空格替换为空

    }

    functionmyTrim(str){//记录前后空格的个数,最后对字符串进行截取

    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)

    }

    字符串全排列

    广度优先实现

    functioncombine(str){//抽出一个字符s,对其余的进行排列,将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)

    }

    }

    //可能会出现类似"aa"=>[aa,aa,aa,aa]的情况,需要去重

    return[...newSet(results)]

    }

    深度优先实现

    functioncombine(str){//记录已经使用过的字符,深度优先访问所有方案

    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)

    //可能会出现类似"aa"=>[aa,aa,aa,aa]的情况,需要去重

    return[...newSet(result)]

    }

    排序和查找

    插入排序

    functionsort(arr){//原地

    for(letiinarr) {//选一个元素

    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

    //选基准值

    letmid_pos=arr.length>>1

    letmid=arr.splice(mid_pos,1)[0]

    letleft=[],right=[]

    //和基准值比较,分别插入left,right数组

    arr.forEach(item=>(item<=mid?left:right).push(item))

    return[...sort(left),mid,...sort(right)]//递归调用排序

    }

    二分查找

    functionsearch(arr,target){//循环写法,不断移动左右指针,缩小范围

    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

    }

    找出出现次数最多的元素 - getMostItem()

    functiongetMost(arr){

    //计数

    letmap=newMap()

    arr.forEach(item=>{

    if(map.has(item)) {

    map.set(item,map.get(item)+1)

    }else{

    map.set(item,1)

    }

    })

    //找出出现最多

    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']))

    功能函数实现

    setTimeout实现setInterval

    functionmyInterval(fn,interval,...args){

    letcontext=this

    setTimeout(()=>{

    fn.apply(context,args)

    myInterval(fn,interval,...args)//别忘了为它传入参数

    },interval)

    }

    myInterval((num)=>console.log(num),500,10)

    函数柯里化

    functionsum(...args1){

    returnfunction(...args2){

    return[...args1,...args2].reduce((p,n)=>p+n)

    }

    }

    console.log(sum(1,2,2)(7))

    防抖 节流

    实现了两个加工方法,返回一个加工后的防抖/节流函数

    防抖

    functiondebounce(fn,delay){

    lettimer=null

    returnfunction(){

    if(timer) clearTimeout(timer)

    timer=setTimeout(()=>fn.call(...arguments),delay)//别忘了为它传入参数

    }

    }

    节流

    functionthrottle(fn,delay){

    letflag=true

    returnfunction(){

    if(!flag)return

    flag=false

    setTimeout(()=>{

    fn(...arguments)//别忘了为它传入参数

    flag=true

    },delay)

    }

    }

    数据结构

    单链表

    functionNode(element){//结点类

    [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 ]

    设计模式

    发布订阅模式

    classObserver{

    constructor() {

    this.events={}//事件中心

    }

    publish(eventName,...args) {//发布=>调用事件中心中对应的函数

    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实现

    bind() call() apply()

    apply()

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

    context.fn=this//为context设置函数属性

    letresult=context.fn(...args)//调用函数

    deletecontext.fn//删除context的函数属性

    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]实现

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

    //构造新的空对象

    letnew_obj={}

    new_obj.__proto__=constructor_fn.prototype

    letresult=constructor_fn.apply(new_obj,args)

    //如果构造函数没有返回一个对象,则返回新创建的对象

    //如果构造函数返回了一个对象,则返回那个对象

    //如果构造函数返回原始值,则当作没有返回对象

    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)

    实现:

    Array.prototype.myReduce=function(fn,init_val){

    let[val,idx]=init_val?[init_val,0]:[this[0],1]//设置初始值

    for(leti=idx,len=this.length;i

    val=fn(val,this[i],i,this)//循环并迭代结果

    }

    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)

    实现:

    Array.prototype.myForEach=function(fn,temp_this){

    for(leti=0,len=this.length;i

    fn.call(temp_this,this[i],i,this)//循环数组元素,为回调函数传入参数

    }

    }

    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完整实现

    通过Promise/A+ test测试

    实现细节过多,还请参照Promise/A+规范阅读

    也可以直接参考我关于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){

    //对参数进行处理

    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

    }

    //发请求

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

    //创建一个供后端返回数据调用的函数名

    letfuncName ='jsonp_'+ Data.now() +Math.random().toString().substr(2,5)

    //将参数拼接成字符串

    if(typeofparams==='object') {

    lettemp=[]

    for(letkeyinparams) {

    temp.push(`${key}=${params[key]}`)

    }

    params=temp.join('&')

    }

    //在html中插入<script>资源请求标签

    letscript=document.createElement('script')

    script.src=`${url}?${params}&callback=${funcName}`

    document.body.appendChild(script)

    //在本地设置供后端返回数据时调用的函数

    window[funcName]=data=>{

    callback(data)

    deletewindow[funcName]

    document.body.removeChild(script)

    }

    }

    //使用方法

    jsonp('http://xxxxxxxx',{id:123},data=>{

    //获取数据后的操作

    })

    js插入html中标签的内容

    后端返回的<script>资源的内容

    funcName('datadatadatadatadatadatadatadata')

    相关文章

      网友评论

          本文标题:手撕前端面试代码题

          本文链接:https://www.haomeiwen.com/subject/ozsrnktx.html