一些web前端面试题的总结

最近呢,出去面试了几家公司,就此记录一下我印象比较深刻的一些问题吧:

在ES5下实现const的功能(还问了const定义的对象和数组能否修改,为什么)

var const_=function (varName,value){
    window.varName=value;
    Object.defineProperty(window,varName,{
        enumerable:false,
        configurable:false,
        get:function(){
            return value;
        },
        set:function(data){
            if(data!==value){
                throw new TypeError('不允许修改');
            }else{
                return value;
            }
        }   
    })
}
const_('a',20);
a=30;//报错

vue是怎么实现数据的双向绑定(其实这个和上面的问题是一个知识点)

这个和上面的方法是一样的,通过监听对象上的get和set,从而实现在修改数据的时候及时判断是否需要更新。这也是为啥每次console vue中的数据是打印出来的都是getter和setter具体的代码就不写了,差不多的

纯函数相关,涉及到react

纯函数的标准定义百度即可,我的理解就是:吃啥吐啥,雷打不动,React中的纯组件(或者说是函数式组件)就是一个纯函数,给我啥数据我显示啥视图,贼稳。再比如Redux中的reducer也是纯函数,负责处理action提供的数据。React文档中就说过,react特别执着于纯函数。

关于数据转换的问题(这类型问题两个公司都问了,感觉是比较关键的点)

这个是真的没想到,一年前我面试的时候还没这类型的问题,感觉自己答的不是很好。。。心态炸裂啊

就举第二家公司的例子吧:

后台给你返回的数据是:[{year:2000,month:1,day:11,birth:200}]这种格式的,计算出每年每个月出生的人数以及在当年的占比,并且能够在视图中展现

假设初始数据是:
arr: [
        {year:2000,month:1,day:11,birth:200},
        {year:2000,month:1,day:11,birth:20},
        {year:2010,month:2,day:22,birth:100},
        {year:2000,month:1,day:11,birth:200},
        {year:2012,month:3,day:11,birth:200},
        {year:2004,month:4,day:11,birth:200},
        {year:2013,month:10,day:11,birth:200},
        {year:2017,month:7,day:11,birth:200},
        {year:2019,month:7,day:11,birth:200},
        {year:2018,month:8,day:11,birth:200},
        {year:2005,month:12,day:11,birth:200},
        {year:2005,month:11,day:11,birth:200},
        {year:2004,month:1,day:11,birth:200},
        {year:2000,month:10,day:11,birth:200},
        {year:2016,month:11,day:11,birth:200},
      ];
// 不使用lodash
let years=arr.map(item=>item.year);
let yearsUnique=[...new Set(years)];
let yearMonths=yearsUnique.map(item=>{
    var monthArr=[];
    var yeartotal=0;
    arr.map(citem=>{
      if(citem.year==item){
        yeartotal+=citem.birth;
        if(monthArr.length<=0){
          monthArr.push({month:citem.month,birth:citem.birth});
        }else{
          monthArr.forEach((mitem,index)=>{
            if(mitem.month==citem.month){
              monthArr[index].birth=citem.birth+mitem.birth;
            }else{
              monthArr.push({month:citem.month,birth:citem.birth});
            }
          })
        }
          
      }
    })
    monthArr.forEach(item=>{
      item.precent=(Math.round((item.birth/yeartotal)*100))+'%'
    })
    return {year:item,month:monthArr,yearBirth:yeartotal};
})
// 最终结果
[
    { 
        "year": 2000, 
        "month": [ 
                    { "month": 1, "birth": 420, "precent": "68%" }, 
                    { "month": 10, "birth": 200, "precent": "32%" } 
                 ], 
        "yearBirth": 620 
    },
    { 
        "year": 2010, 
        "month": [ 
                    { "month": 2, "birth": 100, "precent": "100%" }
                 ], 
        "yearBirth": 100 
    },
    .
    .
    .
]
// 使用lodash
const yearsMonths=arr.map(item=>{
      return {year:item.year,month:item.month}
    });
const yearsMonthsUnique=_.uniqWith(yearsMonths,_.isEqual);

