最近呢,出去面试了几家公司,就此记录一下我印象比较深刻的一些问题吧:
在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标签使得每次访问页面的时候都会重新加载页面的内容,而不是使用缓存中的副本
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');
输出顺序是什么?
持续更新中。。。。