前端面试八股文(最新版)
目录
一、基础(大概率不问)
1.如何理解HTML语义化的?
语义化标签时写html标签的一种方法论。
段落要写成p标签,标题我会用h1-h6之间,文章呢用article,那么时间我会用time标签,画板会用kawasi标签。
优点:适合搜索引擎来检索,适合人类阅读利于团队维护
2.HTML5有哪些新标签
回答:平常用的就是header、atikou
延伸问题:Canvas 和SVG的区别?
- Canvas 主要是用笔刷来绘制 2D 图形的;
- SVG 主要是用标签来绘制不规则矢量图的;
- 相同点:都是主要用来画 2D 图形的,也可以绘制3D不常用;
- 不同点:Canvas 画的是位图,SVG 画的是矢量图;
- SVG 它是一个个的节点,在SVG里面画一个圆是一个节点,画一个正方形是一个节点,节点多了必然会卡,那渲染的就肯定比较慢了,canvas他没有节点,所以他的渲染性能从理论上说是比较好的,但就是写的比较复杂;
- 还有就是SVG 支持分层和事件,Canvas 不支持,但是可以用库实现。
3. BFC是什么?
- 没有标准的话来定义,是块级格式化上下文。
- 一般来说用条件来触发他,
- 浮动,如果这个元素浮动了那这个元素就是BFC;
- 绝对定位,如果把这个元素定位了,这个元素就是BFC;
- 行内块元素,如果把这个元素inline变为 inline block,这个元素就是BFC;
- 如果你把他的overflow的值设置为hidden,只要不是visible就是BFC;
- 只要把display设置为flex或者inline-flex,那么他的子元素就是BFC。
延伸问题:解决了什么问题?
不知道解决了什么根源上的问题,但是我知道可以用来清除浮动、防止margin合并(两个垂直方向上的div他的margin是会合并的,但是只要有一个div触发了BFC就不会合并了)
4. 如何实现垂直居中?
注:如果外面的(父级)高度没有明确写出来,那么就写一句padding:10px 0;[上下都是10像素,就居中了]
如果父级的宽度有明确设定:
- flex
- Table自带属性;
- div装成table;
- 100%高度的after before + inline block;
- margin-top:50%;
- translate:50%;
- absolute:margin auto。
5. Css选择器的优先级如何确定?【背诵】
通配符是最低的。选择器越具体越优先;相同的优先级,后面的覆盖前面的;属性后面加了!import的优先级最高。
6. 如何清除浮动?
方法一:在父元素上加上.clearfix。
.clearfix:after{
Content:’’;
Display:block/table;
Clear:both;
}
方法二: 在父元素上添加overflow:hidden
7. var/ let / const 区别
- var 申明的函数作用域,let const 是块级作用域
- var 存在变量提升,let const 不存在
- var 允许重复申明,let const 不允许
- let 申明变量,const 声明常量
- let const 存在暂时性死区
二、Js [基础概念]
一个函数没有返回值和他返回undefined没办法区别
7. JS 的数据类型有哪些?
[8种]String、number、boolean、undefined、null、object、symbol、bigint
延伸问题:
1. 如果表示对象为空用null,如果表示非对象为空用undefined。
2. 为什么需要bigint? js的number它默认的是双精度浮点数,保存的位数是有限的,bigint 没有限,如果你这个数字特别大又想全部展现出来,由于js本身的number支持不了这个长有效位数的整数,这时候就用bigint。
3. 数组、函数、日期这三个是类,不是类型!
8. 数组的方法有哪些?
- push 向数组的末尾添加一个或多个,并返回新数组
- splice 删除或添加数组中的元素(我一般是用于删除的)
- includes:判断数组中是否包含某个值
- map 遍历数组
- forEach 遍历数组
ps:详情请转至 js 数组的方法_乐~~~的博客-CSDN博客
9. 原型链是什么
原型链涉及到的概念是比较多的,我先举例说一下,假设有一个普通对象x,x会有一个隐藏属性,这个属性会指向一个对象,这个对象叫object.prototype,因此得到一个公式,x的隐藏属性=object.prototype,这时候我们就说x的原型是object.prototype。
假设有一个数组对象a[],它也有隐藏属性叫___???___,这个时候呢a的隐藏属性正好等于Array.ptototype,可以说a的原型是Array.prototype,同时Array.prototype也有隐藏属性,Array.prototype的原型是object.prototype,由此呢就形成了两层原型,a的原型是Array.prototype,a的原型的原型是object.prototype,这样就形成了原型链条。
简说:a的原型是b,b的原型是c,原型链就是a b c。
a.__???__ = b,b.__???__=c
10. this的指向
在不同的场景中调用同一个函数,this的指向也有可能发生变化。
- 箭头函数中的this 指向函数作用域所用的对象
- 普通函数中,谁调用this就指向谁,如果没有调用,就指向window
- 构造函数中的this是指向实例
- 参考链接:JS中的this指向_Armin444的博客-CSDN博客
案例1 : 这个里面的this指的就是obj这个方法
let obj={ name:"测试", say:function(){ name:"测试1", console.log(this.name); } } obj.say(); //测试
案例2 :
-
函数的定义位置不影响其this指向,this指向只和调用函数的对象有关。
-
多层嵌套的对象,内部方法的this指向离被调用函数最近的对象。
let newObj={ name:"测试2", say:function(){ name:"测试3", console.log(this.name); } obj2:{ name:"测试4", skill:function(){ name:"测试5", console.log(this.name); //内部方法中的this 指的是调用函数最近的对象,所以这里指的是obj2 } } } newObj.say(); //测试2 newObj.obj2.skill();//测试4
11. JS 的 new 做了什么【记忆】
- 帮我创建临时对象/新对象(必做)
- 绑定原型【就是共有的属性】
- 帮我指定this=临时对象
- 执行构造函数
- 帮我返回临时对象(必做)
12. JS 的立即执行函数是什么【概念题】
声明一个匿名函数,这种做法,(执行的过程)立即执行他。
目的:通过它创建局部变量;兼容性好
写法:!function(){}()
- (立即函数); 可以用括号把整个函数包起来
- 可以只包函数
- 函数前可以加!、~、+、- 、new、var
13. JS 的闭包是什么?怎么用?
闭包是一种语法特性,js的所有函数都支持闭包,只要有函数+自由变量就是闭包,闭包不能用全局变量。【如果一个变量不是局部变量、不是全局变量,那么就是自由变量】
【缺点】:闭包使用不当,可能导致内存泄漏。
【讲解】:声明一个变量,它=一个立即执行函数,这个立即执行函数里面声明一个count,然后再声明一个函数对count进行操作。
【什么场景使用】优点:避免污染全局变量。提供对局部变量的间接访问。维持变量,使其不被垃圾回收。
【闭包形成的条件】:函数嵌套、内部函数引用外部函数
function fun(){ var count = 1; function fun2(){//条件1:函数嵌套 //形成条件2:内部函数引用外部函数 console.log(count); } } fun();
14. JS 如何实现类?
1. 第一种呢是使用原型,我们把他们对象本身的属性写在构造函数里面,把共有的属性写在原型上面。
Function Dog(name){ This.name=name; This.legsNum=4; } Dog.prototype.say=function(){ Console.log(); } Dog.prototype.kind=’狗’ Const d1=new dog(“哈哈”); D1.say();
2. 第二种是用class方法,吧对象本身的属性写在constructor里面,共有属性写在外面(没有办法申明在原型上面)。
Class Dog{ Kind=”狗”;//相当于在controctor里面写this.kind Constructor(name){ This.name=name; This.legsNum=4; } Say(){ Console.log(‘哈哈哈,我是${this.name}’); }} Const d1=new Dog(“小猴狗”); D1.say()
3. class没有提供在原型上添加非函数属性的方法。
15. JS 如何实现继承?
自身属性要继承,共有属性要继承
class Animal{
constructor(legsNumber){ss
this.legsNumber = legsNumber //animal本身的属性
}
run(){}
}
class Dog extends Animal{
constructor(name) {
super(4)
this.name = name
} // run(){}
say(){
console.log(`汪汪汪~ 我是${this.name},我有${this.legsNumber}条腿。`)
}
}
16. 判断数据类型的方法
1. typeof
返回的数据类型:string,number,boolean,symbol,bigint,unfined,object,function
延伸问题:为什么typeof null 是 Object?
因为在JavaScript中,不同的对象都是使用二进制存储的,如果二进制前三位都是0的话,系统会判断为是Object类型,而null的二进制全是0,自然也就判断为Object
2.instanceof 根据原型链判断
- 判断引用数据类型的,判断基本数据类型无效
17. 作用域和作用域链
(1)作用域:
- 全局作用域:变量,函数在整个全局中都能被访问到;
- 局部作用域:函数,{}内部声明的变量和函数
(2)作用域链:
上下级之间的不同作用域构成作用域链。
- 内部函数访问外部函数函数变量就是采取的是作用域链查找
18.事件流有三个阶段:
- 事件捕获阶段:从window逐层向下传递到目标元素(父级到子级),过程中遇到注册的捕获事件就触发它;
- 处于目标阶段:事件达到目标元素,触发目标元素上注册的事件
- 事件冒泡阶段:从目标元素向上传递到window(子级到父级),过程中遇到注册的冒泡时间就会触发它
三、js 重点
1. 遍历数组
let test=[{
"id":1,"name":"圣诞节佛"
},{
"id":2,"name":"圣诞水电费节佛"
}]
test.forEach((element)=>{
console.log(element);
})
let test=[{
"id":1,"name":"圣诞节佛"
},{
"id":2,"name":"圣诞水电费节佛"
}];
let tests=[];
test.map((element)=>{
if(element.id==1){
tests.push(element);
}
});
console.log("1",test);
console.log("2",tests)
2. 排序方法
2.1 冒泡排序
<script>
data(){
a:[1,23,456,67,78,34,567]
},
mounted(){
this.init();
},
methods:{
init(){
this.maopaoSort(this.a);
console.log(this.a); //[1,23,34,67,78,456,567]
},
sortt(arr){
const len=arr.length;
if(len<2){
return arr;
}else{
for (let i = 0; i < len; i++) {
for(let j=0;j<i;j++){
if(arr[j]>arr[i]){
const temp=arr[j];
arr[j]=arr[i];
arr[i]=temp
}
}
}
return arr;
}
}
}
</script>
2.2 选择排序
let a = [1, 75,8,5,96];
function selectSort(array) {
const len = array.length
let temp
let minIndex
for (let i = 0; i < len - 1; i++) {
minIndex = i
for (let j = i + 1; j < len; j++) {
if (array[j] <= array[minIndex]) {
minIndex = j
}
}
temp = array[i]
array[i] = array[minIndex]
array[minIndex] = temp
}
return array
}
selectSort(a);//[1,5,8,75,96]
3. 数据去重
3.1 set (*****必会)
let a=[1,2,4,5,2,4,2,2,2,1,4,5,6,7,6];
let b=Array.from(new Set(a));
console.log(b)//[1, 2, 4, 5, 6, 7];
3.2 filter+includes
function test(params) {
let newarr=[];
newarr=params.filter(function (item) {
return newarr.includes(item)?'':newarr.push(item);
})
return newarr;
}
console.log(test([1,1,5,5,84,22,45,88,55,7,5])); //[1, 5, 84, 22, 45, 88, 55, 7]
ps: 上面这俩种只能处理基本类型的数组,对于数组里面是对象的这种,就直接返回原值。
4. 深浅拷贝
浅拷贝:如果是基本类型,则拷贝的是基本类型的值(拷贝一层);如果是引用数据类型的话,就是拷贝地址。
深拷贝:不会只传地址,而是会开辟一个新的空间,然后复制到另一个空间。
浅拷贝方法:
Object.assign(target,sources) //target 你要拷贝给谁,这个就是人家的名字;sources 是被拷贝的那个。
let obj={ id:1, name:'anya', msg:{ age:18 } }; let o={}; Object.assign(o,obj); o.msg.age=20; //浅拷贝,o里面的值变了,obj里面的值也会随之改变 console.log(o); console.log(obj);
还有一种:扩展运算符
let arr=[1,1,2]; let newArr=[...arr]; console.log(newArr); //[1,1,2]; newArr[0]=22; console.log(newArr);//[2,1,2] console.log(arr);//[1,1,2]
深拷贝方法:JSON.stringigy();
let a=[1,2,3,{name:1,dsc:"sfj圣诞节佛了"}]; let b=JSON.stringify(a) console.log(b) //[1,2,3,{name:1,dsc:"sfj圣诞节佛了"}]; b[3]=12; console.log(a);//[1,2,3,{name:1,dsc:"sfj圣诞节佛了"}];
5. promise
利用promise可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。promise是同步的,then是异步的。promise必须实现then方法,then方法接收两个回调函数,他们分别是成功时的回调和失败时的回调。
promise 的三种状态:
promise的三种状态:
- pending 初始状态
- resolved 操作成功
- rejected 操作失败
promise 的方法
- promise.all()
- promise.reace()