let res=yearsMonthsUnique.map(item=>{
    var yeartotal=0;
    var monthTotal=0;
    arr.map(citem=>{
      if(item.year==citem.year){
        yeartotal+=citem.birth;
        if(item.month==citem.month){
          monthTotal+=citem.birth;
        }
      }
    })
    return {year:item.year,month:item.month,yearBirth:yeartotal,monthBirth:monthTotal};
})
res.sort(function(prev,next){
    if(prev.year===next.year){
      return prev.month-next.month;
    }else{
      return prev.year-next.year;
    }
})
// 最终结果(percent 再map一遍即可)
[
    { "year": 2000, "month": 1, "yearBirth": 620, "monthBirth": 420 }
    { "year": 2000, "month": 10, "yearBirth": 620, "monthBirth": 200 }
    { "year": 2004, "month": 1, "yearBirth": 400, "monthBirth": 200 }
    { "year": 2004, "month": 4, "yearBirth": 400, "monthBirth": 200 }
    { "year": 2005, "month": 11, "yearBirth": 400, "monthBirth": 200 }
    { "year": 2005, "month": 12, "yearBirth": 400, "monthBirth": 200 }
    { "year": 2010, "month": 2, "yearBirth": 100, "monthBirth": 100 }
    { "year": 2012, "month": 3, "yearBirth": 200, "monthBirth": 200 }
    { "year": 2013, "month": 10, "yearBirth": 200, "monthBirth": 200 }
    { "year": 2016, "month": 11, "yearBirth": 200, "monthBirth": 200 }
    { "year": 2017, "month": 7, "yearBirth": 200, "monthBirth": 200 }
    { "year": 2018, "month": 8, "yearBirth": 200, "monthBirth": 200 }
    { "year": 2019, "month": 7, "yearBirth": 200, "monthBirth": 200 }
]

说实话,这些数据转换的题有时候是真的烧脑,感觉贼绕

关于闭包

也是一道题:f()=''; f('a')()='a'; f('a')('b')()='ab'; f('a')('b')('c')()='abc'·····实现一个类似这种的函数

function ff(s){
	var str='';
	function f(params){
        if(params){
			str+=params;
            return arguments.callee;
        }else{
            return str;
        }
    }
	return f(s);
}
ff('a')('b')('c')()//'abc'

// 这个主要是考察对闭包的理解

2019-08-23

浏览器的缓存处理

浏览器缓存就是在访问页面或者是发送get请求时,浏览器会记住当前输出的内容,当再次通过相同的URL访问的时候,浏览器会根据缓存机制决定是否使用缓存的副本进行响应。比如你访问某个页面的时候,再次通过相同的URL访问,如果页面的输出内容没有变化,就会使用浏览器缓存的副本。

清除浏览器缓存的一些方法:

1.通过设置meta标签使得每次访问页面的时候都会重新加载页面的内容,而不是使用缓存中的副本

<META HTTP-EQUIV="pragma" CONTENT="no-cache"> 
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">

2.发送get请求时,通过设置请求头来重新获取响应的数据

$.ajax({
   url:'请求路径',
   dataType:'json',
   type:'get',//默认值即为get
   data:{},
   beforeSend :function(xmlHttp){ 
    xmlHttp.setRequestHeader("If-Modified-Since","0"); 
    xmlHttp.setRequestHeader("Cache-Control","no-cache");
   },
   success:function(response){
     
   }
 });

3.每次发送请求时,url后跟不同的查询参数,当url不一样时,不会使用缓存的副本。例如在请求路径后加随机数,或者是时间戳等。

react高阶组件,见过那些高阶组件

高阶组件就是接收一个组件作为参数,最终返回一个组件,即对已有的组件进行扩展或者修改。高阶组件的实现方式主要有两种:1.属性代理,通过修改覆盖接收组件的props对其进行重新的渲染2.反向继承,通过继承接收的组件来对其props,方法进行修改

 redux的connect方法就是一个高阶组件,react-router中也用到了高阶组件

react纯组件和普通组件的区别

 纯组件自己实现了shouldUpdateComponent方法,进行props和state的浅比较,如果没有变化的话不会进行render;

普通组件需要自己手动实现shouldUpdateComponent

react版本区别及对应的生命周期变更

 使用递归和非递归分别实现阶乘

 instanceof相关的用法

 浏览器从输入url到渲染页面发生了什么

 浏览器为什么要阻拦跨域请求

 不使用JSON.stringify()实现将复杂对象转换为字符串

 两个有序数组,实现一个函数,返回两个数组合并后的中位数

 ‘use strict’;

function a(){
    this.x=1;
    console.log(this);
}
function b(fn){
    fn();
}

new a();

a();

b(a);

分别输出什么

 console.log('one');

setTimeout(function(){

    console.log('two');

},0);

Promise.resolve().then(function(){

    console.log('three');

})

console.log('four');

输出顺序是什么?

持续更新中。。。。

发布了47 篇原创文章 · 获赞 38 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/qq8241994/article/details/98638279