中高级面试题题目合集
Posted Vicky沛沛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了中高级面试题题目合集相关的知识,希望对你有一定的参考价值。
题目合集持续更新ing~
- 前端基础github地址。
README.md
可以下载到typora
中打开,会有整个大纲目录显示(github中markdown目录快捷生成方式不现实,之后可能会想办法生成贴过来,暂时不做相关处理) - 前端基础gitbook地址。
README.md
中会实时更新进度内容。gitbook!gitbook
版本可建议后期碎片化时间进行复习使用。 - 前端基础csdn地址。
CSDN
博客专栏前端自我修养进阶中,也会一篇一篇实时更新相关知识点。 - 前端基础一掘金地址、前端基础二掘金地址
⭐️就是最好的鼓励哦wink~💗
文章目录
5.20
1、作用域和值类型引用类型的传递
作用域
var num1 = 11;
var num2 = 22;
function fn(num,num1)
//num,num1会计作用域中变量,分别传入时候只为11,22
num = 100;
num1 = 100;
num2 = 100; //没有用var声明,不是块作用域中变量,那么修改的就是全局的num2
console.log(num) //100
console.log(num1) //100
console.log(num2) //100
fn(num1,num2)
console.log(num1) //11
console.log(num2) //100
console.log(num) //undefined报错
值类型、引用类型的传递
function Person(name,age,salary)
this.name = name;
this.age = age;
this.salary = salary;
function f1(person)
//执行f1(p)的时候person的地址和p的地址指向同一个内存地址,因此修改person.name会修改p.name
person.name = "ls"
person = new Person('aa',18,10) //此时重新将person指向另外一个引用地址,所以跟p无关,不修改p值
var p = new Person('zs',18,10000)
console.log(p.name) //zs
f1(p)
console.log(p.name) //ls
2、封装函数进行字符串驼峰命名
- 已知有字符串类似
get-element-by-id
格式,写一个function将其转化成驼峰命名表示法getElementById
function fn(str)
var arr = str.split('-');
for(let i = 1;i<arr.length;i++)
arr[i] = arr[i].charAt(0).toUpperCase()+arr[i].substr(1,arr[i].length-1)
return arr.join(''); //数组拼接成字符串
3、冒泡排序
function bubble(arr)
for(let i = 0;i < arr.length;i++)
for(let j = 0;j < arr.length - 1 -i;j++)
if(arr[j]>arr[j+1])
[arr[j],arr[j+1]] = [arr[j+1],arr[j]];
return arr;
4、反转数组
- 示例:比如数组
[1,2,3,4,5,6,7,8]
反转数组之后的结果是[8,7,6,5,4,3,2,1]
- 类似于首位交换
0 len-1
1 len-1 -1
2 lem-1 -2
function fn(arr)
for(let i = 0;i < arr.length/2;i++)
[arr[i],arr[arr.length -1 -i]] = [arr[arr.length -1 -i],arr[i]]
return arr
5、数组去重
- Set
function fn(arr)
return Array.from(new Set(arr))
- 一项一项去拿,然后和其后面形成的数组进行对比
function fn(arr)
for(let i = 0;i < arr.length;i++)
let val = arr[i],
compareArr = arr.slice(i); //取出i之后的所有项组成的数组
if(compareArr.indexOf(val)>-1) //如果后面存在这个值
arr.split(i,1)
arr.length--;
i--;
return arr;
function fn(arr)
for(let i = 0;i < arr.length;i++)
let val = arr[i],
compareArr = arr.slice(i); //取出i之后的所有项组成的数组
if(compareArr.indexOf(val)>-1) //如果后面存在这个值
arr[i] = null;
arr = arr.filter((item)=>return item != null)
- 先排序再去重
function fn(arr)
arr = arr.sort((a,b)=>return a-b); //升序
for(let i = 0;i < arr.length-1;i++) //倒数第一项不用去跟后面一项进行对比
if(arr[i] === arr[i+1])
arr.split(i,1)
arr.length--;
i--;
return arr;
6、js综合面试题
- 变量提升,函数提升。变量提升:变量名提升;函数提升:函数整体提升
- this指向问题
- 变量常用规则,变量沿着作用域链进行查找
- 运算符优先级关系:点运算优先级最高,但是遇到
()
没有办法进行运算,所以会记那个前面整体先进性运算 - 实例对象属性规则,原型原型链
//涉及变量提升、函数提升;
function Foo()
getName = function()alert(1) //修改了全局的
return this;
Foo.getName = function()alert(2)
Foo.prototype.getName = function()alert(3)
var getName = function()alert(4)
function getName()alert(5)
//输出如下结果
Foo.getName() //2
getName() //4
Foo().getName() //1 this指向window,window.getName()
getName() //1
new Foo.getName(); //2
new Foo().getName(); //3
new new Foo().getName(); //3
7、nodejs事件轮询
-
libuv
-
事件轮询机制
- 定时器阶段:计时到点的计时器
- pending callback:做系统操作,tcp错误等
- idle、prepare准备工作
- 轮询阶段:轮询队列
- 轮询队列不为空:一次去除回调函数中的第一个函数,先进先出。知道轮询队列为空或者达到最大限制(轮询队列为空:设置过SetImmidiate函数直接进入下一个check阶段;没有设置过,那么就在当前poll等待,直到轮询队列添加进来新的函数,就会去第一个情况执行。如果定时器到点,那么也会去执行下一个阶段)
- check查阶段:执行setImmediate设置的回调函数
- close callback:关闭阶段。close事件的回调函数在这个阶段进行。
-
process.nextTick
能在任意阶段优先执行
setTimeout(function()
console.log(1)
,0)
setImmediate(function()
console.log(2)
)
process.nextTick(function()
console.log(3)
)
//nextTick timeout immediate
8、从url输入
-
DNS解析。域名解析成IP。先读取浏览器DNS缓存,读取系统DNS缓存,读取路由器DNS缓存,网络运营商缓存,递归搜索
-
TCP三次握手:
- 浏览器告诉服务器要发送请求
- 服务器告诉浏览器准备接收
- 浏览器告诉服务器马上就发送请求
-
发送请求:请求报文
-
接受响应:响应报文
-
渲染页面
- 遇见html标记,浏览器调用HTML解析器解析解析并且构建成dom树
- 遇见style/link,浏览器调用css解析起解析并且构建成cssom树
- 遇到script会调用js解析器,处理script代码(绑定事件,修改dom树/cssom树)
- 合并dom树和cssom树成渲染树
- 根据渲染树进行计算布局,计算每个节点的几何信息(布局)
- 将各个节点颜色绘制到屏幕上(渲染 )
- 注意:这五个不一定按照顺序执行,如果dom树或者cssom树被修改了,可能会执行多次布局和渲染。
-
断开链接:四次挥手。
- 浏览器发送给服务器:我请求报文完了,关闭
- 服务器告诉浏览器:我准备关闭
- 服务器告诉浏览器:响应报文发送完了,准备关闭
- 浏览器告诉服务器:客户端准备关闭
9、闭包
-
函数嵌套
-
内部函数使用外部函数的局部变量
-
优点:延长外部函数局部变量的生命周期;缺点:内存泄漏
-
合理使用闭包,及时销毁
function fun(n,o)
console.log(o) //执行var a = fun(0)时候o没有定义,undefined
return
fun:function(m)
return fun(m, n); //这个fun是window的fun也就是全局的fun
//a中存的是同一个返回方法,是同一个fun(m,n),此时存的n都是第一次的0,后面也只是改m所以n都是0,o打印都为0
var a = fun(0) //结果给a赋值返回一个对象fun:function()...
a.fun(1) //0
a.fun(2) //0
a.fun(3) //0
//注意这里区别于上面,这里每次执行完之后保存的n都是上一次返回的n
var b = fun(0).fun(1).fun(2).fun(3) //undefined 0 1 2
//同理:
var d = fun(0).fun(1).fun(2).fun(3).fun(67).fun(45) //undefined 0 1 2 3 67
var c = fun(0).fun(1) //undefined 0 此后c上的n保存变成了1
c.fun(2) //1
c.fun(3) //1
10、变量提升&上下文
变量提升
- js引擎在代码执行之前会做预处理工作
- 收集变量:var声明的变量定义,但是不赋值
- 收集函数:function声明的函数就提前定义函数
console.log(username) //undefined
var username = 'smileyqp'
fun(); //正常执行函数
function fun()
console.log('inner func')
执行上下文(excute context)
- 理解:代码执行的环境
- 时机:代码正式执行之前会进入到执行环境
- 创建变量对象(变量提升)
- 变量
- 函数及函数的参数
- 全局:window
- 局部变量对象
- 确认this指向
- 全局window
- 局部:调用其的对象
- 创建作用域链
- 父级作用域链+当前的变量对象
- 扩展:执行上下文可以认为是一个大的对象,这个对象中主要包含
- 变量对象:变量、函数、函数的形参
- 作用域链Scopechain:父级作用链+当前作用域对象
- this:window||调用其的对象
- 创建变量对象(变量提升)
11、宏任务和微任务
js是单线程的,所以我们可以称之为主线程,也就是我们的js代码都是在主线程上完成的。祝不过我们区分任务是同步还是异步,如果是异步的话,那么它会有一个回调函数。 回调函数:定时器的回调、ajax请求的回调、对应事件的回调(比如点击事件)。不同的任务又会交给不同的模块去处理,比如:定时器模块、网络请求模块、事件处理模块。
js事件轮询机制,js是单线程的
- 宏任务:setTimeout 、setInterval、requestAnimationFrame
- 宏任务所处的队列就是宏任务队列
- 第一个宏任务队列中只有一个任务、执主线程的js代码
- 宏任务队列可以哟欧多个
- 微任务:New Promise().then(两个回调函数 )、process.nextTick
- 微任务所处的队列就是微任务队列
- 只有一个微任务队列
- 上一个宏任务执行完成之后如果有微任务就会执行微任务队列中所有任务
- 当宏任务重的任务执行完成之后会此案去查看微任务队列中是否有任务,如果有就先执行微任务队列中的任务,如果没有的话就继续执行下一个宏任务
//主线程宏任务执行打印1-5 微任务队列执行打印then中console setTimeout宏任务执行
console.log('start')
setTimeout(()=>
console.log('setTimeout')
,0)
new Promise((resolve,reject)=>
for(var i = 0;i<=5;i++)
console.log(i)
resolve()
).then(()=>
console.log('promise实例成功回调')
)
console.log('end')
//输出:
// start 1 2 3 4 5 end promise实例成功回调 setTimeout
12、React和Vue
相同点
- 都是组件化开发
- 虚拟dom
- 都支持通过属性的方式去进行父子组件之间通信
- 数据驱动:更新状态数据,界面会自动更新,不用直接操作dom
- 支持服务器渲染
- 支持原生应用方案:react native(react)、weex(vue)
不同点
-
数据绑定:vue中是双向数据绑定,也就是界面和内存的数据可以双向交流;而react只支持从内存到界面,不支持从界面到内存
-
组件书写方式不一样:react采用JSX(JSX是js的扩展语法,react提出all in js)而vue使用的是模版(也就是在html中去写js、css再通过webpack的loader去对他们进行打包)
-
状态变化:react中调用
setState
;vue中直接通过this.xxx
去更新data中的数据 -
虚拟dom的底层实现不是完全一样:vue会去跟踪每一个组件的依赖关系、不需要重新渲染整个组件树;而对于react而言,一旦状态改变,全部组件都会重新去渲染所以react中需要
shouldComponentUpdate
这个生命周期方法去进行控制 -
react严格上来说是MVC的view层,而view则是mvvm模式的
13、Redux状态管理机制
基本理解:
- redux是一个独立的状态管理js库,不是react的插件库
- 可以用在react、vue、angular等项目中,但是大多情况与react配合使用
- 作用:集中管理react组件中共享数据的状态
Redux 使用扩展
- react-redux简化编码
- redux-thunk实现redux的一步编程。以及redux-saga
- redux-devtools实现chrome中redux的调试
5.21
14、vue组件间通信的方式
- 父向子通信
- 子向父通信
- 兄弟组件通信
- 隔代组件通信
实现通信方式
- props
- 标一般属性(父向子)、函数属性(子向父)
- 隔代通信比比较麻烦:需要逐级传递;兄弟组件通信需要通过父组件传递
- Vue自定义事件:
- 绑定监听(子胥见在父组件中调用的时候绑定监听)
<My-component @eveName="callback"/>
- 触发(分发)事件
this.$emit('eveName',data )
- 只适合子组件向父组件通信
- 绑定监听(子胥见在父组件中调用的时候绑定监听)
- 消息订阅与发布(例如:pubsub-js )
- 订阅消息
- 发布消息
- 适用于任意关系的组件通信
- Vuex(vue的状态管理的插件库)
- slot:专门用来父向子传递带数据的标签
15、vuex状态管理机制
16、Vue的MVVM的实现
- 模板解析
- 解析大括号表达式
- 解析指令
- 数据绑定
- 更新显示实现:数据劫持
17、重绘、重排(回流)
- 先把dom节点生成dom树(解析dom)
- 生成cssom(解析css)
- 布局:构成渲染树render tree(从根节点递归,布局)
- 绘制:绘制div等到页面上
重绘(repaint):一个元素外观的改变所触发的浏览器的行为,浏览器会根据元素的新属性重新绘制,使元素呈现新外观
回流(重排、重构reflow):当渲染树的一部分因为元素的尺寸、布局、隐藏等改变而需要重新构建称之为重排
重绘和重排的关系:在重排的过程中,浏览器会使渲染树中收到影响的部分失效,并且重新去构造这部分渲染树,完成重排之后,浏览器会重新绘制受影响的部分到屏幕中,该部分称为重绘。
重排(回流)一定会重绘,但是重绘不一定会重排。(重排=>布局 重绘=>样式)
触发重排的条件
- 页面渲染初始化
- 添加删除可见dom元素
- 元素位置改变或者使用动画
- 元素尺寸的改变——大小、外边距、边框
- 浏览器窗口尺寸的变化(resize事件发生时)
- 填充内容的改变,比如文本的改变导致的计算值的宽高改变
- 读取某些元素属性(读取宽高offsetTop/Top/Height/width等)
重绘或者重排的代价:耗时、导致浏览器卡顿
重绘重排优化
- 浏览器自己的优化:浏览器会维护一个队列,把所有会引起重绘或者重排的操作放入这个队列,等队列中的操作到了一定的哦时间间隔或者一定数量的时候,浏览器就会flush队列进行一个个处理,这样就会让多次回流和重绘便车个一次
- 我们也可以合并多次对dom的操作以及对样式的修改为一次,并且减少对style的样式请求
- 直接改变元素的className
- 先设置元素的
display:none
然后进行页面布局等操作,设置完成之后再将display:block
这样的话就之后出现两次重绘和重排 - 使用cloneNode(ture or false)和replace技术只引发一次重绘和重排
- 将需要毒刺重排的元素的
position
设置成absolte或者fixed,使其脱离文档流,那么它的变化不会影响到其他元素 - 如果要插入多个dom节点可以创建一个documentFragment创建完成之后一次性加入document
var fragment = document.createDocumentFragment()
for(let i = 0;i<=1000;i++)
var li = document.createElement('i')
li.innerHTML = i + '</br>'
fragment.append(li)
document.getElementById('container').appendChild(fragment)
5.22
18、ES6的class
//class就是构造函数的一种新写法,可以视作语法糖
class Person
constructor(name,age)
this.name = name;
this.age = age;
say()
console.log(`$this.name$this.age岁`)
let p = new Person('smileyqp',18);
p.say()
console.log(p.name)
class Teacher extends Person
constructor()
super()
hello()
console.log('say hi')
19、async、await使用与原理
- 异步情况:定时器、ajax、事件处理、nodejs、读取文件也有异步
let p = new Promise((resolve,reject)=>
resolve(1);
)
//这里的function就是promise中调用的resolve。那么上面掉哟哦那个resolve(1),data参数就是1
p.then(function(data)
console.log('success',data) //success 1
)
-
Promise减少嵌套关系,是一个链式编程的结果
-
axios就是把ajax用promise封装了一下
-
async、await最简单的使用就是省去then的步骤,改成类似同步的过程,等待成功才会执行下面。方便、可读性强、异步改成类似同步写法
-
async和await其实是generator和yield的语法糖。async、await使得代码清晰。
-
Generator里面的代码是分段执行。看到yield就分段暂停。
function *helloGenerator()
yield 'hello';
yield 'world';
yield 'ending';
var hw = helloGenerator();
console.log(hw); //这个函数的结果并不是摁钉,因为代码是暂停的。是一个暂停标记,标记指向'hello'等结果
console.log(hw.next()) //hello
console.log(hw.next().next()) //world
console.log(hw.next().next().next()) //ending
console.log(hw.next().next().next().next()) //undefined
- 拓展
Promise.all
和Promise.race
Promise.all
必须数组里面的所有promise执行完毕,才成功。用在要很多结果都执行成功的情况。Promise.race
只要数组里面的一个成功,整个race就成功执行
Promise.all([p1,p2,p3...],function)
Promise.race([p1,p2,p3...],function)
20、ts在项目中的使用
- ts是js的一个超集,支持ES6标准
- ts比js有更严格的类型要求。有类型的约束,减少大型项目中的bug
- 示例:
msg!:string
msg是非空字符串;msg?:string
msg有可能有欲呕可能没有
21、ES6装饰器的使用
- 装饰器:是一种与类相关的语法,用来注释和修改类和类相关的方法和属性。许多面向对象的语言都有这个功能。一般和类class 相关,普通的方法不要去使用
- 装饰器是一种函数,写法是
@函数名
,它可以放在类和类的方法定义前。装饰器就是执行函数,给类或者类下面的属性方法加一些控制条件 - 装饰器
- 给类或者类属性驾驶一些其他代码
- 可以代码复用
@decorator
class A()
//等同于
class A()
//decorator是一个函数,相当于调用它给A类可以加上一些其他代码,加上属性等
A = decorator(A)
//实例.在类或者类属性方法上写上@函数名,就相当于调用这个函数
function testfunc(target)
target.isok = true; //相当于Myclass.isok = true
console.log('i am test func',target)
@testfunc
class Myclass
function readonly(target,name,descriptor)
console.log(target) //当前的class,即Person
console.log(name) //装饰的属性或方法名
//configuerable修改、enumerable枚举是否可for in循环、writeable、value对象属性默认值
console.log(descriptor)
return descriptor;
class Person
@readonly
abc()
console.log('add func ')
5.23
22、事件循环
异步:定时器、ajax、onclick、promise(new Promise立刻执行,then异步)
- 宏任务:定时器(setTimeout、setInterval)、requestAnimationFrame、I/O
- 微任务:process.nextTick、Promise、Object.observe、MutationObserver
- 宏任务队列和微任务队列,执行主线程任务,宏任务放到宏任务队列,微任务放到微任务队列。只有在微任务队列中的微任务全部执行完成之后才会去执行下一个宏任务。注意:执行宏任务的时候,也会产生微任务,继续执行上面过程
console.log('1')
setTimeout(function()
console.log('2')
new Promise(function(resolve)
console.log('3')
resolve()
).then(function()
console.log('4')
)
)
new Promise(function(resolve)
console.log('5')
resolve()
).then(function()
console.log('6')
)
setTimeout(function()
console.log('7')
new Promise(function(resolve)
console.log('8')
resolve()
以上是关于中高级面试题题目合集的主要内容,如果未能解决你的问题,请参考以下文章
Android 大厂高级面试必问36题以及算法合集(附:2022年Android 中高级面试题汇总以及面试题解析)
Android面试复习框架及题型解析,最新Android中高级面试题合集
Android面试复习框架及题型解析,最新Android中高级面试题合集
面试大厂必备~2021高级架构Java面试点解析+最新Java中高级面试题合集震撼来袭!
干货Android BAT高级面试必问36题以及算法合集(附:46份面试题+49份源码解析笔记+145份项目实战PDF)