js相关面试题
####1、map、reduce、filter、every、some 用法与区别?ES6 中的数组方法你知道哪些?
map 映射,执行遍历一个数组,把原数组内的每一项进行一系列操作,return返回一个新数组,原数组不变,如果没有返回则得到一个所有值为undefined的数组([undefined,undefined,undefined]) map方法不需要定义变量来接收最后的数组结果,本身这个方法运行后的结果就是新数组,这个方法也可进行判断,找到其中的一项,然后进行操作,再进行返回,就得到改变后的数组了 reduce 将这个方法定义为数组的归并方法,这个方法和迭代方法(map,forEach,filter...)一样,都会对数组进行遍历,reduce与他们不同的是函数的第一个参数得到的是迭代计算后的效果,返回一个自定义的数据,对原数组不会产生操作 (多用于求和、求乘积、去重、数组转化为对象、映射过滤等等)。
let newArr = arr.reduce(function(prev,curVal,index,arr){
.........
return prev // 返回prev给newArr
},迭代初始值)
cur => 当前的元素
index => 当前元素的索引
arr => 原数组
迭代初始值 => 可以是数组、空对象、空数组等(可传可不传,若是不传,那么首次迭代的初始值就是第一个元素)
最后,要将迭代的结果进行返回return,还需要定义变量进行接收这个迭代后的结果
filter 筛选到符合条件的所有数据对象 返回一个新数组(符合条件的所有项) ,不会改变原数组,这个方法本身运行后的结果就是一个筛选后的新数组
find 筛选符合条件的第一个数据对象 返回的是符合条件的第一项的值 ,不会改变原数组,这个方法本身运行后的结果就是得到的那一个数据项
every 返回这个数组全部都符合条件的bool值,全部匹配则返回真 some 返回这个数组部分符合条件的bool值,只要有有一个存在,则返回为真
for...of 不同用于forEach方法,它可以与break、continue和return配合使用。提供了遍历所有数据结构的统一操作接口
splice 截取或添加数组项,arr.splice(从哪个地方截取,需要截取的元素个数) 包括起始位置和末尾位置 => 会改变原数组 arr.splice(a,b) => 得到的是截取下来的数据,以数组的形式,原来的arr数组也会发生改变(被截取的数据消失)
keys 返回一个新的数组
,entries,slice,from,forEach
快速伪造一个数组:Array(10).fill('').map((item,index)=> {return {对每一项的操作}})
####2、数组去重的方法?
① 使用indexOf去重 => 新建一个空的结果数组,for 循环原数组,判断结果数组是否存在当前元素,如果有相同的值则跳过,即array.indexOf() === -1 => 不相同则push进结果数组
② 使用includes去重 => 具体操作同上
③ 递归去重 => 将一列数组,从末尾开始,两个数进行比较,看是否相等,若相等则去掉末尾的那个数据(用splice截取,splice方法会改变原数组)
④ new Set() Set是一个构造函数,是ES6新增的语法,类似于数组,它的特性是所有的元素都是唯一的,所以可以进行数组去重,可以使用add() delete() has() clear()进行增删改查等 去重转数组:Array.from()或者使用展开运算符[...new Set([2,3,3,4])]
###3、本地储存有哪些 自身特性和区别?
localStorage、sessionStorage、cookie local本地存储,不会自动删除,需要手动清除数据,存储大小大致在5M左右 session会话存储,在完成会话后,会自动清理掉数据,存储大小大致在5M左右 cookie是用户解决http无状态的一种方式,会随请求一起发送到后端,不适合用来存储数据,存储大小大致在4K左右,Cookie 的作用是与服务器进行交互,作为 HTTP 规范的一部分而存在
###4、拷贝管理?什么是浅拷贝、深拷贝?主要是对栈、堆等理解
对数据进行赋值的功能
JS浅拷贝与深拷贝只针对的是数组(Array)和对象(Object)两种引用数据类型。引用类型的数据在内存中分两部分存储,分别是存储在栈中的引用地址和存储在堆中的数据。简单点来说就是:假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝,自食其力
浅拷贝其实拷贝的是引用类型数据的地址,两个对象共享堆中的数据,一个对象改变了某个属性值,另一个对象的属性值也会跟着改变。而深拷贝则会同时拷贝引用地址和数据,之后两个对象之间是完全独立的,互不影响。
浅拷贝--只执行一次遍历,如果这个对象中,某个key是数据对象,则会出现对象引用的问题 var a = {a0: 10, a1: 20, a2: {a20: 50, a21: 70}} 浅拷贝:for (let name in a) { b[name] = a[name] } 深拷贝--使用递归或JSON.parse(JSON.stringify())来实现深拷贝,这个方法会导致数据中的方法函数属性丢失 var b = {b0: 20, b1: function() { console.log('this is b1 function') }, b2: 60} var c = JSON.parse(JSON.stringify(b)) c.b1 === undefined
注意:数组的slice方法和concat方法都不是深拷贝
###5、怎么判断是否为数组?
原型链顶端(终点)是null
ES5 可以使用:instanceof(需要先判断是否为Array) 和 Object.prototype.toString.call(数据对象) 结果类型是:=> ['Object','Array'] ES6 可以使用:constructor 构造函数 constructor
属性的含义就是指向该对象的构造函数,所有函数(此时看成对象了)最终的构造函数都指向Function => Object.prototype.constructor(数据对象)
###6、ES6的导入导出功能的实现方法有哪些?
导出:export const/let/function; export {key}; export default -- 默认导出 导入:import Obj from 'path' -> export default; import {} from 'path' -> export const/let/function; export {key}; import * as Obj from 'path' -> export const/let/function; export {key}; CommonJS、ES5的
导出:exports.key = const/let/function;module.exports = {}/const/let/function 导入:const {} = require('path'); const Obj = require('path');
###7、通过ES6如何定义一个类,并实现继承与传参?
ES6中的class可以看作是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰,更加面向对象编程的语法而已。
在类的内部可以使用 get 和 set 关键字对某个属性设置存储函数和取值函数,拦截该属性的存取行为
使用class来定义一个类,继承并传参会使用到extends和super方法,super作为函数调用时表示父类的构造函数,作为属性时表示父类的一个实例化对象
class Parent{
constructor(name){this.name = name}
say(){console.log(this.name + '说hello')}
}
class Child extends Parent{
constructor(name,age){
// super作为函数调用时表示父类的构造函数
super(name) // 此处的super相当于Parent的构造函数
this.age = 10 }
say(){
console.log(this.age + '岁的' + this.name)
console.log(super.say()) // 继承Parent的方法 此处的super相当于Parent一个实例化
}
}
let a = new Child('jack')
a.say()
打印结果是:Child内的say方法成功打印
###8、求时间的交集和差集?
① 先对这段时间数据进行排序 用数组的sort 方法 arr.sort(function(a,b){return b-a}) 这里的a,b分别指前一项和后一项,若是return的是b-a,则排序出来时从小到大 注意:new Date() 是可以传入参数的,比如:new Date('2021/10/18') => 返回的是:中国标准时间 若是不传参数,则返回的是当前的中国标准时间 取毫秒数:new Date().getTime()
② 排序之后,利用for循环遍历这个时间段数组,根据前一段时间的后一个时间点和后一段时间的前一个时间点进行毫秒数相减,若是大于0,则这两段时间没有交集,有空集,若是小于0,则有交集,没有空集
###9、快速排序实现
快速排序实际上就是冒泡排序的升级版本;添加了一个哨兵,使用哨兵来做对比,如果比哨兵大放右边,小的放左边,然后左边和右边再分开去添加一个哨兵,再去用这些哨兵进行对比.... 在实现的时候,主要用到递归算法 42315 => 3 L 2,1 [3] R 4,5 2,1 => 1 [1] R 2
###10、事件执行捕获过程?几个阶段?
以点击事件为例,当我们点击一个元素之后,浏览器会从顶级的document元素发出一个事件流,然后顺着事件流的方向一层一层的往下找,直到找到触发点击事件的目标元素,这个查找的过程就是捕获(在查找的过程中,若是遇到相同的事件类型,默认都是不会触发的,事件的执行都是在冒泡阶段);在找到这个目标元素之后,触发点击事件,接着就会顺着层级一层一层往上,这个时候若是遇到相同的事件类型,那么就会一次触发事件,这个触发的过程就是冒泡阶段 (捕获 => 从大到小 冒泡 => 从小到大)
使用addEventListener 注册事件,可以决定他是在捕获阶段还是冒泡阶段进行触发 addEventListener('click',function(){},第三个值) => 这里的第三个值就可以决定 若是设置为true则为事件捕获阶段 若是为false 则是事件冒泡阶段(默认是false 即默认是在冒泡阶段触发)
我们给一个dom同时绑定两个点击事件,一个用捕获,一个用冒泡,会执行几次事件,会先执行冒泡还是捕获?
点击目标元素之后,先是进入捕获阶段,从大到小,如果在到达目标元素之前,遇到非目标元素设定是捕获触发,那么这些事件会被触发,直到遇到目标元素,然后触发事件,接着进入冒泡阶段,从小到大,遇到非目标元素设定是冒泡触发,那么这些事件会被触发
总结:给一个节点元素同时绑定两个点击事件,一个捕获,一个冒泡,会先执行捕获,再执行冒泡(在捕获阶段,就检测到一个捕获事件,所以直接触发,最后再在冒泡阶段执行冒泡触发事件)
###11、箭头函数的特性?
箭头函数:let func = () => {}
=> 箭头函数的this指向:永远指向外层函数的this
=> 箭头函数不能用new关键字来进行实例化,即不能做构造函数
=> 没有arguments参数
=> 箭头函数没有原型对象(prototype)
=> 写法简洁,若是此时箭头函数只有一个入参,那么()可以省略不写
=> 对于花括号{ },如果省略不写,那么函数体就只能是一行代码或者一个表达式,而且会自动返回这行代码的值
###12、展开运算符是深拷贝吗?
let a = [1,2,3] let b = [...a] => a,b都是引用数据类型 a == b // false 理解
引用数据类型里面再有一个引用数据类型,能不能用展开运算符实现深拷贝?不能
展开符对于存在复杂数据类型的第一级数据能完成深拷贝,我们可以把他理解为,把拷贝目标对象内的一级值做简单数据类型的声明创建操作,一经展开此时的一级值就存在栈内存里,由此完成深拷贝
###13、promise存在的理由?
在实际项目中,通常这一次的异步请求的结果会作为下一次的异步请求的参数,那么就会通过回调函数的嵌套来处理,但是这样容易造成回调地狱的问题,可读性很差,而且代码也不容易维护。
promise的出现就很好的解决了回调地狱问题,而且还有async+await来进行promise的进一步优化
###14、对于promise,async+await只能处理reslove的结果?
=> async+await是将promise进行优化,将异步代码优化成了同步代码,这样书写更加清晰简洁且方便阅读
=> 对于await promise ,只能接收到成功resolve()的结果,对于reject()的结果是会报错的
=> 解决报错:① 用try catch去捕获异常 ② 通过返回一个处于pending(即将发生)状态时的结果,以此来中断promise链
###15、try catch => 捕获错误/报错机制
try{ 有可能出现错误的代码 }catch(error){ 出错后的处理 }
=> 若try中的内容没有出错,那么在正常执行完try中的内容后,就不会执行catch中的内容
=> 若try中的内容一旦发现出错,那么就会立即执行catch中的内容
=> throw new Error(....) 创建一个错误并抛出一个错误
###16、http状态码
200:请求成功
304: 所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源 ---- 也就是说前端请求的数据已经存在或者已经被缓存,并且没有任何改变,就会返回304
4开头:请求失败 前端出错 ---- 请求包含语法错误或无法完成请求
401:需要用户的身份验证
408:服务器等待客户端发送的请求时间过长,超时
5开头:请求失败 后端出错 ---- 服务器在处理请求的过程中发生了错误
###17、token是什么?
一个已经登录的标识或者票据
###18、函数设置默认值
① 使用 if 语句
function test(b) {
if (!b) b = 'b的默认值'
}
② 使用三元运算符
function test(b) {
b = b ? b : 'b的默认值';
}
③ 使用逻辑或运算符: ||
function test(b) {
b = b || 'b的默认值';
}
④ ES6设置函数参数默认值
使用 = 号对参数设置默认值
function myfunc(message, flag = false) {
}
当flag没有传值(即flag为undefined)时,则会使用后面的默认值,需要注意,函数参数是已经被定义的变量,在函数内部不能再重新定义
###19、模拟一个异步请求
function Ajax(){
return new Promise((reslove) => {
reslove({code : 200,message:'数据请求成功!'})
})
}
###20、var、let、const 定义变量的区别
① var => 有变量提升;有函数作用域的概念;能够重复声明变量,后面声明的会覆盖前面的;可以进行重复赋值
② let => 没有变量提升,所以必须先声明再使用;有块作用域(也包括{},即在{}内声明的变量,在外面不能使用)的概念;不能重复声明变量;可以重复赋值
③ const => 没有变量提升,且在声明的时候就必须要赋值;有块作用域;不能重复声明;赋值后不能再更改;const在此处说不能重新赋值,存在一定的误区,对于引用数据类型,const声明的变量只是相当于一个指针,而const只能保证这个指针是固定的,而其指向的数据是在堆区域内,所以堆区域的数据能不能改变就不是const能控制的了
变量提升: 在正式开始执行程序前,先将var声明的变量,和function声明的函数提前到当前作用域的顶部,集中声明,赋值留在本地;函数的声明比变量的声明更置顶
预解析:在代码解析执行之前,浏览器会先对源代码进行通读,如果遇到声明式(function 函数名(){})函数或者var关键字,会将它提前 JavaScript源代码 ==预解析>> 浏览器解析 => 执行代码 => 结果 注意:在预解析前,如果遇到函数名和var变量同名,则函数优先,再执行var变量赋值,但是是给函数名赋值,更改了函数的性质
###21、同步和异步
同步:前面一个任务执行完成之后,才会执行下一个任务
异步:将异步任务放到另一个线程,然后主线程和副线程同时执行任务,等主线程执行完成之后,才会去发出副线程任务结束的信号,然后再执行响应的结果
###22、setTimeout是异步的吗?
不算是异步,他是被放入到副线程任务列中的(没有阻塞主线程),但是它是等主线程的任务执行完成之后,通过事件循环机制访问到这个定时器,然后再将其放入到主线程再执行
为什么延迟时间不准确?
定时器先会被放入到副线程,然后等待主线程结束后,才会将 定时器再拿到主线程执行,所以定时时间是有延迟的
###23、es6新语法
let、const、箭头函数、展开运算符、解构赋值、class、promise、Symbol、Proxy、async、js的错误处理机制:用过throw => 手动抛出一个错误对象,终止程序向后执行 try - catch => 捕获错误
###24、闭包
一个函数里面再嵌套一个函数,内部函数使用外部函数的数据 --- 例如useEffect钩子函数等就是形成一个闭包,需要注入数据才能有依赖
###25、原型链
构造函数(创建一个对象)、原型对象、实例对象
原型对象:每个函数都有一个原型对象,构造函数也有原型对象 访问原型对象 --- 函数名.prototype属性 访问实例对象 --- 对构造函数new出一个实例对象 实例对象访问原型对象 --- --proto--
原型对象的原型对象 => Object.prototype 指向构造函数 => Object.protype.constructor
###26、双飞翼(圣杯布局)怎么实现? ---- 两边固定,中间自适应
flex布局:两边给其固定宽高,中间flex:1
浮动布局:左右先给宽高,左边左浮动,右边右浮动,中间设置(margin:0 (左右的宽度))
通过绝对定位
###27、promise的三个状态、promise.all
promise的存在原因:解决异步请求时的回调地狱问题
它的三个存在状态:pending(未解决)、resolve(成功后 )、reject(拒绝后)
使用promise的链式写法:需要在其then中再返回一个promise对象
promise.all:接收多个promise回调结果,但是返回一个promise,一旦接收的promise有reject,就会立即抛出错误
###28、宏任务和微任务
宏任务:主线程上的每次执行栈中的代码就是一个宏任务
微任务:前后两个任务执行期间执行的任务
###29、继承的内部实现过程
继承:子类继承父类的属性或者方法等
继承的方式:原型链继承(通过子类的原型对象prototype去继承父类的实例对象)、构造函数继承(使用call或者apply改变this指向,让子类的this指向父类的构造函数)、组合继承
###30、作用域
全局作用域(在页面的任意位置都可以被访问到)和局部作用域
局部作用域(函数作用域):在函数作用域中,函数外部不能访问到内部的变量和方法;在函数作用域中访问变量、函数时,会先在自身作用域中寻找,若没有找到,则会到函数的上一级作用域中寻找,一直到全局作用域
###31、redux的中间件
在简单的redux的数据流的过程中,添加middleware 后,我们就可以在这途中对 action 进行截获,并进行改变 例如:redux-thunk => 适用于异步请求
###32、react的常用组件
类组件
函数组件
无状态组件:无数据状态更新的组件 复用性较强 就相当于一个render
有状态组件:有完整的生命周期,可执行一些数据交互等
高阶组件:入参一个组件返回一个功能更加强大的组件
###33、react中的受控组件和非受控组件
受控组件:比如对于input标签,在react中数据是单向流,所以即便是表单元素有onChange来监听输入框的值,但是它的state数据并没有更新到,那么就需要react来控制监听的数据,对其数据进行更改
非受控组件:不需要控制它的state属性,直接通过ref来控制真实DOM
###34、事件的执行过程,事件循环机制(event loop)
事件执行机制:主线程只会做一件事,就是从消息队列里面取消息、执行消息 ,取一个消息并执行的过程叫做一次循环
###35、盒模型
普通盒子模型:width 和 height 指的是内容区域的宽度和高度。增加内边距、边框和外边距不会影响内容区域的尺寸,但是会增加元素框的总尺寸
IE盒子模型中,width 和 height 指的是内容区域+border+padding的宽度和高度。
###36、类数组
类似于数组,获取每一项的值在写法上是一样的,但是它的构造函数是Object,只不过这个对象的key值是0,1…写出来之后类似数组的下标,所以叫类数组
###37、this 指向
事件处理中:this指向事件源
普通函数中:this指向window对象
定时器中:this指向window对象
普通对象中的this:指向调用该方法的对象
箭头函数中的this:指向上下文this
改变this指向:常用为bind...,还有call和apply
###38、react中性能优化的点在于:
-
调用setState,就会触发组件的重新渲染,无论前后的state是否不同
-
父组件更新,子组件也会自动的更新
实现性能优化:1、代码复用、减少冗长代码 2、antd按需引入组件 3、实现懒加载/动态加载 4、批量更新 对于类组件,setState方法本身就能达到这一个目的,而函数组件却不行,一次只能定义一个状态数据 解决方法:可以使用一个useState保存多个状态数据 ---- 使用API 5、使用数据状态管理器 --- 对于不变的数据,多个页面或组件需要的数据,为了避免重复请求,我们可以将数据放在状态管理里面
###39、useMemo和useCallback
useMemo:用来缓存数据,当组件内部某一个渲染的数据,需要通过计算而来,这个计算是依赖与特定的state、props数据,我们就用useMemo来缓存这个数据,以至于我们在修改她们没有依赖的数据源的情况下,多次调用这个计算函数,浪费计算资源。
useCallback:回调函数仅在某个依赖项改变时才会更新 ,在父组件传递给子组件函数时是非常有用的
useMemo和useCallback的区别:区别在于useMemo返回的是函数运行的结果,useCallback返回的是函数。
useMemo的使用场景:每次组件的state数据进行更新,都会重新定义这个计算函数(返回一个计算结果),但是是没有必要的,会造成内存垃圾等问题,这时候,就需要useMemo这个钩子函数,只有当注入的依赖数据发生变化时,才会重新调用并缓存数据
uaeCallback的使用场景:比如说父组件需要传递一个函数给子组件的时候,由于父组件的多个数据更新会导致该函数重新生成从而传递给子组件的函数引用发生了变化,这就会导致子组件也会更新,而很多时候子组件的更新是没必要的,所以我们可以通过useCallback来缓存该函数,然后传递给子组件
###40、useEffect中不能使用promise+async和await
useEffect的作用就是清除副作用, 它会返回clean-up函数 ,所以不能反回promise函数
###41、ant-design中:为什么更新某个tate 数据就会导致全表渲染?
由于 columns 支持 render方法,因而 Table 无法知道哪些单元会受到影响。你可以通column.shouldCellUpdate来控制单元格的渲染,从而优化性能。
###42、get和post的区别
get和post是http协议(数据在万维网中如何通信的协议)发送请求的两种方式
1、安全性能:get的请求参数会被放入到url地址栏中,post的请求参数是对用户不可见的
2、传入的参数大小:get的参数会被放入到地址栏,所以长度会受到一定的限制(地址栏的最大1024个字节);二post 就没有这个影响
3、传入参数的类型:get只能是字符串方式 而post就可以是各种类型,比如说图片等都可以放入到请求体里进行传输
4、执行效率:get执行效率要高一些
###43、http和https的区别
http:超文本传输协议,前后端进行交互时的数据传输通道
https:http的安全版,传输的数据进行保密封装以及它的完整性等
https是在http上建立ssl加密层,并对数据传输进行加密,是http协议的安全版。它的主要作用是对数据进行加密,并建立一个信息安全通道,保证传输过程中的数据安全,以及对网站服务器进行真实身份认证。HTTPS并不是一种新的协议,只是在通信接口使用了SSL和TLS协议而已。HTTP通常直接和TCP通信,而HTTPS中HTTP先和SSL通信,再由SSL和TCP进行通信。(SSL协议并不是一个应用层协议,它是介于应用层和传输层协议之间的一个安全协议,https采用了它的两种加密方式的混合加密)
###44、setState的异步问题过程
更新state数据,创建新的VNode,通过diff算法对比差异,找出需要决定渲染哪一部分以及怎么渲染,最终形成最新的UI
异步:会将多个setState数据修改方法进行合并,放到一起,然后一起执行
###45、js的执行环境是单线程的:
好处:实现起来比较简单 坏处: 只要有一个任务耗时很长 后面的任务都必须排队等待 会拖延整个程序的执行 如: 浏览器无响应(假死) 往往就是因为某一段代码长时间运行 (如死循环) 导致整个页面都卡在了这个地方 其他代码无法执行
###46、typeScript
一般在大项目中会使用ts,这样能保证数据和方法的类型都是确定的,可控的;对于小项目,不建议使用ts,因为编写代码不够方便 对于ts:会在代码编译的时候就会 报错;对于js:需要运行才能发现错误
###47、git
问过:阐述一个案例,最近在开发中遇到一个问题。自己在代码的主分支拉了一个分支,开始快乐的开发修改了。同事小明也在主分支拉了一个分支,也在快乐的修改。小明的开发速度很快,一个问题很快就解决了,并且把自己的代码,提交合并到主分支了。当我完成自己的工作,去主分支进行代码的合并的时候,发现不能提交了。那么问题了来了,关于我们在开发中遇到的这些问题是如何解决的呢。
一个思路就是:
首先在本地重新创建一个主分支,拉取小明已经提交的主分支的代码到新重建的本地的主分支,然后合并本地主分支和自己分支的代码。遇到冲突解决掉,然后提交自己分支的代码到自己的远程分支,然后在和主分支的代码进行合并。
48、轮询和长链接
轮询:前端以一定的时间间隔向后端发出请求,但是,由于我们并不能确定后端的数据是否有进行改变,从而导致返回的是一个空信息;同理,若是后端有数据更新,但是前端请求又刚好错过,导致不能实时更新
优点:后端开发较为容易 缺点:或许很多请求是无用的,浪费资源 => 小型简单应用
长连接:前端发起一次请求后就挂起,一直到服务端有更新的时候,服务器才会主动推送信息到客户端。如果没有更新信息,那就一直保持连接的状态,客户端不做多余的请求,服务器端也不做响应
优点:无消息的时候,不会频繁请求 缺点:要处理高并发问题 => 网页版应用等
49、作为一个前端开发人员来说,怎么避免浏览器卡顿,实现性能优化cdn?
主要包括网络加载类、页面渲染类、CSS优化类、JavaScript执行类、缓存类、图片类、架构协议类等几类,下面逐一介绍
网络加载类:1、减少http网络请求资源的次数和大小,在前端页面中,通常建议通过构建工具(webpack、gulp等)尽可能合并静态资源图片、JavaScript或CSS代码为一个文件并进行压缩,减少页面请求数和资源请求消耗,这样可以缩短页面首次访问的用户等待时间;2、将CSS或JavaScript放到外部文件中,避免使用<style>或<script>标签直接引入 ;3、为HTML内容设置Cache-Control 或Expires可以将HTML内容缓存起来,避免频繁向服务器端发送请求。在页面Cache-Control或Expires头部有效时,浏览器将直接从缓存中读取内容,不向服务器端发送请求。 <meta http-equiv="Cache-Control" />;4、合理设置Etag和Last-Modified使用浏览器缓存,对于未修改的文件,静态资源服务器会向浏览器端返回304,让浏览器从缓存中读取文件,减少Web资源下载的带宽消耗并降低服务器负载。 <meta http-equiv="last-modified"/>;5、减少页面重定向,页面每次重定向都会延长页面内容返回的等待延时,一次重定向大约需要600毫秒的时间开销,为了保证用户尽快看到页面内容,要尽量避免页面重定向。 6、浏览器在同一时刻向同一个域名请求文件的并行下载数是有限的,因此可以利用多个域名的主机来存放不同的静态资源,增大页面加载时资源的并行下载数,缩短页面资源加载的时间。通常根据多个域名来分别存储JavaScript、CSS和图片文件。 7、使用静态资源CDN来存储文件 ,如果条件允许,可以利用CDN网络加快同一个地理区域内重复静态资源文件的响应下载速度,缩短资源请求时间。 8、CDN Combo是在CDN服务器端将多个文件请求打包成一个文件的形式来返回的技术,这样可以实现HTTP连接传输的一次性复用,减少浏览器的HTTP请求数,加快资源下载速度。例如同一个域名CDN服务器上的a.js,b.js,c.js就可以按如下方式在一个请求中下载。9、使用GET来完成AJAX请求,使用XMLHttpRequest时,浏览器中的POST方法发送请求首先发送文件头,然后发送HTTP正文数据。而使用GET时只发送头部,所以在拉取服务端数据时使用GET请求效率更高。 10、减少Cookie的大小并进行Cookie隔离,HTTP请求通常默认带上浏览器端的Cookie一起发送给服务器,所以在非必要的情况下,要尽量减少Cookie来减小HTTP请求的大小
页面渲染类:1、将css文件放在head头部 这样页面可以优先下载css并完成渲染......
CDN:本质就是一个缓存,CDN能够缓存一般的CSS,js图片等静态资源文件,而且将数据缓存在里用户最近的地方,使用户以最快的速度获取数据
前端项目代码在上传到服务器以后,资源文件往往会很大,而使用的云服务一般带宽都会很小(带宽很贵),所以资源往往需要放到cdn上面来加速,节约服务器的带宽,这里我们使用回源的方式来实现cdn加速
50、webpack构建工具、工程化、里面包的集成是怎么实现的,会进行包压缩优化?
webpack:是前端资源模块化管理和打包工具,一个模块打包器 它的模块化:前端的所有资源文件(css/js/less/img)等都会作为模块化处理 入口:src-index.js 出口:dist-main.js
Webpack的工作方式是:把你的项目当做一个整体,通过一个给定的主文件(如:index.js),Webpack将从这个文件开始找到你的项目的所有依赖文件,使用loaders处理它们,最后打包为一个(或多个)浏览器可识别的JavaScript文件。
loader:让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理
常见loader:html-loader:将HTML文件导出编译为字符串,可供js识别的其中一个模块
babel-loader : 加载ES6+ 代码后使用Babel转义为ES5后浏览器才能解析
typescript-loader : 加载Typescript脚本文件
url-loader : 多数用于加载图片资源,超过文件大小显示则返回data URL
还有各种样式loader
51、css.loader、style.loader、less.loader等的处理顺序是怎样的?
style.loader:处理css样式,将样式挂载到style标签上,必须放在第一个位置,内部执行会创建一个style标签等
css.loader:处理css文件,他必须配合style.loader使用
less.loader:处理less文件,转为css文件,必须放在css.loader后面
注意:loader都是从下往上执行的
配置:ts-loader
52、promise的优缺点
优点:解决回调地狱的问题
缺点:当promise处于pending状态时,不知道当前任务是已经执行完成还是未解决的状态;无法取消,一旦新建,就必须执行,Promise对象的状态改变,只有两种可能: 从pending变为resolved从pending变为rejected。 这两种情况只要发生,状态就凝固了,不会再变了 ;.then中需要返回promise再进行链式调用
promise是将异步转为同步吗? 完全不是,他只是一种易读的编程风格,解决回调地狱
then阶段如何中断? then 块默认会向下顺序执行,return 是不能中断的,可以通过 throw 来跳转至 catch 实现中断
promise适用于:多次顺序执行异步请求的时候
53、闭包的优缺点和使用场景,有什么特性,对页面有什么影响
闭包:就是一个函数里面再嵌套另一个函数,能够改变局部变量的作用域
优点:方便使用上下文的变量;避免某些变量的污染;
缺点:闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。因为闭包会使外层函数作用域中的变量被保存在内存中不被回收,所以如果滥用闭包就会导致性能问题,谨记
使用场景:防抖性能优化 => 需要在外层定义一个变量来保存计时(避免timer值污染),如果这个计时为空,会创建一个定时器,如果不为空,则在时间范围内会进行定时器销毁
54、什么是“前端路由”?什么时候适合使用“前端路由”? “前端路由” 有哪些优点和缺点?
路由是根据不同的 url 地址展示不同的内容或页面 vue-router react-router-dom
前端路由更多用在单页应用上, 也就是SPA, 前端只需要切换组件就可以实现用户的路由跳转,以前是后端进行实现页面的跳转
优点:刷新速度快,复用性强
缺点:不利于浏览器的前进与后退
56、浏览器的解析流程
浏览器真实DOM的解析流程:1、分析html元素,生成dom树(数据结构) 2、分析css文件或者inline样式,生成style样式表 3、将dom树和样式表关联起来,生成render树 4、根据render树,浏览器开始布局,计算dom的精确坐标 5、绘制 => 1/2/3 可同时交叉进行
操作真实dom的代价:比如说浏览器在接收到dom更新的消息之后,如果有10个dom需要更新,那么浏览器在接收到第一个dom请求之后,就会立即执行更新(从重建dom树开始),直到执行10次dom更改之后,才会停止,这样计算dom节点的坐标等都是白白浪费性能,从而造成页面卡顿
虚拟dom的出现:解决浏览器性能问题而出现,同样的如果出现10次更新请求,那么虚拟dom会通过diff算法,将10次更新集中到一起,获取到各个更新的精确坐标,最后再进行一次dom树更新,从而避免不必要的计算量
57、浏览器的缓存机制
http缓存机制:是浏览器的缓存机制
为什么要使用浏览器的缓存机制:浏览器缓存可以在很好的提升页面的性能同时减轻后端服务器的压力
浏览器的缓存类型:强缓存:不会向后端服务器发送送请求,直接从缓存中读取资源
协商缓存:会向后端发送请求,会根据请求头中的参数数据进行判断,当前的请求 是否符合协商缓存,如果符合,则发送请求返回304码,并通知浏览器从缓存中读取资源
两者的共同点都是从客户端缓存中读取资源,区别是强缓存不会发送请求,协商缓存会发送请求
请求头参数(request header): 强缓存:在Cache-Control(缓存控制) : max-age=* => 代表在首次成功获取到数据后 ,如果需要再次加载资源,且在设置的时间范围内,则会命中强缓存;expires也是控制页面失效时间的 协商缓存: ETag和If-None-Match:这两个要一起说。Etag是上一次加载资源时,服务器返回的response header,是对该资源的一种唯一标识,只要资源有变化,Etag就会重新生成。浏览器在下一次加载资源向服务器发送请求时,会将上一次返回的Etag值放到request header里的If-None-Match里,服务器接收到If-None-Match的值后,会拿来跟该资源文件的Etag值做比较,如果相同,则表示资源文件没有发生改变,命中协商缓存。Last-Modified和If-Modified-Since:这两个也要一起说。Last-Modified是该资源文件最后一次更改时间,服务器会在response header里返回,同时浏览器会将这个值保存起来,在下一次发送请求时,放到request header里的If-Modified-Since里,服务器在接收到后也会做比对,如果相同则命中协商缓存。
缓存过程 :1、浏览器首次成功请求后,会将请求的资源和 response header 中的参数和请求的时间进行一并缓存 2、下一次加载资源时,会先进行请求时间对比,如果没有达到过期时间,则命中强缓存,则不发送请求直接从本地缓存中读取数据;如果时间过期,则会发送一个请求头中带有if-Modified-since和If-None-Match的请求 3、服务器收到请求之后,会优先根据Etag的值进行判断,如果一致,则返回304,直接从缓存中拉取之前的数据,如果不一致,则会response响应最新的数据并返回Etag值以及响应码是200 4、如果发出的请求中没有Etag的值,则将If-Modified-Since和被请求文件的最后修改时间做比对,一致则命中协商缓存,返回304;不一致则返回新的last-modified和最新的资源文件并返回200;
用户对浏览器的控制: 1、地址栏访问,链接跳转都是正常的用户行为,将会触发这个浏览器的缓存机制 2、F5刷新,浏览器会跳过强缓存,进行协商缓存判断 3、ctrl + f5 跳过强缓存和协商缓存,直接从服务器拉取数据
设置cache-control:对于图片,css,等长期不变化的内容应该设置较长的过期时间 它的值有:max-age、private、no-cache
浏览器的缓存方式:http缓存(是基于http协议的文件级缓存机制)、session缓存、local缓存
后端服务器的缓存:CDN缓存机制:是后端服务器的缓存, 和Http类似,客户端请求数据时,先从本地缓存查找,如果被请求数据没有过期,拿过来用,如果过期,就向CDN边缘节点发起请求。CDN便会检测被请求的数据是否过期,如果没有过期,就返回数据给客户端,如果过期,CDN再向源站发送请求获取新数据,它也是通过cache-control来控制资源失效时间
57、如何优化网页加载速度?
-
减少 css,js 文件数量及大小(减少重复性代码,代码重复利用),压缩 CSS 和 Js 代码
-
图片的大小
-
把 css 样式表放置顶部,把js 放置页面底部
-
减少 http 请求数
-
使用外部 Js 和 CSS
###58、为什么虚拟 dom 会提高性能?
虚拟 dom 相当于在 js 和真实 dom 中间加了一个缓存,利用 dom diff 算法避免了没有必要的 dom 操作,从而提高性能。
用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,插到文档当中当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异把 2 所记录的差异应用到步骤 1 所构建的真正的DOM 树上,视图就更新了。
react diff 原理(常考,大厂必考)
· 把树形结构按照层级分解,只比较同级元素。
· 给列表结构的每个单元添加唯一的 key 属性,方便比较。
· React 只会匹配相同 class 的 component(这里面的 class 指的是组件的名字)
· 合并操作,调用 component 的 setState 方法的时候, React 将其标记为 dirty.
到每一个事件循环结束, React 检查所有标记 dirty 的 component 重新绘制.
· 选择性子树渲染。开发人员可以重写 shouldComponentUpdate 提高 diff 的性能。
###60、展示组件(Presentationa component) 和容器组件 (Container component)之间有何不同
· 展示组件关心组件看起来是什么。展示专门通过props 接受数据和回调,并且几乎不会有自身的状态,但当展示组件拥有自身的状态时,通常也只关心 UI 状态而不是数据的状态。
· 容器组件则更关心组件是如何运作的。容器组件会为展示组件或者其它容器组件提供数据和行为(behavior),它们会调用 Flux actions,并将其作为回调提供给展示组件。容器组件经常是有状态的,因为它们是(其它组件的)数据源。
###61、类组件(Class component) 和函数式组件(Functional component)之间有何不同
· 类组件不仅允许你使用更多额外的功能,如组件自身的状态和生命周期钩子,也能使组件直接访问 store 并维持状态
· 当组件仅是接收 props,并将组件自身渲染到页面时,该组件就是一个 '无状态组件(stateless component)',可以使用一个纯函数来创建这样的组件。这种组件也被称为哑组件(dumb components)或展示组件
(组件的)状态(state)和属性(props)之间有何不同
· State 是一种数据结构,用于组件挂载时所需数据的默认值。State 可能会随着时间的推移而发生突变,但多数时候是作为用户事件行为的结果。
· Props(properties 的简写)则是组件的配置。props 由父组件传递给子组件, 并且就子组件而言,props 是不可变的(immutable)。组件不能改变自身的props,但是可以把其子组件的 props 放在一起(统一管理)。Props 也不仅仅是数据--回调函数也可以通过 props 传递
###62、何为受控组件(controlled component)
在 HTML 中,类似 <input>, <textarea> 和 <select> 这样的表单元素会维护自身的状态,并基于用户的输入来更新。当用户提交表单时,前面提到的元素的值将随表单一起被发送。但在 React 中会有些不同,包含表单元素的组件将会在 state 中追踪输入的值,并且每次调用回调函数时,如 onChange 会更新 state,重新渲染组件。一个输入表单元素,它的值通过 React 的这种方式来控制,这样的元素就被称为"受控元素"。
###63、何为高阶组件(higher order component)
高阶组件是一个以组件为参数并返回一个新组件的函数。HOC 运行你重用代码、逻辑和引导抽象。最常见的可能是 Redux 的 connect 函数。除了简单分享工具库和简单的组合,HOC 最好的方式是共享 React 组件之间的行为。如果你发现你在不同的地方写了大量代码来做同一件事时,就应该考虑将代码重构为可重用的hoc
###64、为什么建议传递给 setState 的参数是一个 callback 而不是一个对象
因为 this.props 和 this.state 的更新可能是异步的,不能依赖它们的值去计算下一个
state。
###65、除了在构造函数中绑定 this,还有其它方式吗
你可以使用属性初始值设定项(property initializers)来正确绑定回调,create-react- app 也是默认支持的。在回调中你可以使用箭头函数,但问题是每次组件渲染时都会创建一个新的回调。
###66、(在构造函数中)调用 super(props) 的目的是什么
在 super() 被调用之前,子类是不能使用 this 的,在 ES2015 中,子类必须在constructor 中调用 super()。传递 props 给 super() 的原因则是便于(在子类中)能在constructor 访问 this.props。
###67、应该在 React 组件的何处发起 Ajax 请求
在 React 组件中,应该在 componentDidMount 中发起网络请求。这个方法会在组件第一次“挂载”(被添加到 DOM)时执行,在组件的生命周期中仅会执行一次。更重要的是,你不能保证在组件挂载之前 Ajax 请求已经完成,如果是这样,也就意味着你将尝试在一个未挂载的组件上调用 setState,这将不起作用。在componentDidMount 中发起网络请求将保证这有一个组件可以更新了。
###68、描述事件在 React 中的处理方式。 react的事件处理机制
react 的事件机制利用了事件委托机制。事件并没有绑定在真实的 dom 节点上,而是把事件都绑定在结构的最外层 document,使用一个统一的事件监听器。所有的事件都由这个监听器统一分发。
组件挂载和更新时,会将绑定的事件分门别类的放进一个叫做EventPluginHub的事件池里。事件触发时,根据事件产生的Event对象找到触发事件的组件,再通过组件标识和事件类型从事件池里找到对应的事件监听回调,然后执行相关的监听函数。
###69、react 组件的划分业务组件技术组件?
· 根据组件的职责通常把组件分为 UI 组件和容器组件。
· UI 组件负责 UI 的呈现,容器组件负责管理数据和逻辑。
· 两者通过 React-Redux 提供 connect 方法联系起来。
###70、简述 flux 思想
Flux 的最大特点,就是数据的"单向流动"。
-
用户访问 View
-
View 发出用户的 Action
-
Dispatcher 收到 Action,要求 Store 进行相应的更新
-
Store 更新后,发出一个"change"事件
-
View 收到"change"事件后,更新页面
###71、React 项目用过什么脚手架(本题是开放性题目)
creat-react-app Yeoman 等
###72、了解 redux 么,说一下 redux 把
· redux 是一个应用数据流框架,主要是解决了组件间状态共享的问题,原理是集中式管理,主要有三个核心方法,action,store,reducer,工作流程是view 调用 store 的 dispatch 接收 action 传入 store,reducer 进行 state 操
作,view 通过 store 提供的 getState 获取最新的数据,flux 也是用来进行数据操作的,有四个组成部分 action,dispatch,view,store,工作流程是view 发出一个 action,派发器接收 action,让 store 进行数据更新,更新完成以后 store 发出 change,view 接受 change 更新视图。Redux 和 Flux 很像。主要区别在于 Flux 有多个可以改变应用状态的 store,在 Flux 中dispatcher 被用来传递数据到注册的回调事件,但是在 redux 中只能定义一个可更新状态的 store,redux 把 store 和 Dispatcher 合并,结构更加简单清晰
· 新增 state,对状态的管理更加明确,通过 redux,流程更加规范了,减少手动编码量,提高了编码效率,同时缺点时当数据更新时有时候组件不需 要,但是也要重新绘制,有些影响效率。一般情况下,我们在构建多交 互,多数据流的复杂项目应用时才会使用它们
###73、redux 有什么缺点
一个组件所需要的数据,必须由父组件传过来,而不能像 flux 中直接从store 取。
当一个组件相关数据更新时,即使父组件不需要用到这个组件,父组件还是会重新 render,可能会有效率影响,或者需要写复杂的shouldComponentUpdate 进行判断。
74、同源策略
同协议、端口、域名的安全策略,由网景公司提出来的安全协议
75、js 延迟加载的方式有那些?
defer 和 async、动态创建 DOM 方式(用得最多)、按需异步载入 js
76、解释 jsonp 的原理,以及为什么不是真正的 ajax
jsonp 是用来解决跨域获取数据的一种解决方案,具体是通过动态创建 script 标签,然后通过标签的 src 属性获取js 文件中的 js 脚本,该脚本的内容是一个函数调用,参数就是服务器返回的数据,为了处理这些返回的数据,需要事先在页面定义好回调函数,本质上使用的并不是 ajax 技术
动态创建 script 标签,回调函数
Ajax 是页面无刷新请求数据操作
###80、解释什么是 sql 注入,xss 漏洞
xss :跨站脚本攻击,指恶意攻击者往web页面插入恶意脚本代码,而程序对于用户输入内容未过滤,当用户浏览该页面时,嵌入其中的web里面的脚本代码会被执行,从而达到恶意攻击用户的特殊目的。因此,一般在表单提交或者url参数传递前,对需要的参数进行过滤。
###83、列举浏览器对象模型 BOM 里常用的至少 4 个对象,并列举 window 对象的常用方法至少 5 个
常用对象:window document location screen
常用方法:alert() confirm() open() close() addEventLisener
84、你如何对网站的文件和资源进行优化
文件合并;文件最小化/文件压缩;使用 CDN 托管;缓存的使用
85、HTML5 Canvas 元素有什么用
Canvas 元素用于在网页上绘制图形,该元素标签强大之处在于可以直接在 HTML 上进行图形操作
86、为什么利用多个域名来存储网站资源会更有效
CDN 缓存更方便
突破浏览器并发限制
节约 cookie 带宽
节约主域名的连接数,优化页面响应速度防止不必要的安全问题
确保用户在不同地区能用最快的速度打开网站,其中某个域名崩溃用户也能通过其他郁闷访问网站,并且不同的资源放到不同的服务器上有利于减轻单台服务器的压
88、ajax的最大特点是什么?有什么缺点
89、一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?
分为 4 个步骤:
1. 当发送一个 URL 请求时,不管这个 URL 是 Web 页面的 URL 还是 Web 页面上每个资源的 URL,浏览器都会开启一个线程来处理这个请求,同时在远程 DNS 服务器上启动一个 DNS 查询IP地址。这能使浏览器获得请求对应的 IP 地址。
2. 浏览器与远程 Web 服务器通过 TCP 三次握手协商来建立一个 TCP/IP 连接。该握手包括一个同步报文,一个同步-应答报文和一个应答报文,这三个报文在 浏览器和服务器之间传递。该握手首先由客户端尝试建立起通信,而后服务器应答并接受客户端的请求,最后由客户端发出该请求已经被接受的报文。
3. 一旦 TCP/IP 连接建立,浏览器会通过该连接向远程服务器发送 HTTP 的 GET 请求。远程服务器找到资源并使用 HTTP 响应返回该资源,值为 200 的 HTTP 响应状态表示一个正确的响应。
4. 此时,Web 服务器提供资源服务,客户端开始下载资源。
当输入 URL 时,整个过程是什么样的
-
域名解析(为了将消息从你的PC上传到服务器上,需要用到1P协议、ARP协议和0SPF协议)
-
发起TCP的3次握手
-
建立TCP连接后发起http请求
-
服务器响应http请求
-
浏览器解析htm代码,并请求html代码中的资源(如js、css、图片等)
-
断开TCP连接
-
浏览器对页面进行渲染
91、知道什么是 webkit 么? 知道怎么用浏览器的各种工具来调试和 debug 代码么
Webkit 是浏览器引擎,包括 html 渲染和 js 解析功能,手机浏览器的主流内核,与之相对应的引擎有 Gecko(Mozilla Firefox 等使用)和 Trident(也称 MSHTML,IE 使用)。
对于浏览器的调试工具要熟练使用,主要是页面结构分析,后台请求信息查看,js 调试工具使用,熟练使用这些工具可以快速提高解决问题的效率
###92、语义化的理解?
用正确的标签做正确的事情!
html 语义化就是让页面的内容结构化,便于对浏览器、搜索引擎解析; 在没有样式 CCS 情况下也以一种文档格式显示,并且是容易阅读的。
搜索引擎的爬虫依赖于标记来确定上下文和各个关键字的权重,利于 SEO。使阅读源代码的人对网站更容易将网站分块,便于阅读维护理解。
93、web性能优化的方案
1、尽量减少 HTTP 请求
2、使用浏览器缓存 浏览器的缓存机制:提升页面性能同时减轻后端服务器压力的利器
3、使用压缩组件
4、图片、JS 的预载入
5、将脚本放在底部
6、将样式文件放在页面顶部
7、使用外部的 JS 和 CSS
8、精简代码
9、使用CDN托管
使用CDN(内容分发网络)加速(他可以将数据缓存到距离用户最近的位置,用户可以尽快获取数据,数据中心也可以减轻压力,从而提高访问速度)
代码简化,去掉无用代码,逻辑循环清晰
94、项目中遇到过什么问题
1、技术问题:① 在之前的项目中,由于我着手的业务可能相对比较常规,所以没有遇到太大的难题,但是我也很期待在之后的项目中遇到难题,这样自己才能成长进步 ② 在之前的项目中,确实遇到过一些坑
2、业务沟通问题:经常遇到在完成某个功能模块后,甲方的需求变动,一般这种时候只能我们去改代码,完成客户的需求,但是这个问题其实有机会去避免的,在做某个模块的时候,要去与客户沟通,尽可能发掘出它的潜在需求
3、
95、项目问题
电商项目:
96、React 中函数组件和普通组件有什么区别
Answer:函数组件是个纯函数,接受一个props对象,返回一个react元素,没有生命周期和状态state(所以也叫无状态组件);而类组件需要继承React.Component并且创建render函数返回react元素,有生命周期和状态state。
97、fiber 是什么
Answer:React Fiber是对核心算法的一次重新实现。破解JavaScript中同步操作时间过长的方法:分片。React Fiber把更新过程碎片化,每执行完一段更新过程,就把控制权交还给React负责任务协调的模块,看看有没有其他紧急任务要做,如果没有就继续去更新,如果有紧急任务,那就去做紧急任务。维护每一个分片的数据结构,就是Fiber。
98、关于模块的分包
根据代码的复用性有common模块、项目的具体模块
99、amd 和 cmd 的区别 commonjs,esmodule
100、什么是函数柯力化
一个函数里再返回一个函数
101、虚拟dom是什么以及如何实现的?
虚拟dom就是一个js对象,它可以理解为真实dom的一个副本,它将元素、属性、内容子节点等数据去描述它的构成,然后他通过数据模型的变化(页面交互)来更新dom树
102、eslint测试 ---- 代码格式测试
103、Accept 头部的作用什么,如果服务器不支持怎么办
请求方的头结构:请求报头|实体报头
Accept属于请求头,描述客户端希望接收的响应body 数据类型
Content-Type属于实体头,描述客户端发送的 body 数据类型
104、input 中如何监听值的变化?
因为input的onchange事件是要改变值之后失去焦点才触发,并不能实现实时监听,所以存在3种情况,第一种是只需要失去焦点时监听,那就用onchange,第二种是js改变值,这时候可以在改变值的方法里手动触发,第三种则是实时监听,可以用keypress、keydown、keyup等事件监听。
104、什么是事件冒泡和事件捕获,区别是什么?
事件冒泡是子元素向父元素传递事件,而事件捕获是父元素向子元素传递事件(ps.事件代理/事件委托:直接在父元素写事件,可以避免遍历子节点的操作,优化性能),事件触发的顺序是相反的。阻止:event.stopPropagation()
105、对babel的理解
就是将es6、ts等浏览器不认识的代码编译成浏览器能识别的代码
106、react的优点
1、一切皆组件,所以代码的复用性、维护性更强
2、入门简单,但是对原生js的要求更高
3、虚拟dom
4、react仅提供了视图层,即MVC中的V => view => 单向数据流,所以业务流程更加清晰
5、react可以有服务端渲染
107、渲染方式
浏览器渲染 :
单页应用用的基本都是浏览器渲染。优点很明确,后端只提供数据,前端做视图和交互逻辑,分工明确。服务器只提供接口,路由以及渲染都丢给前端,服务器计算压力变轻了。但是弱点就是用户等待时间变长了,尤其在请求数多而且有一定先后顺序的时候。
服务端渲染:
服务端根据用户请求计算出需要的数据资源,然后将数据更新成视图,发给客户端,客户端直接将这串字符塞进浏览器即可,但是服务端渲染存在的问题:导致后端计算压力变重,另外没有前后端分离,不能很好的并行开发,开发效率变低
108、JSX --- js的扩展(有点像模板字符串的用法,在js文件里可以写html标签) 浏览器只能识别js,所以需要babel插件对其进行编译
JSX会被babel编译为react.createElement() ---- 它会返回一个js对象(元素、属性、内容或子节点)
109、react是怎么将数据层和视图层联系上的?
数据层:数据状态管理器 --- model 例如redux
视图层:react组件 react 本身仅提供视图层
react中父子组件传值:父组件传给子组件:通过props,子组件通过props就可以拿取到数据,若是想要进行数据的修改,则要调用setState方法
子组件传给父组件:主要是使用父组件传递过来的方法来进行通信,在传递过来的方法上入参我们需要传递的参数,父组件中的方法就可以接收到传递过来的参数
110、event.preventDefault()
防止组件发生默认行为
111、高阶组件
优势:代码复用性强,可以进行渲染劫持
112、热加载
113、class里面能使用箭头函数吗?
114、怎么实现一个promise.all
css样式相关面试题
1、实现响应式布局? 响应式布局:同一页面在不同的屏幕尺寸下有不同的页面布局
响应式设计与自适应设计的区别:响应式开发一套界面,通过检测视口分辨率,针对不同客户端做一定的代码处理,来展现不同的布局和内容;自适应需要开发多套界面,通过检测视口分辨率,来判断当前访问的设备是pc端、平板、app端,从而请求服务层,返回不同的页面
响应式布局实现方案:1、媒体查询(最重要的) 2、百分比布局 3、rem布局
使用@media来实现不同分辨率使用不同的样式,作为基础,然后结合其他的方案,比如用rem实现字体的适配,宽度可以使用百分比、flex弹性盒子布局(CSS3提出的:排列、对齐、分配空白空间等,但是兼容性较差)等
2、CSS中link和@import的区别? link:是html的语法,它可以在页面上使用阻塞的形式来加载样式,这样可以避免页面加载出来后,缺少样式;它除了样式,还能加载其它文件,还可以定义一系列属性等 @import:只能在样式文件中,异步导入加载样式文件;它是在页面加载完毕后,才会加载样式
3、display:none 和 visibility:hidden 的区别? display: none 设置一个元素不显示,不会占用页面空间,没有继承性 visibility: hidden 设置一个元素不可见,会占用原来的页面空间,有继承(inherit)性,也就是给父元素设置了这个样式之后,子元素也会有这个样式
visibility具有继承性,给父元素设置visibility:hidden;子元素也会继承这个属性。但是如果重新给子元素设置visibility: visible,则子元素又会显示出来。这个和display: none有着质的区别
4、 :: 和 : 有什么区别? css3中
:: 是伪元素,通过css样式给某个元素添加一个子元素或者添加文本等,常见的有::before 和 ::after
: 是伪类,通过css样式给已有的元素添加样式等,常见的有:hover(移入该元素时触发怎样的样式) 或 :first-letter(给该元素文的本字段的第一个字符添加样式) 或 first-child(给该元素的一个子元素添加样式) 或 :active(给正在被激活的元素设置添加的样式) 或 :visited(给激活后的元素设置添加的样式) 或 :link(给未被访问的元素添加的样式) 或 :focus(给拥有输入焦点的元素设置样式)
5、让元素居中的方法有哪些?
1、弹性盒子 flex
①:父元素:设置为:弹性盒子,display:flex; align-items: center(垂直居中);justify-content: center(水平居中)
②:父元素:display:flex; justify-content:center;
子元素:align-self:center; (弹性盒子的子元素在侧轴的排序方式)
2、在已知父元素的高度下,text-align+line-height
父元素:text-align:center;
子元素:line-height:'父元素的高度';
3、在已知父元素的高度下,margin+line-height
子元素 :display:block;width:'宽度'; margin:0 auto(水平居中); line-height:'父元素的高度'(垂直居中);
4、使用定义为单元格,display:table-cell,就相当于<th><td> (行内块)
父元素 display: table-cell;vertical-align(必须是行内块元素才能应用,垂直居中): middle;text-align(水平居中): center; 子元素 display: inline-block/inline;
5、绝对定位+transform
父元素 position: relative; 子元素 position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);
6、绝对定位+ margin 父元素 position: relative; 子元素 position: absolute; top: 0; bottom: 0; left: 0; right: 0; margin: auto; => 要有宽高
6、弹性盒子设置?参数?撑破问题?
容器上的属性:
flex-direction -- 决定主轴的方向,即决定容器内子元素的一个排列方式(横向还是纵向)
flex-wrap -- 决定子元素在容器内溢出后,是否换行
flex-flow -- flex-direction和flex-wrap的简写 => flex-flow:<flex-direction><flex-wrap>
justify-content -- 决定子元素在主轴上的对齐方式
align-items -- 决定子元素在侧轴上的对齐方式
align-content -- 设置多行时的行的对齐方式
项目上的属性:
order -- 设置弹性盒子的子元素排列顺序,用整数值来定义排列顺序,数值小的排在前面。可以为负值,默认为0
flex-grow -- 设置或检索弹性盒子元素的扩展比率,规定相对于其他项目扩展的量,默认值是0
flex-shrink -- 指定了 flex 元素的收缩规则。flex 元素仅在默认宽度之和大于容器的时候才会发生收缩,其收缩的大小是依据 flex-shrink 的值,默认值是0
flex-basis -- 用于设置或检索弹性盒伸缩基准值,默认值是auto
flex -- 设置弹性盒子的子元素如何分配空间 => flex:<flex-grow><flex-shrink><flex-basis> => flex:1 => flex:1即为flex-grow:1,经常用作自适应布局,将父容器的display:flex,侧边栏大小固定后,将内容区flex:1,内容区则会自动放大占满剩余空间。
align-self -- 在弹性子元素上使用。覆盖容器的 align-items 属性
解决父元素盒子撑破问题:
产生原因:浏览器的默认盒模型是 content-box 即内容就为其的宽度,若是给子元素设置宽为100%,且添加padding或者border,那么就会将父盒子撑破
解决办法:① 将盒模型改为border-box(怪异盒子:box-sizing:border-box),其内容就包括content-padding-border
② 利用calc()属性,计算出除去padding和border后的width应该是多少
③ 添加滚动条、滚动条失效:
子元素:flex:1;滚动方向的大小(宽度或者高度)设置为0,非滚动方向大小设置为100%,若是还是不行,则给父元素设置一个width:0或者height:0即可;overflow-x:auto;或overflow-y:auto
父元素:flex-flow:设置为滚动条方向;
7、盒子模型
① 普通盒子模型(默认模式):width 和 height 指的是内容区域的宽度和高度。增加内边距、边框和外边距不会影响内容区域的尺寸,但是会增加元素的总尺寸
② IE盒子模型(怪异模式):width 和 height 指的是内容区域+border+padding的宽度和高度 设置:box-sizing:border-box
8、CSS3新特性
① 新增选择器:选择器匹配第几个子元素 => e:nth-child(n)、e:nth-of-type(n)、e:first-child
② 文本相关:一、设置文本阴影:text-shadow:val1 val2 val3 val4; => val1:向右的偏移量 val2:向左的偏移量 val3:渐变的像素 val4:渐变的颜色
二、设置文本溢出:text-overflow:ellipsis;
三、设置文本换行:text-wrap
四、设置元素中的空白:white-space
③ 边框:border-raduis:*px; => 边框圆角设置
④ 渐变:一、线性渐变:linear-gradient(角度,颜色 *%,颜色)
二、环形渐变:radial-gradient()
⑤ 多列布局:column-count => 将一个块级元素分成三等列,像报纸的排版一样
⑥ 过渡:transition
⑦ 动画:animation
⑧ 旋转:transform:translate(平移)/rotate(旋转)/scale(缩放)/skew(倾斜)
⑨ flex布局:弹性盒子布局
⑩ @media:媒体查询
⑪ calc():允许在属性值中实现计算,设置动态值等
9、常见布局:
float浮动、display(改变元素特性)、表格布局、position定位布局、flex弹性盒子布局、column-count多列布局
10、BFC是什么?
BFC => block format context => 块级格式化上下文 => 一个独立的渲染区域,与外部其他的区域毫不相关
=> 脱离文档流,就会触发BFC
=> 触发情况:float(值不为none)、position(fixed、absolute)、overflow(值不为visible)、display(inline-block、table-cell)
=> 作用:自适应两栏布局(左侧float,右侧overflow => 让右侧单独成一个BFC)、阻止同级元素被浮动元素覆盖、清除内部浮动,防止高度塌陷(父节点不设置高度,子节点设置浮动,则会触发高度塌陷)、阻止margin重叠(上下两个同级元素若是分别设置了下margin和上margin,则会选数据大的那一个,导致重叠)
11、重排和重绘的区别
重排(回流) => 页面的排列布局 => 元素的删减、元素的位置、尺寸大小的改变、页面窗口尺寸的变化等
重绘 => 外观样式发生变化则会发生重绘
=> 重绘不一定会重排(比如颜色的改变),但是重排一定会重绘
=> 浏览器在这方面有自己的优化,将重排和重绘放入一个队列,等这个队列到一定的数量或者到某个时间间隔之后,那么就会将这一批的重排重绘一起进行处理
12、less和sass/scss的区别
less:对CSS赋予了动态语言的特性,如变量、嵌套、继承、运算、函数
sass:也是一种CSS动态样式语言,如变量、嵌套、运算、混入(Mixin)、继承、颜色处理,函数等
区别:① 实现方式不同:less是基于JavaScript的,是在客户端处理的;而sass是基于Ruby,是在服务端处理的
② 声明变量的方式:less是@;sass是$
③ less中的运算,可带单位也可不带,单位不会带入计算;sass中就要注意单位,sass在 计算时会带入单位计算
④ sass可以写if结构、循环结构(for、while)
13、请讲一下圣杯布局和双飞翼布局
圣杯布局与双飞翼布局都是双边固定宽度,中间自适应的布局
实现方法
14、img的alt属性和title属性
alt => 指图片无法正确加载时的显示文字
title => 指鼠标移动到图片上的提示文字
15、渐进增强和优雅降级?
渐进增强 progressive enhancement:针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。
优雅降级 graceful degradation:一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。
区别:优雅降级是从复杂的现状开始,并试图减少用户体验的供给,而渐进增强则是从一个非常基础的,能够起作用的版本开始,并不断扩充,以适应未来环境的需要。降级(功能衰减)意味着往回看;而渐进增强则意味着朝前看,同时保证其根基处于安全地带。
16、css优先级问题