CSS类
1. 如何清除浮动
- 给父容器手动加高度
原理:手动设置高度,解决父元素获取不到高度的问题。
优点:操作简单,易于编码。
缺点:不灵活,只适合高度固定的布局,当子元素高度不确定时,容易出现问题。 - 给父元素增加样式 –
overflow: hidden
原理:通过overflow: hidden
格式化上下文结构
优点:简单、代码少、浏览器支持好
缺点:当父元素宽度不够时,overflow: hidden
会引起超出隐藏问题。 - 在父元素最后追加空div标签,设置
clear: both
原理:利用css - clear属性清除浮动
缺点:需要新增空白标签,繁琐 - 利用伪元素方法(个人常用)
原理:利用父元素的::after
伪元素,模拟空白标签div
优点:减少重复代码(可以设置公有类)
例:
.clearfix::after {
/* 模拟空标签 */
content: '';
display: block;
/* 不占位 */
height: 0;
line-height: 0;
visibility: hidden;
/* 清除浮动 */
clear: both;
}
.clearfix {
/* 兼容IE */
zoom: 1;
}
2. 几种方式实现已知或者未知宽度的垂直水平居中
/* 思路一:父、子容器(块级)宽高都已知,可以利用 margin */
.box1 {
width: 400px;
height: 400px;
background-color: rgb(129, 2, 2);
overflow: hidden; /* 父容器要格式化上下文,防止塌陷 */
}
.box1_son {
width: 200px;
height: 200px;
background-color: rgb(6, 88, 6);
margin: 100px auto;
}
/* 思路二:父容器宽高未知、子容器宽高已知,子绝父相 + margin */
.box1 {
position: relative;
background-color: rgb(129, 2, 2);
}
.box1_son {
width: 200px;
height: 200px;
background-color: rgb(6, 88, 6);
position: absolute;
top: 50%;
left: 50%;
margin-top: -100px;
margin-left: -100px;
}
/* 思路三:父、子容器宽高都未知,子绝父相 + 过渡 */
.box1 {
position: relative;
background-color: rgb(129, 2, 2);
}
.box1_son {
background-color: rgb(6, 88, 6);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%)
}
/* 思路四:伸缩盒子 */
.box1 {
width: 400px;
height: 400px;
background-color: rgb(129, 2, 2);
display: flex;
justify-content: center;
align-items: center;
}
3. 雪碧图的优缺点
原理: 将网站上需要用到的图片进行整合,放到一张图片中,从而减少HTTP请求次数。使用时通过 background-image
、background-report
和 background-position
配合使用。
优点: 减少了HTTP请求次数,提高了网页加载速度。
原理: css样式变得复杂,需要的代码变多。
4. px,em,rem的区别
px:是指一个像素单位。
em:不是固定值,能够继承父元素的 font-size
的大小。
rem:不是固定值,永远参照 html 标签的 font-size
的大小。
JS类
1. JS基本数据类型
参考链接: https://blog.csdn.net/qq_40311523/article/details/103476125
2 实现一个函数,判断输入是不是回文字符串
回文字符串: 是指一个字符串正序和倒序完全一致,例如:‘level’,‘12321’。
思路一: 从字符串中抽取单个字符与对应位置上的字符比对。
const isPalindrome = (str) => {
let isTrue = true
// for (let i = 0; i < str.length - 1; i++) {
// str.charAt(i) === str.charAt(str.length - 1 - i) ? false : isTrue = false
// }
// 优化:减少循环次数
for (let i = 0; i < Math.floor(str.length / 2 - 1); i++) {
str.charAt(i) === str.charAt(str.length - 1 - i) ? false : isTrue = false
}
return isTrue
}
思路二: 将字符串分解为数组,翻转后拼接并与原字符串比对。
const isPalindrome = (str) => str.split('').reverse().join('') === str
3. 编写一个数组去重的例子
思路一: (不改变原数组)循环原数组并将每一项推入新数组,推入是判断新数组中是否有重复项
const removeDuplicate = (arr) => {
let newArr = []
arr.map((item) => {
newArr.includes(item) ? false : newArr.push(item)
})
return newArr
}
思路二: (改变原数组)循环原数组每一项并判断数组中是否有重复项,有就删除
const removeDuplicate = (arr) => {
let len = arr.length
for (let i = 0; i < len; i++) {
let index = arr.lastIndexOf(arr[i])
if (index != i) {
arr.splice(index, 1)
i--
len--
}
}
}
4. 编写一个统计字符出现最多的字符,及最多的次数
思路: 将字符串转为对象,key
为字符串,value
为出现次数,并按照value
大小排序
// 获取统计对象
const toObject = (str) => {
let obj = {}
str.split('').map((item) => {
obj[item] ? obj[item]++ : obj[item] = 1
})
return obj
}
// 获取最大值对象
const getMax = (obj) => {
let maxKey = ''
let maxVal = 0
for (const key in obj) {
if (obj.hasOwnProperty(key) && obj[key] > maxVal) {
maxKey = key
maxVal = obj[key]
}
}
return {maxKey, maxVal}
}
使用: console.log(getMax(toObject(str)))
5. 怎么给一个DOM元素绑定多个同类型事件?
利用 addEventListener
属性绑定多个同类型事件。
扩展: 利用 removeEventListener
进行事件监听移除,移除事件时,必须传入要移除的事件函数名
注意: addEventListener
和 removeEventListener
中,事件名不加 on
例如:
let btnObj = document.getElementById('btn')
let fn1 = () => {
console.log('Hello World')
}
let fn2 = () => {
console.log('Hi World')
}
btnObj.addEventListener('click', fn1)
btnObj.addEventListener('click', fn2)
// btnObj.removeEventListener('click', fn1)
6. cookies sessionStorage 和 localStorage 的异同点
相同点: 都是将数据存储在浏览器端
不同点:
- 存储大小:
cookie
存储的数据大小不能超过4KB,否则会被截掉;
sessionStorage
和localStorage
可以达到5M或更多。 - 功能:
cookie
主要是用来存储需要和服务器发生交互的数据,即:cookie
中的数据每次请求时都会在发送到服务器端
sessionStorage
和localStorage
中存储的数据仅是在客户端使用,不会主动参与交互 - 存储时间:
localStorage
中的数据会长久储存,关闭浏览器也会保留,除非手动删除
sessionStorage
中的数据在窗口关闭时会被删除
cookie
中的数据可以设置有效期,有效期内不会被删除;未设置有效期,会在窗口关闭时删除
7. 闭包
- 什么是闭包?
- MDN: 函数与对其状态即词法环境的引用共同构成闭包(closure)。
- 个人理解: 闭包就是能够读取其他函数内部变量的函数。
例:
const fn = () => {
let name = '张三'
return () => name
}
console.log(name) // 空
const fn1 = fn()
console.log(fn1()) // 张三
- 闭包的作用?
- 闭包可以储存变量,一般在函数体内声明的变量,在使用完后会被释放,但闭包的外部函数中的变量一直是引用状态,不会被释放。
- 闭包可以用来操作私有变量。
8. 继承
父类(构造函数):
function Animal(name) {
this.name = name
}
Animal.prototype.eat = function () {
console.log('吃肉..')
}
- 原型链继承
function Dog() {}
Dog.prototype = new Animal()
let dog = new Dog()
console.log(dog.name) // undefined
dog.eat() // 吃肉..
重点: 让子构造函数的原型指向父构造函数的实例
优点: 可以继承父构造函数原型中的属性和方法
缺点: 新实例无法向父类构造函数传参,无法继承构造函数实例中的属性和方法
- 构造函数继承
function Cat() {
Animal.call(this, '猫')
}
let cat = new Cat()
console.log(cat.name) // 猫
cat.eat() // cat.eat is not a function
重点: 子构造函数中调用父构造函数并改变 this
指向
优点: 可以继承父构造函数中的属性和方法
缺点: 无法继承构造函数原型中的属性和方法
- 组合继承(常用)
function Cat(name) {
Animal.call(this, name)
}
Cat.prototype = new Animal()
let cat = new Cat('猫')
console.log(cat.name)
cat.eat()
重点: 结合构造函数继承和原型链继承的特点
优点: 可以继承父构造函数及其原型中的属性和方法
缺点: 代码复杂
- class 关键字继承
父类:
class Animal {
constructor(name) {
this.name = name
}
eat() {
console.log(this.name + '吃吃吃')
}
}
子类:
class Cat extends Animal {
constructor(name) {
super(name)
}
}
let cat = new Cat('猫')
console.log(cat.name) // 猫
cat.eat() // 猫吃吃吃
重点: 子类的 constructor
方法中要调用 super
方法,表示调用父类的 constructor
方法
优点: 可以继承父类中的属性和方法,代码简单
9. documen.write和 innerHTML的区别
documen.write
只能是整个页面进行重绘;
innerHTML
可以只重绘页面中的一部分。
10. .call() 、 .apply() 和 .bind() 的区别和作用?
-
作用:
.call()
、.apply()
和.bind()
的作用都是改变一个函数的this指向。 -
区别:
.call()
:直接调用目标函数并改变this指向,第一个参数是this
指向,之后依次传入目标函数的原有参数。
.apply()
:直接调用目标函数并改变this指向,第一个参数是this
指向,之后以数组形式传入目标函数的原有参数。
.bind()
:改变this指向并返回一个新函数,第一个参数是this
指向,之后依次传入目标函数的原有参数。
优化类
1. 浏览器渲染页面的流程
一、渲染流程
-
首先浏览器会根据 URL地址 去 DNS服务器 上请求网页文档,期间经过三次握手、四次挥手
-
当浏览器拿到服务器响应过来的文档后,会加载 DOM树 和 CSSOM树,会根据文档将字节转为字符,生成标签,再确定节点,构成节点树。DOM树 和 CSSOM树 会并行加载,所以一般把
link
标签放到head
标签中,通过延长并行时间来缩短整体加载时间。例:DOM树加载图例
-
加载 JS 文件,加载 JS 文件时会停止生成 DOM树 和 CSSOM树,所以一般把
script
标签放到body
标签的最后,减少渲染时间。 -
根据 DOM树 和 CSSOM树 合成 渲染树(Render Tree),其实渲染树和 DOM树 和 CSSOM树 都是并行的,解析一部分 DOM树 和 CSSOM树,就合成一部分渲染树,浏览器就渲染一部分,所以经常会看到浏览器一边解析,一边渲染的情况。
二、个人理解:
浏览器渲染页面就相当于盖一幢大楼,硬装和软装同时生产,生产出来一个房间就先装修好一个房间
2. 重绘和重排
一、概念
- 重绘(repaint): 页面一部分要重新绘制。当 CSSOM 树 中的节点发生变化,但不影响该节点的空间大小,此时会引起浏览器重绘。例如:改变某一节点颜色
- 重排(reflow): 也称为回流,当 CSSOM 树 中的节点发生变化,影响了该节点的所占大小(实际宽高变化),此时会引起浏览器重排。例如:
display: none
二、个人理解:
重绘就是一个房子重新软装、粉刷,重排就是一个房子的结构要发生变化
3. CSS和JS的位置会影响页面的效率,为什么?
-
加载css文件时会生产 CSSOM树,与 DOM树 是并行的,所以越早加载css文件越好,会延长并行时间,缩短整体时间;
-
加载js文件时与生成 DOM树 和 CSSOM树 是单线程的,并且会优先加载js文件,会影响页面渲染,所以越晚引入越好。
4. 如何优化网页加载速度
减少http请求:图片地图,CSS Sprites(精灵图)。
使用CDN:使用外部的 JS 和 CSS。
样式引入放头部,脚本引入放底部。
避免CSS表达式。
减少DNS查找。
精简 javaScript。
避免重定向。
删除重复脚本。
5. 优雅降级和渐进增强
优雅降级和渐进增强是用来处理兼容性的两种方式。
优雅降级是指,一开始就考虑高级浏览器开发好完整功能,在逐步根据低版本浏览器的需求进行兼容。
渐进增强和优雅降级刚好相反,一开始只根据低级浏览器开发基本功能,再针对高级浏览器开发效果,交互,提升用户体验。
交互类
1. get和post的区别
传参方式: get
传参会拼接到URL地址后,形式是 ?
后面以 &
分割,post
传参是将参数放到请求体里
数据大小: get
传参有数据大小的限制,一般参照浏览器地址栏支持的最大字节长度,post
传参没有参数数据大小要求
安全性: post
的安全性相对较高。
使用: get
和 post
都可以用来获取或更新数据,只是一般用 get 来获取数据,post 来存储数据
2. 跨域问题的产生和解决
同源策略: 协议名、域名、端口号都相同的两个URL地址叫做同源,非同源的地址间交互会产生跨域。
解决跨域:
- 通过
JSONP
解决跨域 - 通过
CORS
解决跨域(跨域资源共享) node.js
中间件代理跨域WebSocket
协议跨域
(文档会持续更新)