2022年前端面试集
2022/2/25 6:28:39
本文主要是介绍2022年前端面试集,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
css01盒子模型
ie盒子模型=怪异盒子模型:
- width/height = content + border + padding
标准盒模型
- width/height = content
css02盒子水平垂直居中
不知道盒子宽高
1.利用定位 + margin:auto
.parent { width: 500px; height: 500px; border: 1px solid #000; position: relative; } .child { width: 100px; height: 100px; border: 1px solid #999; position: absolute; margin: auto; top: 0; left: 0; right: 0; bottom: 0; }
2.利用表格布局 display:table-cell
.parent { width: 500px; height: 500px; border: 1px solid #000; display: table-cell; vertical-align: middle; text-align: center; } .child { width: 100px; height: 100px; border: 1px solid #999; display: inline-block; }
3.利用 display:flex
.parent { width: 500px; height: 500px; border: 1px solid #000; display: flex justify-content: center; align-items: center; } .child { width: 100px; height: 100px; border: 1px solid #999; }
css03-图片懒加载
使用自定义属性保存图片真实连接,监听页面卷曲事件,当图片进入视口的时候,页面被卷曲的高度+图片到可视窗口的高度>图片到顶部的距离时,将自定义属性地址放入src中
css04字体设置12px以下
通过transform: scale(0.8)
css05-画三角形
<style> .triangle { width: 0; height: 0; //底为哪个方向,边框给哪个方向 border-top: 100px solid #f00; border-right: 100px solid #0f0; border-bottom: 100px solid #00f; border-left: 100px solid #ff0; } </style>
js01-js的数据类型
最新的 ECMAScript 标准定义了 8 种数据类型:
- 7中原始类型:
- Boolean
- Null
- Undefined
- Number
- BigInt
- String
- Symbol
- Object
值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol。
引用数据类型:对象(Object)、数组(Array)、函数(Function)。
js02-如何判断数据类型
-
typeof
-
typeof '5' // string typeof 5 // number typeof null // object typeof undefined // undefined typeof true // boolean typeof Symbol('5') // symbol typeof 5n // bigint typeof new Object(); // object typeof new Function(); // function
-
适用于判断(除null)基础类型,
-
判断引用类型,除了function 全返回object类型
-
-
instanceof
-
只能用来判断
变量的原型链上是否有构造函数的prototype属性(两个对象是否属于原型链的关系)
,不一定能获取对象的具体类型 -
Instanceof 不适用判断原始类型的值,只能用于判断对象是否从属关系
-
[] instanceof Array; // true [] instanceof Object; // true function Person() {}; const person = new Person(); person instanceof Person; // true person instanceof Object; // true
-
-
constructor
-
原理:
每一个实例对象都可通过constructor来访问它的构造函数
,其实也是根据原型链的原理来的。 -
'5'.__proto__.constructor === String // true [5].__proto__.constructor === Array // true undefined.__proto__.constructor // Cannot read property '__proto__' of undefined null.__proto__.constructor // Cannot read property '__proto__' of undefined
-
-
toString
-
Object.prototype.toString方法返回对象的类型字符串,因此可用来判断一个值的类型。
-
因为实例对象有可能会自定义toString方法,会覆盖Object.prototype.toString,所以在使用时,最好加上call
-
所有的数据类型都可以使用此方法进行检测,且非常精准
-
Object.prototype.toString.call('5') // [object String] Object.prototype.toString.call(5) // [object Number] Object.prototype.toString.call([5]) // [object Array] Object.prototype.toString.call(true) // [object Boolean] Object.prototype.toString.call(undefined) // [object Undefined] Object.prototype.toString.call(null) // [object Null] Object.prototype.toString.call(new Function()); // [object Function] Object.prototype.toString.call(new Date()); // [object Date] Object.prototype.toString.call(new RegExp()); // [object RegExp] Object.prototype.toString.call(new Error()); // [object Error]
-
js03-js中的继承
-
原型链继承
-
借用构造函数继承
-
组合继承
-
原型式继承
-
寄生式继承
-
寄生组合式继承
-
混入方式继承多个对象
-
ES6类继承extends
js04-什么是原型?原型链?
-
原型:每个函数创建都会有一个属性prototype,这个属性指向一个对象,这个对象就是原型。
- 每一个构造函数所new出来的实例对象,都可以调用这个原型里面的属性和方法。
-
原型链:原型本身也是一个对象,这个对象就是Object的实例,所以原型也可以调用到Object的原型,这样就组成了一个链式结构。
js05-闭包
- 闭包是什么
- 闭包是指有权访问另一个函数作用域中变量的函数
- 形成闭包的原因
- 内部的函数存在外部作用域的引用就会导致闭包。
- 闭包的本质
- 延长了变量的作用域
js06-如何判断this的指向
- 箭头函数内的 this 指向外层的 this。
bind()
、apply()
和call()
的第一个参数都是 this,区别在于通过 apply 调用时实参是放到数组中的,而通过 call 调用时实参是逗号分隔的。- 普通函数
- 当使用 new 关键字调用函数时,函数中的 this 一定是 JS 创建的新对象。
- obj,this指向obj
- 直接调用,this 将指向全局对象,在浏览器环境中全局对象是 Window
- 异步,this 将指向全局对象,在浏览器环境中全局对象是 Window
js07-call apply bind的使用
-
call
-
首先把要操作的函数中的this关键字变为
call
方法第一个传递的实参 -
把
call
方法第二个及之后的实参获取到 -
把要操作的函数执行,并且把第二个以后传递进来的实参传递给函数
-
fn.call(obj, 1, 2);
-
-
apply
-
和call基本上一致,唯一区别在于传参方式
-
fn.call(obj, 1, 2); fn.apply(obj, [1, 2]);
-
-
bind
-
多次 bind 时只认第一次 bind 的值
-
语法和call一模一样,区别在于立即执行还是等待执行
-
fn.call(obj, 1, 2); // 改变fn中的this,并且把fn立即执行 fn.bind(obj, 1, 2); // 改变fn中的this,fn并不执行
-
js08-数组常用api
Array.of()
返回由所有参数值组成的数组
let a = Array.of(3, 11, 8); // [3,11,8] let a = Array.of(3); // [3]
Arrary.from()
将两类对象转为真正的数组
-
参数:
第一个参数(必需):要转化为真正数组的对象。
第二个参数(可选): 类似数组的map方法,对每个元素进行处理,将处理后的值放入返回的数组。
第三个参数(可选): 用来绑定this。
-
// 1. 对象拥有length属性 let obj = {0: 'a', 1: 'b', 2:'c', length: 3}; let arr = Array.from(obj); // ['a','b','c']; // 2. 部署了 Iterator接口的数据结构 比如:字符串、Set、NodeList对象 let arr = Array.from('hello'); // ['h','e','l','l','o'] let arr = Array.from(new Set(['a','b'])); // ['a','b']
splice()
添加/删除数组元素
参数:
- index:必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。
- howmany:可选。要删除的项目数量。如果设置为 0,则不会删除项目。
- item1, ..., itemX: 可选。向数组添加的新项目。
删除元素:
let a = [1, 2, 3, 4, 5, 6, 7]; let item = a.splice(0, 3); // [1,2,3] console.log(a); // [4,5,6,7] // 从数组下标0开始,删除3个元素 let item = a.splice(-1, 3); // [7] // 从最后一个元素开始删除3个元素,因为最后一个元素,所以只删除了7
删除并添加
let a = [1, 2, 3, 4, 5, 6, 7]; let item = a.splice(0,3,'添加'); // [1,2,3] console.log(a); // ['添加',4,5,6,7] // 从数组下标0开始,删除3个元素,并添加元素'添加' let b = [1, 2, 3, 4, 5, 6, 7]; let item = b.splice(-2,3,'添加1','添加2'); // [6,7] console.log(b); // [1,2,3,4,5,'添加1','添加2'] // 从数组最后第二个元素开始,删除3个元素,并添加两个元素'添加1'、'添加2'
不删除只添加:
let a = [1, 2, 3, 4, 5, 6, 7]; let item = a.splice(0,0,'添加1','添加2'); // [] 没有删除元素,返回空数组 console.log(a); // ['添加1','添加2',1,2,3,4,5,6,7] let b = [1, 2, 3, 4, 5, 6, 7]; let item = b.splice(-1,0,'添加1','添加2'); // [] 没有删除元素,返回空数组 console.log(b); // [1,2,3,4,5,6,'添加1','添加2',7] 在最后一个元素的前面添加两个元素
sort()
数组排序
定义: sort()方法对数组元素进行排序,并返回这个数组。
var array = [10, 1, 3, 4,20,4,25,8]; // 升序 a-b < 0 a将排到b的前面,按照a的大小来排序的 // 比如被减数a是10,减数是20 10-20 < 0 被减数a(10)在减数b(20)前面 array.sort(function(a,b){ return a-b; }); console.log(array); // [1,3,4,4,8,10,20,25]; // 降序 被减数和减数调换了 20-10>0 被减数b(20)在减数a(10)的前面 array.sort(function(a,b){ return b-a; }); console.log(array); // [25,20,10,8,4,4,3,1];
pop()
删除一个数组中的最后的一个元素
定义: pop() 方法删除一个数组中的最后的一个元素,并且返回这个元素。
let a = [1,2,3]; let item = a.pop(); // 3 console.log(a); // [1,2]
join()
数组转字符串
定义: join() 方法用于把数组中的所有元素通过指定的分隔符进行分隔放入一个字符串,返回生成的字符串。
let a= ['hello','world']; let str=a.join(); // 'hello,world' let str2=a.join('+'); // 'hello+world'
reduce
为数组提供累加器,合并为一个值
-
定义:reduce() 方法对累加器和数组中的每个元素(从左到右)应用一个函数,最终合并为一个值。
-
语法:
array.reduce(function(total, currentValue, currentIndex, arr), initialValue) // 数组求和 let sum = [0, 1, 2, 3].reduce(function (a, b) { return a + b; }, 0); // 6 // 将二维数组转化为一维 将数组元素展开 let flattened = [[0, 1], [2, 3], [4, 5]].reduce( (a, b) => a.concat(b), [] ); // [0, 1, 2, 3, 4, 5]
-
参数:
// 回调函数的参数 1. total(必须),初始值, 或者上一次调用回调返回的值 2. currentValue(必须),数组当前元素的值 3. index(可选), 当前元素的索引值 4. arr(可选),数组对象本身
js09-reduce的使用格式
-
定义:reduce() 方法对累加器和数组中的每个元素(从左到右)应用一个函数,最终合并为一个值。
array.reduce(function(total, currentValue, currentIndex, arr), initialValue) // 数组求和 let sum = [0, 1, 2, 3].reduce(function (a, b) { return a + b; }, 0); // 6 // 将二维数组转化为一维 将数组元素展开 let flattened = [[0, 1], [2, 3], [4, 5]].reduce( (a, b) => a.concat(b), [] ); // [0, 1, 2, 3, 4, 5]
js10-什么是回调地狱,如何解决
-
回调的本质:
- 是将回调函数作为参数传递给另一个函数,当处理比较复杂的需求时,回调函数作为参数一层层嵌套,代码结构会非常庞大臃肿,代码维护难度极高,这就叫回调地狱。
-
Promise如何解决回调地狱问题
-
Promise实现了链式调用,代码更优雅,可读性更高
-
promise的then方法有返回值,且返回值依然是一个promise对象,且是一个全新的 promise实例。这样,我们就可以在then方法返回的promise对象后面链式地继续then。后面的then里面回调函数的参数就是上一个then里面return的内容。因为return 的value值会被包装成Promise.reslove(value) 。
采用链式的then可以指定一组按照次序调用的回调函数。第一个then方法指定的回调函数有可能返回的还是一个Promise对象(即有异步操作),这时,第二个then方法指定的回调函数就会等待这个Promise对象状态发生变化,再被调用。如果变为Resolved,就调用resolve函数;如果状态变为Rejected,就调用reject函数
-
js11-promise的使用
Promise 是异步编程的一种解决方案
-
对象不受外界影响,初始状态为pending(等待中),结果的状态为resolved(成功)和rejected,只有异步操作的结果决定这一状态
-
状态只能由pending变为另外两种的其中一种,且改变后不可逆也不可再度修改,
即pending -> resolved 或 pending -> rejected -
let promise = new Promise((resolve, reject)=>{ reject("拒绝了"); resolve("又通过了"); }); promise.then((data)=>{ console.log('success' + data); }, (error)=>{ console.log(error) }); 执行结果: "拒绝了"
js12-new的背后做哪些事情
创建一个新的对象
将对象里面的this指向这个新的对象
将新对象连接到构造函数的原型
返回这个对象
js13-防抖和节流
-
函数防抖(debounce)
- 在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。
-
函数节流(throttle)
- 规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。
js14-高阶函数
- 高阶函数是对其他函数进行操作的函数,操作可以是将它们作为参数,或者是返回它们。
- 简单来说,高阶函数是一个接收函数作为参数或将函数作为输出返回的函数。
js15-函数柯里化
-
柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。
-
//普通函数 function fn(a,b,c,d,e) { console.log(a,b,c,d,e) } //生成的柯里化函数 let _fn = curry(fn); _fn(1,2,3,4,5); // print: 1,2,3,4,5 _fn(1)(2)(3,4,5); // print: 1,2,3,4,5 _fn(1,2)(3,4)(5); // print: 1,2,3,4,5 _fn(1)(2)(3)(4)(5); // print: 1,2,3,4,5
js16-for in和for of的区别
-
for in
遍历的是数组的索引(即键名),而for of
遍历的是数组元素值 -
for in
总是得到对象的key
或数组、字符串的下标 -
for of
总是得到对象的value
或数组、字符串的值
js17-递归及应用场景
-
什么是递归
-
函数的递归就是在函数中调用自身,看一个简单的例子:
-
function doA(n) { ... doA(n-1); }
-
-
数组求最大值
-
遍历数组
-
数组倒置
-
对象属性遍历
-
对象扁平化
-
递归应用-递归读取文件
js18-eventloop事件循环
Event Loop
即事件循环,是指浏览器或Node
的一种解决javaScript
单线程运行时不会阻塞的一种机制,也就是我们经常使用异步的原理。
js19-深拷贝和浅拷贝
浅拷贝,是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
深拷贝,是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。
浅拷贝的实现方式
- Object.assign()
- 展开运算符...
深拷贝的实现方式
- JSON.parse(JSON.stringify())
- 手写递归方法
js20-垃圾回收机制
js21-await async的使用方式
作用是用同步的方式,执行异步操作
async
用于申明一个function
是异步的await
用于等待一个异步方法执行完成。
js22-histroy模式上线后白屏,你怎么解决的?
原因:是页面刷新时,浏览器会向服务器真的发出对这个地址的请求,而这个文件资源又不存在,所以就报404。
处理方式:就由后端修改nginx的配置,做一个保底映射,所有的请求全部拦截到index.html上
js23-把ajax或axios设置成同步
ajax有个参数叫async设置成true axios就是async await
js24-什么是作用域?作用域链?
全局作用域 全局作用域为程序的最外层作用域,一直存在 函数作用域 函数作用域,就是指声明在函数内部的变量,它正好和全局作用域相反。内层作用域可以访问到外层作用域,而外层作用域不能访问到内层作用域 块级作用域 块级作用域可通过let和const声明,声明后的变量,在指定块级作用域外,无法被访问 作用域链 当所需要的变量,在所在的作用域中,查找不到的时候,它会一层一层向上查找,直到找到全局作用域,还没有找到的时候,就会放弃查找。这种一层一层的关系,就是作用域链
js25-什么是同步?什么是异步?
同步 同步运行,同步任务是存储在栈上的,每次会同步清楚每个同步任务,一次只能运行一个任务,函数调用后需等到函数执行结束,返回执行的结果,才能进行下一个任务,这样就会导致线程阻塞。 异步 异步模式,即与同步模式相反,异步任务是以队列的形式来储存的,可以一起执行多个任务,函数调用后不会立即返回执行的结果,如果前一个人物需要等待,可先执行后面的任务,等到前置任务结果返回后再继续回调
js26-什么是宏任务?什么是微任务?
js27-forEach、map、reduce、find、filter的区别?
forEach只是简单的遍历数组 [1,2,3].forEach(num => console.log(num)) map遍历原数组,生成新数组,将数组的每一个元素拿出来处理完成之后再放回去 [1,2,3].map(num => num > 10 ? num : '0'+num) filter遍历数组,生成新数组,判断每一个值的返回结果是否为true,是true的就放进去 [1,2,3].filter(num => num >1) //[2,3] reduce主要是为了对所有数组进行累加,最后返回一个值,不改变原数组 [1,2,3].reduce((add,val,index,arr) => add + val , 0) find遍历数组找到第一个与之匹配的值 [1,2,3].find( num => num > 1) //2
js28-ES6新增的特性?
1. let和const 2. 解构赋值 模版字符串 箭头函数 扩展运算符 新增方法Object.is()、Object.assign() promise与async set和map结构 class
js29-set和map结构?
-
Set 类似于数组,但数组可以允许元素重复,Set 不允许元素重复
// 例1 const set = new Set([1, 2, 3, 4, 4]); console.log(set) // Set(4) {1, 2, 3, 4} // 例2 const set = new Set(); [2, 3, 5, 4, 5, 8, 8].forEach(item => set.add(item)); for (let item of set) { console.log(item); } // 2 3 5 4 8
-
Map 类似于对象,但普通对象的 key 必须是字符串或者数字,而 Map 的 key 可以是任何数据类型
const map = new Map(); const obj = {p: 'Hello World'}; map.set(obj, 'OK') map.get(obj) // "OK" map.has(obj) // true map.delete(obj) // true map.has(obj) // false
js30-封装好的 Ajax 里的常见参数及其代表的含义
url: 发送请求的地址。 type: 请求方式(post 或 get)默认为 get。 async: 同步异步请求,默认 true 所有请求均为异步请求。 timeout : 超时时间设置,单位毫秒 data:要求为 Object 或 String 类型的参数,发送到服务器的数据 cache:默认为 true(当 dataType 为 script 时,默认为 false), 设置为 false 将不会从 浏览器 缓存中加载请求信息。 dataType: 预期服务器返回的数据类型。 可用的类型如下: xml:返回 XML 文档,可用 JQuery 处理
js31-字符串方法?
split
把一个字符串分割成字符串数组
trim()
会从一个字符串的两端删除空白字符
toLowerCase()
用于把字符串转换为小写。
toUpperCase()
用于把字符串转换为大写。
includes()
用于检查字符串是否包含指定的字符串或字符。
js32-require和import的区别
-
导入
require
导出exports/module.exports
是CommonJS
的标准,通常适用范围如Node.js
-
import/export
是ES6
的标准,通常适用范围如React
-
require
的性能相对于import
稍低。因为
require
是在运行时才引入模块并且还赋值给某个变量,而import
只需要依据import
中的接口在编译时引入指定模块所以性能稍高
wl01-https和http的区别
-
HTTP 是一种
超文本传输协议(Hypertext Transfer Protocol)
协议 -
HTTPS 协议提供了三个关键的指标
-
加密(Encryption)
-
数据一致性(Data integrity)
-
身份认证(Authentication)
-
wl02-常见http的状态码
1xx指示信息 | 请求已接收,继续处理 |
---|---|
2xx成功 | 请求已被成功接收 |
3xx重定向 | 要完成请求必须进行更进一步的操作 |
4xx客户端错误 | 请求有语法错误或请求无法实现 |
5xx服务端错误 | 服务器未能实现合法的请求 |
2开头 (请求成功)表示成功处理了请求的状态代码。
200 (成功) 服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。 201 (已创建) 请求成功并且服务器创建了新的资源。 202 (已接受) 服务器已接受请求,但尚未处理。 203 (非授权信息) 服务器已成功处理了请求,但返回的信息可能来自另一来源。 204 (无内容) 服务器成功处理了请求,但没有返回任何内容。 205 (重置内容) 服务器成功处理了请求,但没有返回任何内容。 206 (部分内容) 服务器成功处理了部分 GET 请求。
3开头 (请求被重定向)表示要完成请求,需要进一步操作。 通常,这些状态代码用来重定向。
300 (多种选择) 针对请求,服务器可执行多种操作。 服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。 301 (永久移动) 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。 302 (临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。 303 (查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。 304 (未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。 305 (使用代理) 请求者只能使用代理访问请求的网页。 如果服务器返回此响应,还表示请求者应使用代理。 307 (临时重定向) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
4开头 (请求错误)这些状态代码表示请求可能出错,妨碍了服务器的处理。
400 (错误请求) 服务器不理解请求的语法。 401 (未授权) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。 403 (禁止) 服务器拒绝请求。 404 (未找到) 服务器找不到请求的网页。 405 (方法禁用) 禁用请求中指定的方法。 406 (不接受) 无法使用请求的内容特性响应请求的网页。 407 (需要代理授权) 此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理。 408 (请求超时) 服务器等候请求时发生超时。 409 (冲突) 服务器在完成请求时发生冲突。 服务器必须在响应中包含有关冲突的信息。 410 (已删除) 如果请求的资源已永久删除,服务器就会返回此响应。 411 (需要有效长度) 服务器不接受不含有效内容长度标头字段的请求。 412 (未满足前提条件) 服务器未满足请求者在请求中设置的其中一个前提条件。 413 (请求实体过大) 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。 414 (请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。 415 (不支持的媒体类型) 请求的格式不受请求页面的支持。 416 (请求范围不符合要求) 如果页面无法提供请求的范围,则服务器会返回此状态代码。 417 (未满足期望值) 服务器未满足"期望"请求标头字段的要求。
5开头(服务器错误)这些状态代码表示服务器在尝试处理请求时发生内部错误。 这些错误可能是服务器本身的错误,而不是请求出错。
500 (服务器内部错误) 服务器遇到错误,无法完成请求。 501 (尚未实施) 服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码。 502 (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。 503 (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。 504 (网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。 505 (HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。
wl03-js延迟加载的方式
-
JS延迟加载:也就是等页面加载完成之后再加载 JavaScript 文件。
-
js的延迟加载有助与提高页面的加载速度。
-
一般有以下几种方式:
- defer 属性
- async属性
- 动态创建DOM方式
- 使用jquery的getScript方法
- 使用settimeout延迟方法
- 让js最后加载。
wl04-如何减少重绘和回流
CSS
- 避免使用
table
布局。 - 尽可能在
DOM
树的最末端改变class
。 - 避免设置多层内联样式。
- 将动画效果应用到
position
属性为absolute
或fixed
的元素上。 - 避免使用
CSS
表达式(例如:calc()
)。
JavaScript
- 避免频繁操作样式,最好一次性重写
style
属性,或者将样式列表定义为class
并一次性更改class
属性。 - 避免频繁操作
DOM
,创建一个documentFragment
,在它上面应用所有DOM操作
,最后再把它添加到文档中。 - 也可以先为元素设置
display: none
,操作结束后再把它显示出来。因为在display
属性为none
的元素上进行的DOM
操作不会引发回流和重绘。 - 避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。
- 对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。
wl05-描述输入url地址到网页展示的过程
浏览器从输入网址到渲染页面主要分为以下几个过程
- URL 输入
- DNS 解析
- 建立 TCP 连接
- 发送 HTTP / HTTPS 请求(建立 TLS 连接)
- 服务器响应请求
- 浏览器解析渲染页面
- HTTP 请求结束,断开 TCP 连接
wl06-跨域问题及解决方案
跨域浏览器
- 创建一个文件夹, C:\aaa
- 创建一个谷歌浏览器的快捷方式
- 在快捷方式点右键 =>属性=>目标,移动到最后,加入空格,粘贴 --disable-web-security --user-data-dir=C:\aaa
- 点击确定,打开后就是跨域浏览器
proxy配制代理
-
修改.env.development内的基地址为 :
- VUE_APP_BASE_API = '/abc'
-
加入proxy配制
-
devServer:{ proxy: { '/abc': { target: 'http://localhost:3000/api', // 真实调用的接口基地址它会target+/abc=>http://localhost:3000/api/abc pathRewrite: { '^/abc': '' } } } }
-
-
重启脚手架
wl07-本地持久化的方式和区别
通过localStorage.getItem和localStorage.setItem,对用户的信息进行存储和获取
wl08-get请求和post请求的区别
-
GET使用URL或Cookie传参。而POST将数据放在BODY中。
-
GET的URL会有长度上的限制,则POST的数据则可以非常大。
-
POST比GET安全,因为数据在地址栏上不可见。
wl09-http的协议的三个内容
wl10-请求头中的contentType有什么用处
HTTP 请求头/响应头 Content-Type 用于向接收方说明传输资源的媒体类型
dom01-事件冒泡和事件捕获
事件冒泡
微软提出了名为事件冒泡(event bubbling)的事件流。事件冒泡可以形象地比喻为把一颗石头投入水中,泡泡会一直从水底冒出水面。也就是说,事件会从最内层的元素开始发生,一直向上传播,直到document对象。
因此上面的例子在事件冒泡的概念下发生click事件的顺序应该是
p -> div -> body -> html -> document
事件捕获
网景提出另一种事件流名为事件捕获(event capturing)。与事件冒泡相反,事件会从最外层开始发生,直到最具体的元素。
上面的例子在事件捕获的概念下发生click事件的顺序应该是
document -> html -> body -> div -> p
dom02-事件委托
事件委托,通俗地来讲,就是把一个元素响应事件(click、keydown......)的函数委托到另一个元素;
一般来讲,会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,当事件响应到需要绑定的元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数。
dom03-如何添加和删除事件
js添加移除事件的方法: 1、addEventListener()//添加事件,用于向指定元素添加事件句柄; 2、removeEventListener()//删除事件,用于移除由addEventListener()方法添加的事件句柄。
vue01-单个组件的生命周期钩子
触发钩子的完整顺序:
将路由导航、keep-alive
、和组件生命周期钩子结合起来的,触发顺序,假设是从a组件离开,第一次进入b组件:
beforeRouteLeave
:路由组件的组件离开路由前钩子,可取消路由离开。beforeEach
: 路由全局前置守卫,可用于登录验证、全局路由loading等。beforeEnter
: 路由独享守卫beforeRouteEnter
: 路由组件的组件进入路由前钩子。beforeResolve
:路由全局解析守卫afterEach
:路由全局后置钩子beforeCreate
:组件生命周期,不能访问this
。created
:组件生命周期,可以访问this
,不能访问dom。beforeMount
:组件生命周期deactivated
: 离开缓存组件a,或者触发a的beforeDestroy
和destroyed
组件销毁钩子。mounted
:访问/操作dom。activated
:进入缓存组件,进入a的嵌套子组件(如果有的话)。- 执行beforeRouteEnter回调函数next。
vue02-哈希路由和history路由的区别
单页应用是在移动互联时代诞生的,它的目标是不刷新浏览器,而通过感知地址栏中的变化来决定内容区域显示什么内容。要达成这个目标,我们要用到前端路由技术,具体来说有两种方式来实现:hash模式和history模式。
不同之处有三点。
一是原理不同。hash模式的实现原理是通过监听hashChange事件来实现的。history模式是通过调用 history.pushState方法(或者replaceState) 并且 监听popstate事件来实现的。history.pushState会追加历史记录,并更换地址栏地址信息,但是页面不会刷新,需要手动调用地址变化之后的处理函数,并在处理函数内部决定跳转逻辑;监听popstate事件是为了响应浏览器的前进后退功能。
二是表现不同。hash模式会在地址栏中有#号,而history模式没有;同时由于history模式的实现原理用到H5的新特性,所以它对浏览器的兼容性有要求(IE >= 10)。
三是history模式开发的SPA项目,需要服务器端做额外的配置,否则会出现刷新白屏(链接分享失效)。原因是页面刷新时,浏览器会向服务器真的发出对这个地址的请求,而这个文件资源又不存在,所以就报404。处理方式就由后端做一个保底映射:所有的请求全部拦截到index.html上。
vue03-哈希路由和history路由的原理
hash: 兼容所有浏览器,带#号,监听hash值的改变,触发hashchange事件,通过监听hashchange事件来完成操作实现前端路由。hash值变化不会让浏览器向服务器请求。
history: 兼容能支持 HTML5 History Api 的浏览器,依赖HTML5 History API来实现前端路由。没有#
,路由地址跟正常的url一样,但是初次访问或者刷新都会向服务器请求,如果没有请求到对应的资源就会返回404,所以路由地址匹配不到任何静态资源,则应该返回同一个index.html 页面,需要配置。
vue04-父子组件的生命周期钩子
子组件挂载完成后,父组件还未挂载。所以组件数据回显的时候,在父组件mounted中获取api的数据,子组件的mounted是拿不到的。
加载渲染过程
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
更新过程
父beforeUpdate->子beforeUpdate->子updated->父updated
销毁过程
父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
vue05-组件之间传参方式
-
props
/$emit
- 父组件向子组件传值
- 子组件向父组件传值
-
$children
/$parent
-
provide
/inject
-
ref
/refs
-
父组件调用子组件的方法
-
1.子组件的方法
-
methods:{ childMethod(){ alert("我是子组件的方法"); } }
-
2.父组件调用子组件的方法
-
<template> <child ref="child"></child> <div @click="parentMethod"></div> </template> methods:{ parentMethod(){ this.$refs.child.childMethod(); } }
-
-
eventBus
-
Vuex
-
localStorage
/sessionStorage
-
$attrs
与$listeners
vue06-v-mode和.sync的对比
v-model和.sync的区别
- v-model: 局限性只能传递一个属性, 如果只有一个 可以使用v-model
- sync: 能传递多个属性,多个依然需要使用.sync
vue07-vue路由钩子beforeEach的参数
to,from,next 这三个参数:
to和from是将要进入和将要离开的路由对象,路由对象指的是平时通过this.$route获取到的路由对象。
next:Function 这个参数是个函数,且必须调用,否则不能进入路由(页面空白)。
- next() 进入该路由。
- next(false): 取消进入路由,url地址重置为from路由地址(也就是将要离开的路由地址)。
- next 跳转新路由,当前的导航被中断,重新开始一个新的导航。
vue08-vuex的基本使用步骤
进入项目,在命令行中输入安装指令,回车
npm install vuex --save
然后配置 vuex,使其工作起来:在src路径下创建store文件夹,然后创建index.js文件,文件内容如下:
import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); const store = new Vuex.Store({ state: { // 定义一个name,以供全局使用 name: '张三', // 定义一个number,以供全局使用 number: 0, // 定义一个list,以供全局使用 list: [ { id: 1, name: '111' }, { id: 2, name: '222' }, { id: 3, name: '333' }, ] }, }); export default store; 复制代码
修改main.js:
import Vue from 'vue'; import App from './App'; import router from './router'; import store from './store'; // 引入我们前面导出的store对象 Vue.config.productionTip = false; new Vue({ el: '#app', router, store, // 把store对象添加到vue实例上 components: { App }, template: '<App/>' }); 复制代码
最后修改App.vue:
<template> <div></div> </template> <script> export default { mounted() { // 使用this.$store.state.XXX可以直接访问到仓库中的状态 console.log(this.$store.state.name); } } </script>
vue09-路由之间传参方式
vue10-vue路由钩子beforeEach的参数
vue11-vuex的getter的作用
对于getters的理解主要作用是对state属性进行计算,可以理解类似于Vue中computed
vue12-mutation和action的使用区别
mutation
-
在使用vuex对项目状态进行管理时,只能使用commit来提交mutation对store中的状态进行更改
-
mutation必须是同步函数
Action
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。
vue13-计算属性和watcher的使用区别
- watch:监测的是属性值, 只要属性值发生变化,其都会触发执行回调函数来执行一系列操作。
- computed:监测的是依赖值,依赖值不变的情况下其会直接读取缓存进行复用,变化的情况下才会重新计算。
- 计算属性不能执行异步任务,计算属性必须同步执行。也就是说计算属性不能向服务器请求或者执行异步任务。如果遇到异步任务,就交给侦听属性。watch也可以检测computed属性。
vue14-vue2中v-model是一个语法糖,那具体是怎么实现的?
它的本质上是
<input type="text" :value="name" @input="name = $event.target.value">
vue15-v-if和v-show的区别
(1)、v-if和v-show用于视图层进行条件判断视图展示
(2)、v-if的原理是根据判断条件来动态的进行增删DOM元素,v-show是根据判断条件来动态的进行显示和隐藏元素,频繁的进行增删DOM操作会影响页面加载速度和性能,由此我们可以得出结论:
当您的项目程序不是很大的时候,v-if和v-show都可以用来进行判断展示和隐藏(这种场景使用v-if只是影响不大,并不是没有影响);
当您的项目程序比较大的时候,不推荐使用v-if来进行判断展示和隐藏,推荐使用v-show;
(3)、只有v-if能和v-else连用进行分支判断,v-show是不能和v-else连用的,如果出现多种条件场景的情况下,可以使用v-if来进行判断
vue16-key的作用
1、key的作用主要是为了高效的更新虚拟dom,其原理是vue在patch过程中通过key可以精准判断两个节点是否是同一个,从而避免频繁更新不同元素,使得整个patch过程更加高效,减少dom操作量,提高性能。
2、另外,若不设置key还可能在列表更新时候引发一些隐藏的bug。
3、vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue可以区分它们,否则vue只会替换其内部属性而不会触发过渡效果。
vue17-vue2常用指令有哪些
vue18-vue2和vue3的区别
Vue3带来的新变化
-
性能提升(零成本:从vue2切到vue3就享受到)
首次渲染更快,diff算法更快,内存占用更少,打包体积更小,....
-
更好的Typescript支持(在vue下写TS更方便了)
-
提供新的写代码的方式:Composition API (需要学习成本)
这些Vue2.0的语法不能用了
-
移除了vue实例上的$on方法 (eventBus
Vue.prototype.$eventBus=new Vue(); this.$on('事件名', 回调)
现有实现模式不再支持,可以使用三方插件替代)。下边是vue2中eventBus的用法Vue.prototype.$eventBus = new Vue() 组件1 this.$on('事件名', 回调) 组件2 this.$emit('事件名')
-
移除过滤器选项 。下边是vue2中过滤器的用法:
<div>{{ msg | format}}</div> 插值表达式里, 不能再使用过滤器filter, 可以使用methods替代 {{format(msg)}}
-
移除 .sync语法(v-bind时不能使用.sync修饰符了,现在它v-model语法合并了)。下边是vue2中.sync的用法
<el-dialog :visibel.sync="showDialog"/>
vue19-vue2中过滤器是怎么使用的
在组建内创建局部过滤器
export default { data(){ return{ str:'hole word' } }, filters: { /* 不带参数的过滤器:字符串首字母大写 */ call(data){ /* data:管道符| 前面的数 */ return data.charAt(0).toUpperCase() + data.slice(1) }, /* 带有参数的过滤器:限制文本的长度 */ maxlength(data,maxnum){ /* data:管道符| 前面的数,maxnum:传入的参数 */ if(data.length>maxnum){ return data.slice(0,maxnum) + '...' } } },
使用过滤器:
/* Hole word */ <h1>{{str | call}}</h1> /* hole w... */ <h2>{{str | maxlength(6)}}</h2>
vue20-vue2中如何自定义指令
自定义全局指令语法
Vue.directive('自定义指令名称', { 生命周期名称: function (el) { 指令业务逻辑代码 } });
指令生命周期方法
自定义指令时一定要明确指令的业务逻辑代码更适合在哪个阶段执行
例如: 指令业务逻辑代码中没有用到元素事件, 那么可以在bind阶段执行
例如: 指令业务逻辑代码中用到了元素事件, 那么就需要在inserted阶段执行
如何自定义一个局部指令
给创建Vue实例时传递的对象添加
directives: { // key: 指令名称 // value: 对象 'color': { bind: function (el, obj) { el.style.color = obj.value; } } }
html代码:
<div id="app1"> <p v-color="'blue'">我是段落</p> </div> <div id="app2"> <p v-color="'red'">我是段落</p> </div>
vue21-vue2中vue.use是怎么用的
采用 ES6 的 import ... from ...语法或 CommonJS 的 require()方法引入插 件 使用全局方法 Vue.use( plugin )使用插件,可以传入一个选项对象 Vue.use(MyPlugin, { someOption: true })
vue22-vue2中$nextTick
因为vue是异步更新的,$nextTick是用来知道什么时候DOM更新完成的
vue23-什么是mvvm 、 mvc 模型?
MVC: MVC即model-view-controller(模型-视图-控制器)是项目的一种分层架构思想,它把复杂的业务逻辑,抽离为职能单一的小模块,每个模块看似相互独立,其实又各自有相互依赖关系。它的好处是:保证了模块的智能单一性,方便程序的开发、维护、耦合度低。
mvvm: MVVM:MVVM即 Model-View-ViewModel,(模型-视图-控制器)它是一种双向数据绑定的模式,用viewModel来建立起model数据层和view视图层的连接,数据改变会影响视图,视图改变会影响数据
vue24-vue双向数据绑定的原理?
-
vue.js 是采用数据劫持结合发布者-订阅者模式的方式
-
通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
-
具体步骤:
第一步:需要 observe 的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter 和 getter
这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化
第二步:compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
第三步:Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是:
1、在自身实例化时往属性订阅器(dep)里面添加自己
2、自身必须有一个update()方法
3、待属性变动dep.notice()通知时,能调用自身的 update() 方法,并触发Compile中绑定的回调,则功成身退。
第四步:MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。
vue25-组件中 data 为什么是一个函数?
因为vue的组件是会复用的,如果你的data是对象的话,你在其中一个组件修改了data的值,另外一个组件获取到的data是修改后的值,并不是初始值。这样就不能保证组件的data数据的唯一性。
而如果你的data是函数的话,data函数执行后返回的是初始值,并不会受到影响。
vue26-v-if和v-for为什么不能同时使用
因为v-for的优先级比v-if高会先循环渲染出数据后才会进行条件渲染判断 造成性能浪费
如果要在同一元素上使用可以使用 计算属性computed
vue27-Vue-router路由导航守卫有哪些?
全局前置/钩子:beforeEach、beforeResolve、afterEach 路由独享的守卫:beforeEnter 组件内的守卫:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave
这篇关于2022年前端面试集的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-25前端大厂面试真题解析与实战攻略
- 2024-12-25如何准备前端面试:新手指南
- 2024-12-25前端面试题详解与实战攻略
- 2024-12-25前端面试真题详解与实战攻略
- 2024-12-252024前端大厂面试真题详解及备考指南
- 2024-12-252024前端面试必备指南:从零开始掌握前端面试技巧
- 2024-12-252024前端面试题详解与实战指南
- 2024-12-21动态面包屑教程:新手入门指南
- 2024-12-21动态主题处理教程:新手必读指南
- 2024-12-21富文本编辑器教程:新手入门指南