CSS
盒模型的理解
盒子模型是使用CSS控制页面元素外观和位置的基础,本质是一个盒子用来封装HTML元素。它由内而外包含内容(content)、内边距(padding)、边框(border)和外边距(margin)。
盒子的宽度和高度的计算方式由box-sizing属性控制:
box-sizing(
属性值)content-box
:默认值,设定宽高为内容的宽高——标准盒模型border-box
:设定宽高包含了内边距(padding)和边框(border)。——怪异盒模型inherit
:规定应从父元素继承box-sizing属性的值
计算方式:
content-box
:盒子的总宽度 = width +padding(左右)+margin(左右)+border(左右)
border-box
:盒子的总宽度 = width +margin(左右)
高清方案(适配)实现(CSS自适应/响应式布局)?
常用的自适应方案有:
1.@media媒体查询:
@media screen and (max-width: 300px) {
body {
font-size: 20px;
}
}
2.rem,%,wh等动态单位 (如屏宽100px,则以下运行结果都为width: 20px)
html, body {
font-size:100px;
}
.div-box1 {width: 0.2rem} //根html设置font-size:100px
.div-box2 {width: 20%} //直属父元素设置width:100px
.div-box3 {width: 20vw} //以根html宽为100vw计算
3.calc、–var1等动态计算机制
body {
width: 100px;
}
.div-box4 {width: calc(width: 100% - 20px);} //此处运算结果为比父元素小20px
:root {
–-width20: 20px;
}
.div-box3 {width: var(–width20);} //设置:root {–-width20: 20px;}
px、em、rem、%、vw、vh区别
px:像素,相对长度单位,相对于屏幕分辨率;
em:参考物是父元素的font-size,具有继承的特点。浏览器的默认字体大小是16px,同一个页面内不同的1em不是一个固定的值。(比如A父元素大小为24px,则A的1em是24px;B服元素大小为36px,则B的1em是36px。
rem:CSS新增的相对单位,相对于HTML根元素。通过它可以只改根元素大小就能成比例调整所有字体,避免字体大小逐层复合的连锁反应。(最优选)
%:相对长度单位,相对于父元素的百分比值。
vw/vh:相对长度单位,相对于视窗(viewviewport)大小。单位是1,类似于视窗的1%。
vw:视窗宽度的百分比
vh:视窗高度的百分比
vmin:取当前vw和vh中的较小值
vmax:取当前vw和vh中的较大值
vw 100%,横向滚动条的原因:
vw单位忽视了滚动条占据视口空间(滚动条是不会影响 vw
单位计算的),还是计算整个视口的宽度。
解决办法:margin-right: calc(100% - 100vw);
对BFC的了解,列举一些常见的可以触发 BFC 的方法
BFC全称是Block Formatting Context,意思就是块状格式化上下文。你可以把BFC看做一个容器,容器里边的元素不会影响到容器外部的元素。
特点:
BFC是一个块级元素,块级元素在垂直方向上依次排列。
BFC是一个独立的容器,内部元素不会影响容器外部的元素。
属于同一个BFC的两个盒子,外边距margin会发生重叠,并且取最大外边距。
计算BFC高度时,浮动元素也要参与计算。
作用:
解决当父级元素没有高度时,子级元素浮动会使父级元素高度塌陷的问题。
解决子级元素外边距会使父级元素塌陷的问题。(外边距塌陷/垂直塌陷)
解决包含塌陷。(有时候我们给子元素加margin可能会带着父元素一起跑)
清除浮动
解决标准元素流被浮动元素覆盖的问题。
如何触发BFC:给父元素加以下任何样式
overflow: hidden;
display: flex;
display: inline-flex;
display: inline-block;
position: absolute;
position: fixed;
flex布局及相关属性
定义:弹性盒布局(flexible box)
容器container的属性:
- flex-direction // 主轴方向 默认值row,主轴为水平方向,起点在左端
- flex-wrap // 主轴一行满了换行 默认值nowrap,不换行压缩宽度
- flex-flow // 1和2的组合 简写flex-low: [flex-direction] [flex-wrap]
- justify-content // 主轴元素对齐方式 默认flex-start,靠左对齐main-start
- align-items // 交叉轴元素对齐方式//单行 默认值stretch
- align-content // 交叉轴行对齐方式//多行. 默认flex-start,靠左对齐cross-start
项目元素item的属性:
- flex-grow // 放大 默认值0,不放大
- flex-shrinik // 缩小 默认值1,允许项目收缩
- align-self // 覆盖container align-items 属性 默认值auto
- order // 排序
- flex-basis // 有效宽度
如何实现单行/多行文本溢出的省略样式?
单行:
overflow: hidden; // 文字超出限定宽度,隐藏超出内容
white-space: nowrap; // 设置文字在一行显示,不能换行
text-overflow: ellipsis; // 规定当文本溢出时,显示省略符号来代表被修剪的文本
多行:
css样式优先级讲讲
内联样式 > 内部样式 > 外部样式 (优先级加权值)
!important (10000)> 内联样式(1000) > ID 选择器(100) > 类选择器 = 属性选择器 = 伪类选择器(10) > 标签选择器 = 伪元素选择器(1) > 通配选择器 (0)> 浏览器默认样式(0)
- 内联样式:写在标签属性 style 的样式,如 <span style="color:green">
- ID 选择器,如 #id{…}
- 类选择器,如 .class{…}
- 属性选择器,如 p[type="email"]{…}
- 伪类选择器,如 input:hover{…}
- 标签选择器,如 div{…}
- 伪元素选择器,如 span::before{…}
- 通配选择器,如 *{…}
- 浏览器默认样式
如何解决设计稿和 通用 UI 组件的样式冲突问题
覆写通用UI组件的样式,用 :global 来实现,注意需要限定在某个自定义样式下,就不会全局覆盖,否则全局覆盖。
样例:
.answerModeSelect {
width: 120px;
margin-left: 10px;
color: #fff;
background-color: #1890ff;
border-radius: 20px;
// 限定在自定义样式answerModeSelect下面不会覆盖全局的通用组件
:global {
.ant-select-selector .ant-select-selection-item {
color: #fff;
}
.ant-select-arrow {
color: #fff;
}
}
}
CSS 选择器有哪些
- id选择器:#child1
- 类选择器:.container
- 标签选择器:div
- 后代选择器:.container div,表示container类里面的所有div标签
- 子选择器:.container>div,表示container类里面下一代的所有div标签
- 相邻同胞选择器:.child1+.child2,表示所有紧接在.child1后面的一个.child2(二者必须是兄弟)
- 群组选择器:.child1,.child2,表示所有的.child1和.child2
- 伪类选择器:比如 :hover :link :active :first-child ::nth-child(n)
- 伪元素选择器:比如 ::after ::before ::first-letter
- 属性选择器:[attribute]选择带有attribute属性的标签,[attribute=value]选择attribute=value属性的标签
- 层次选择器:p~ul,表示p后面的所有ul,二者必须有相同的父标签
我如何选择一个节点的兄弟节点:使用相邻同胞选择器
JS
let、const、var 能够说出之间的简单使用区别
var:es5
- var声明的变量就是全局变量,也是顶层变量
- var声明的变量存在变量提升
- var能对同一个变量声明多次,后面声明的覆盖前面的
- 在函数中使用var声明的变量是局部的
let:es6
- let声明的变量,只在let命令所在的代码块内有效
- 不存在变量提升,这代表声明它之前,变量a是不存在的,这时如果用它,就会抛出一个错误
- 存在暂时性死区,只要块级作用域内存在let命令,这个区域就不再受外部影响
- let 不允许在相同作用域中重复声明,不同作用域下可以
- 不能在函数内部重新声明参数
const:es6
- const声明一个只读的常量,一旦声明,常量的值就不能改变,如果之前用var或let声明过变量,再用const声明同样会报错
- 其他情况同let
区别:
变量提升
- var声明的变量存在变量提升,即变量可以在声明之前调用,值为undefined
- let和const不存在变量提升,即它们所声明的变量一定要在声明后使用,否则报错
暂时性死区
- var不存在暂时性死区
- let和const存在暂时性死区,只有等到声明变量的那一行代码出现,才可以获取和使用该变量
块级作用域
重复声明
- var允许重复声明变量
- let和const在同一作用域不允许重复声明变量
修改声明的变量
- var和let可以
- const声明一个只读的常量。一旦声明,常量的值就不能改变
使用
- 能使用const的情况尽量使用const,其他情况大多数使用let,避免使用var
什么是 promise 和 async await
事件委托是什么?解决什么问题?有什么应用场景?React中需要使用事件委托吗?
事件轮询机制event loop
JS原型、原型链
- 每个构造函数(Array)都有一个原型,叫protoType对象属性,在该对象上添加方法会被该构造函数构造出来的对象(arr1、arr2)共享;
- 每个构造函数构造出来的对象(arr1、arr2)都有一个_proto_属性,这个_proto_还可以有它自己的_proto_,以此类推,就形成了一个原型链。
- 构造函数构造出来的对象的_proto_属性指向构造函数的protoType对象属性。
Array.prototype.sum = funtion(){
var res = 0 //记录求和
for(var i = 0; i < this.length; i++){
res += this[i];
}
return res;
}
var arr1 = new Array(1,2,3,4,5);
var arr2 = new Array(10,20,30,40,50);
alert(arr1.sum());//15
alert(arr2.sum());//150
alert(arr1.sum == arr2.sum); //true
<script>
function Person(name, sex){
this.name = name;
this.sex = sex;
}
Person.prototype.showName = function(){
lert("我的名字叫:" + this.name);
}
Person.prototype.showSex = function(){
alert("我的性别是:" + this.sex);
}
//继承于Person创建一个新的构造函数叫做Worker
function Worker(name, sex, job){
//继承属性 这里也可以叫做构造函数的伪装
Person.apply(this, [name, sex]);
this.job = job;
}
//继承方法 添加新的方法
Worker.prototype = Object.create(Person.prototype);
Worker.prototype.showJob = function(){
alert("我的工作是" + this.job);
}
var w1 = new Worker("小明", "男", "演员");
w1.showName();//我的名字叫:小明
w1.showSex();//我的性别是:男
w1.showJob();//我的工作是演员
alert(w1.__proto__ == Worker.prototype); //true
alert(w1.__proto__.showName == Worker.prototype.showName); //true
var w2 = new Worker("小白", "女", "画家");
alert(w2.__proto__.showSex == Worker.prototype.showSex); //true
alert(w1.__proto__ == w2.__proto__); //true
alert(w1.__proto__.showName == w2.__proto__.showName); //true
alert(w1.showName == w2.showName); //true
alert(w2.__proto__.showSex == Person.prototype.showSex);//true
</script>
GC机制(垃圾回收机制)
局部变量在函数执行过后就结束了,此时可以释放他们所占用的内存(垃圾回收)
常用方法:
标记清除法:
- 标记:从根节点遍历为每个可以访问到的对象都打上一个标记,表示该对象可达。
- 清除:在没有可用分块时,对堆内存遍历,若没有被标记为可达对象就将其回收。
引用计数法:
- 引用计数法就是追踪每个变量被引用的次数,当引用数为0将可以被回收掉。
React
hooks 的优势
Hooks 是用来让我们更好地复用 React
状态逻辑代码的。注意这里说的不是模板代码,模板代码可以用组件来复用;而单纯的状态逻辑代码没法用组件复用。(普通的函数可以复用逻辑代码,但是没法复用带状态的逻辑代码。)
优点:
- 提取逻辑出来非常容易
- 非常易于组合
- 可读性非常强
- 没有名字冲突问题
hooks能写在条件语句中吗?
一般情况下不可以,是因为React需要保证hooks的调用顺序是稳定的,如果hooks在条件语句里,可能会导致hooks的调用顺序发生变化,从而引发不可预知的错误,因此官网建议不要使用。
但是,在10月13日的first-class-support-for-promises RFC中,介绍了一种新的hook
—— use
-
可以在条件语句中书写的
hook
-
可以在其他
hook
回调中书写的hook
useState的更新函数,传入一个值和传入一个函数有什么区别
传入一个函数,在函数中计算并返回初始的 state,此函数只在初始渲染时被调用。
useEffect 第二个参数是做什么的?
第二个参数可以不传
或者是一个数组(空数组或者
由基本类型或者引用类型组成的数组)
,非必传项。数组里面依赖改变时候副作用函数才会重新更新。所谓依赖改变就是 [ 之前值 === 之后值 ] ,如果为true不执行useEffect
,为false重新执行useEffect。
合成事件是什么?为什么 React 要使用合成事件这种模式?
React 合成事件(SyntheticEvent)是 React 模拟原生 DOM 事件所有能力的一个事件对象,即浏览器原生事件的跨浏览器包装器。
目的:
- 进行浏览器兼容,实现更好的跨平台
- 避免垃圾回收
- 方便事件统一管理和事务机制
受控组件&非受控组件,一般的应用场景是什么?
- 非受控组件: 用户输入A => input 中显示A
- 受控组件: 用户输入A => 触发onChange事件 => handleChange 中设置 state.name = “A” => 渲染input使他的value变成A
注意:
- 受控组件的两个要点:
- 组件的value属性与React中的状态绑定
- 组件内声明了onChange事件处理value的变化
- 非受控组件更像是传统的HTML表单元素,数据存储在DOM中,而不是组件内部,获取数据的方式是通过ref引用
- 尽可能使用受控组件
- 受控组件是将状态交由React处理,可以是任何元素,不局限于表单元素
- 对于有大量表单元素的页面,使用受控组件会使程序变得繁琐难控,此时使用非受控组件更为明智
- 在受控组件中,数据流是单向的(state是变化来源),因此在改变state时都应该使用setState,而不要强制赋值
- Refs不能用于函数式组件,因为函数式组件没有实例
- 在函数式组件内部,是可以使用Refs的
diff 算法
diff算法的本质就是:找出两个对象之间的差异,目的是尽可能做到节点复用。
fiber 是什么?解决什么问题?
可以说 Fiber 是一种数据结构(堆栈帧),也可以说是一种解决可中断的调用任务的一种解决方案,它改变了之前react的组件渲染机制,新的架构使原来同步渲染的组件现在可以异步化,可中途中断渲染,执行更高优先级的任务。释放浏览器主线程。
setState 后,React做了哪些事情?
当调用render和setState方法进行组件渲染和更新的时候,react会经历俩个阶段:reconciler(调和阶段)和render阶段(渲染阶段)。
了解调和过程和原理吗?
调和阶段(Reconciler):官方解释。React 会自顶向下通过递归,遍历新数据生成新的 Virtual DOM,然后通过 Diff 算法,找到需要变更的元素(Patch),放到更新队列里面去。
Vue
- vue2、vue3 区别
- 在哪个生命周期内调用异步请求?
- computed计算属性
- 谈谈你对 keep-alive 的了解?
- 为什么组件中的 data 必须是一个函数,然后 return 一个对象,而 new Vue 实例里,data 可以直接是一个对象?
- Vue是怎么实现双向绑定的?
- v-show 和 v-if 的区别。
- $nextTick 是干什么的?
- 什么是 SPA?他有什么优势?有什么劣势?
Node
- 有什么常见的 Stream 流,那实现一个自定义的 可写流 要做哪些事情?
- Express 和 KOA 有什么区别?什么是洋葱模型?
- 如何查看 nodejs 进程的栈内存?
- 父子进程如何通信
计算机基础
- HTTP缓存策略
- HTTP/HTTPS 的区别
- 跨域是什么?拦截在什么阶段?有哪些解决方案?
工程链路
- 说一说Loader和Plugin的区别?
- Webpack构建流程简单说一下
- source map是什么?
- 生产环境怎么用?=====
- Webpack 的热更新原理吧
- 聊一聊Babel原理吧
- git 常规命令
- git merge rebase 的区别是啥?
- 如何回退一个提交?
- 如果这提交在4 - 5个提交之前怎么回滚?=====
- 工作的 git flow 是怎么样的?
项目阐述
笔试题
- twoSum 在数组里面寻找两个数加起来等于target的索引
- 数组去重
- 实现一个深拷贝函数
- 给定一个只包含 '(', ')', '{', '}', '[' and ']', ' ' 空字符 的字符串 ,判断这个字符串是否满足下列条件:
1) 左括号必须用相同类型的右括号闭合。
2) 左括号必须以正确的顺序闭合。([)] => false
3) 注意空字符串 ' ' 可被认为是有效字符串,但不需要闭合处理。
示例:"()" => true, "()[]{}" => true, "(]" => false, "([)]" => false, "{[]}" => true])([ - 实现一个深拷贝函数deepClone,尽量考虑多种情况
- 写一个 logger 类,用于存储业务日志并批量缓存到本地磁盘