初级前端面试题(二)之 JavaScript

1.  手写节流、防抖

节流【相当与技能冷却中,或者用户频繁点击按钮】

//假设你要实现技能冷却中,要怎么实现?
//假设你要调用闪现,但是在闪现过程中的120秒内你再次调用闪现,不会做任何事情,因为正在冷却中


const d=(distance)=>{ //闪现的函数
   console.log('闪现')
},

//实现任意函数的节流
const abcFn=(f,time)=>{
  let timer=null;
  let lengQue=false; 
   return (...args)=>{
      if(lengQue){
    return
  }else{
     f(...args);//调用闪现的函数
     lengQue=true;
     timer=setTimeout(() => {
        // 方法区
        lengQue= false;
        timer=null
      }, time);
  }
     
   }
}

//调用函数
const da=abcFn(d,120*1000)

防抖【相当于回城,或者拖动页面时】

//打断后重新计时

const f=()=>{
  console.log('回城成功');
}

const debounce=(f,time)=>{
 let timer=null;
 return (...args)=>{
   if(timer!=null){
     clearTimerout(timer); //清空timer
   }else{
      timer=setTimerout(()=>{
         f(...args);
         timer=null
      },time)
   }
 }
 
}

//调用
const tp=debounce(f,3000)
tp(); //3秒之后才会‘回城成功’



2. 手写发布订阅

发布订阅是非常著名的设计模式。

    例如:你刷博客之类的,遇到感兴趣的会去关住他,去看他的内容,但他下次发布新内容时,网站会通过一些方法通知到我们,我们也会在第一时间了解到这些新内容,但至于会不会第一时间去看就起决于我们自己了。

const eventHub={
   //queue:[] //一般使用q来代表数组
   queueMap:{}, //在js里用空对象表示哈希表
    on:(name,fn)=>{
      eventHub.queueMap[name]=eventHub.map[name]||[];//取他的第name个,如果是空的就初始化(取后面  的 值)
      eventHub.queueMap[name].push(fn)
   //return undefined
   },
    emit:(name,data)=>{ //把队列里的东西调用一下
        const q=eventHub.queueMap[name]
        if(!q){return}  //判断是否为空,若为空,就短路了什么也不用做
        q.map(f=>f(data) //遍历。foreach、map但map有返回值
        return undefined},
    off:(name,fn)=>{
        //这是只是读,可以给eventHub.queueMap[name]做别名
      if(!eventHub.queueMap[name]){return}
      const index=eventHub.map[name].indexOf(fn)
        if(index<0){return } //短路法
        eventHub.map[name].splice(index,1) //splice 是设置要删除的索引
      }
}
//监听两次click,调用两次函数
eventHub.on('click',console.log)
eventHub.on('click',console.error)

//3秒钟后触发click
setTimeout(()=>{ 
    eventHub.emit('click','frank')
},3000)

3. 深浅拷贝

  • 浅拷贝:只拷贝一层 object.assign(target,sources);
  • 深拷贝:不会只传地址,而会开辟一个新的空间,复制给另一个空间,拷贝完的空间给了要赋值的那个

参考:【js进阶】-深浅拷贝_js深拷贝-CSDN博客

// 手写深拷贝


var obj = {
    id: 1,
    name: 'andy',
    msg: {
        //这是对象
        age: 18
    },
    color: ['pink', 'red'] //这是数组
};
var o = {};
//封装一个函数
function deepCp(newobj, oldobj) {
    //先遍历一遍obj
    for (var k in oldobj) {
        //我们要判断属性值是属于哪一种类型
        //所以,第一步:获取属性值
        var item = oldobj[k];
        //第二步:判断这个值是不是数组
        if (item instanceof Array) {
            newobj[k] = [];
            deepCp(newobj[k], item);
        } else if (item instanceof Object) {
            //第三步:判断是不是对象类型
            newobj[k] = {};
            deepCp(newobj[k], item); //运用递归,把原对象属性值给新对象
        } else {
            //第四步:如果都不是,这就是简单数据类型,直接复制就可
            newobj[k] = item;
        }
    }
}
deepCp(o, obj); //调用函数
//解答:为什么先判断是不是数组后判断是不是对象,因为对象包括数组

4. promise

(1)  地址ES6 入门教程

(2)  概念:promise 是异步编程的一种解决方案。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。promsie 一旦创建会立即执行,无法中途取消。promsie对象必须返回then方法。可以说then方法是promise的核心。一个promise对象可以注册多个then方法,且回调函数返回的顺序和注册的顺序保持一致。

(3)  三种状态:pending (进行中)          resoloved (已完成)                   rejected (已失败)

(4)  基本用法:

const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});


promise 
  .then(function (a){})
  .catch(function(error){})
  .finally(()=>{})

ps: finally优点: 1)成功和失败的情况只需要写一次; 2)会返回原来的值

(5) 常用方法:

5.1  Promise.all([p1,p2])

1)都返回resolve(); 才能够拿到成功的返回值;

2)有一个返回reject(), 则进入catch(error), 拿到失败的返回值。

//手写promise.all

 let list=[1,3,5,6,4]
 promise.myall=function(list){
	 const results=[];
	 let count=0;
	 return new promise((resolve,reject)=>{
		 list.map((item,index)=>{
			 item.then(result=>{
				 results[index]=result;
				 count+=1;
				 if(count>=list.length){resolve(results)}
			},reason=>reject(reason))
		})
	})
}

5.2  promise.race([p1,p2,p3])

     只要p1p2p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。

5.3  promise.allSettled()

     只有等到参数数组的所有 Promise 对象都发生状态变更(不管是fulfilled还是rejected),返回的 Promise 对象才会发生状态变更。

5.4  promsie.any()

   Promise.any()Promise.race()方法很像,只有一点不同,就是Promise.any()不会因为某个 Promise 变成rejected状态而结束,必须等到所有参数 Promise 变成rejected状态才会结束.

5. 扩展运算符

对象扩展运算符 (...)

let ab={a:"erer",b:123};
let ac={... ab}; // 等价于 let ac=Object.assign({},ab)
console.log(ac); //{a: 'erer', b: 123}

6.手写ajax

//首先申明一个对象
var xhr =new XMLHttpRequest()
//发请求发到哪个地方呢(路径)
xhr.open('GET','/XXX')
//监听onreadystatechange事件
xhr.onreadystatechange=function()
{
    if (xhr.readyState == 4) //4是下载操作已完成
    {     //看它的状态码,如果在这个区间内说明成功了
        if (xhr.status >= 200 && xhr.status < 300||xhr.status===304) 
        {
            success(xhr)
        }
        else
        {
            fail(xhr)
        }
    }
};
//一般是全都设置好之后再发送,所以习惯吧send写在最下面    
//设置请求体,get一般是空的,post是传一个json数据
xhr.send('{"name":"frank"}')

  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值