前端面试题

本文详细探讨了前端面试中的核心问题,包括从输入网址到页面显示的过程、HTML页面渲染、Vue框架的理解与原理,以及组件封装、通信、路由、状态管理和事件处理等方面。此外,还涵盖了Vue的生命周期、数据绑定、DOM操作、CSS布局、浏览器工作原理、网络请求、存储机制和各种编程概念。是前端开发者面试准备的重要参考资料。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

从输入网址到页面显示的过程?

DNS解析

发起TCP连接(三次握手、四次挥手)

发送HTTP请求

服务器处理请求并返回HTTP报文

浏览器解析渲染页面

连接结束

HTML页面渲染过程?

解析HTML文件,创建DOM树

解析CSS,形成CSS对象模型

将CSS与DOM合并,构建渲染树

布局和绘制

对Vue的理解?

用于创建用户界面的开源JavaScript框架

用于创建单页面的Web应用框架

用于创建用户界面的渐进式MVVM框架

Vue关注的核心是MVC模式中的视图层

Vue便于与第三方库或既有项目整合

双向绑定的原理?

MVVM模型:

Model:数据层   View:视图层   ViewModel:业务逻辑层

ViewModel:将视图和数据关联起来,由监听器和解析器组成

1、Vue实例初始化,对data执行响应化处理,这个过程发生在监听器中

2、对模板编译,找到动态绑定的数据,从data中获取并初始化试图,这个过程发生在解析器中

3、定义一个更新函数和Watcher,将来对应数据变化时会调用更新函数

Vue生命周期?

beforeCreate:vue实例的生命周期相关属性的初始化以及事件的初始化

created:完成vue的数据注入以及数据监听操作

beforeMount:模板的解析。vue会判断实例中是否含有el属性,如果没有停止编译,知道调用vm.$mount(el)才会继续编译,接着会判断是否含有template属性,如果有将其解析为一个render function,如果没有将el指定的外部html进行解析

mounted:创建vm.$el替换el,执行了render函数,将模板进行了解析,将数据进行了动态绑定。

beforeUpdate---updated---beforeDestroy---destroyed

1、new Vue会调用_init方法

2、调用$mount方法进行页面挂载

3、挂载的时候主要通过mountComponent方法

4、执行render生成虚拟DOM

5、_update将虚拟DOM生成真实DOM结构,并渲染到页面中

组件封装

写组件---引入组件---注册组件---使用组件

组件间通信

父组件传递数据给子组件

1、子组件设置props属性,接受父组件传递过来的参数

2、父组件在使用子组件标签中通过字面量来传递值

子组件传递数据给父组件

1、子组件通过$emit触发自定义事件,第二个参数为传递的数值

2、父组件绑定监听器获取到子组件传递过来的参数

兄弟组件传递数据

1、创建一个中央时间总线Bus

2、一个兄弟组件通过$emit触发自定义事件,第二个参数为传递的数值

3、另一个兄弟组件通过$on监听自定义事件

祖先组件传递数据给子孙组件

1、在祖先组件定义provide属性,返回传递的数值

2、在后代组件通过inject接收祖先组件传递的数值

复杂关系的组件数据传递可以通过vuex存放共享的变量

路由机制

1、先引入vue,再引入vueRouter---<script src=''>

2、定义一个路由对象数组,由route路由对象组成---[{},{},{}]

3、创建路由器对象router(声明路由器对象实例)---new VueRouter

4、注册路由器对象(将路由实例对象导入vue实例对象)---router

5、使用路由(实现路由切换)---<router-link to=''>

6、路由组件显示的位置(路由出口,匹配路由组件,渲染到这个区域)---<router-view>

hash路由和history路由的区别

1、hash路由在地址栏URL上有#,而history路由没有会好看一点

2、进行回车刷新操作,hash路由会加载到地址栏对应的页面,而history路由一般就404报错了(刷新是网络请求,没有后端准备时会报错)。

3、hash路由支持低版本的浏览器,而history路由是HTML5新增的API。

状态机

1、生成仓库/状态机配置对象---五个属性可选

2、生成Vuex Store构造函数的状态机---new Vuex.Store

3、注册状态机---router

4、访问状态机中的数据---$store.state.xx或鼠标触发提交突变、分发动作

状态机的五个参数

1、State:在State中存放状态,可将状态理解为组件中的data,

只不过在state中一般存放的是组件共享的数据,而在组件内的data中一般存放组件的私有数据

2、getters:类似于computed属性,对state中的属性处理之后再返回,从state中派生出来的

默认参数为state

3、mutations:突变,同步操作,唯一修改state中数据的方式

参数为state、payload,state为默认参数类似于事件中的event,payload载荷形参

4、actions:动作,存放的是异步请求

参数为sto、payload,sto是类状态机对象解构出来{commit,dispatch,state,getters},payload同上

提交突变:sto.commit('changMsg',res);

第一个参数是触发突变的事件名称,第二个参数是获取到的后台数据

分发动作:sto.dispatch('getAll',[])

第一个参数是分发动作的事件名称,第二个参数是要传递的数据

5、modules:模块化

mapState和mapGetters写在computed中,mapMutations和mapActions写在methods中

插槽

在插槽默认模板中,可以直接访问子组件的数据,可以通过props间接访问父组件的数据。

在插槽自定义模板中,可以直接访问父组件的数据,可以通过作用域插槽间接访问子组件的数据。

混入规则

当组件和混入对象有同名选项时,这些选项会以恰当的方式合并

data:会进行合并,发生冲突时,保留组件的数据

methods、computed:methods会合并,如果对象的键名发生冲突,则保留组件的键值对

生命周期钩子函数:同名的钩子函数会被合并为一个数组,依次被调用且混入对象的先被调用

v-if和v-show的区别?

1、v-if支持v-else-if、v-else,v-show 不支持 v-else。

2、v-if对应的是元素/标签的添加或者删除。

满足条件添加元素/标签,不满足条件删除元素/标签

3、v-show对应的是元素的CSS样式中的display属性。

满足条件对应的是元素的显示 display:block,不满足条件对应的是元素的隐藏 display:none

4、v-show 不管初始条件是啥,元素总会被渲染。v-if 只有条件变为真时,才会开始渲染条件块。

5、v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。

如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。

watch和computed的区别

watch:支持异步,不支持缓存

数据变化时执行异步或开销较大的操作

computed:不支持异步,支持缓存,只要依赖数据不变,就不会重新计算

变量是经过某种计算然后输出而不是直接输出

为什么在大型项目中data是一个函数而不是一个对象?

根实例对象data可以是对象也可以是函数,不会产生数据污染

组件实例对象data必须为函数,目的是为了防止多个组件实例对象之间共用一个data产生数据污染

key?

1、v-for:key 具有唯一标识当前组件不被复用

2、:key = '+new Date()',手动强制触发重新渲染

过滤器?

双花括号插值---v-bind表达式

常见修饰符?

.stop:停止事件冒泡    

.capture:在事件捕获阶段执行事件处理函数

.prevent:阻止事件默认行为

.self:只当在 event.target 是当前元素自身时触发处理函数

.once:事件处理函数执行一次后解绑

.passive:滚动行为将会立即触发 ,一般与scroll连用,能够提升移动端的性能

<keep-alive>

默认情况下,当组件在切换的时候都会重新创建组件。

<keep-alive> :组件实例能够被在它们第一次被创建的时候缓存下来。

Ajax

1、创建Ajax实例对象---let xhr = new XMLHttpRequest();

2、打开一个连接---xhr.open(请求方式,请求路径),其中请求方式为必填参数

①get请求:地址栏请求字符串,要用qs转换js对象---Qs.stringify()

②post请求:参数携带在请求体send()中

        设置请求头为表单格式,发送请求时要用qs转换js对象---Qs.stringify()

        设置请求头为JSON格式,发送请求时要用JSON转换js对象---JSON.stringify()

3、发送请求---xhr.send();

4、接收响应---xhr.onreadystatechange = function(){ }

get和post的区别

1、get,参数url可见;post,参数url不可见

2、get请求是可以缓存的;post请求不可以缓存

3、get一般传输数据大小较小;post请求传输数据的大小较大

4、原则上post肯定要比get安全

cookie、localStorage和sessionStorage的区别

cookie生命期为只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。

localStorage生命周期是永久的,关闭页面或浏览器之后 localStorage 中的数据也不会消失。

sessionStorage 的生命周期是仅在当前会话下有效。

http状态码

1xx:信息提示,表示临时的响应。

2xx:成功,表示服务器成功地接受了客户端请求。

3xx:重定向,表示客户端浏览器必须采取更多操作来实现请求。

4xx:客户端错误

5xx:服务器错误

BFC

直译为块级格式化上下文,可以理解成一块独立的渲染区域,BFC看成元素的一种属性。

当元素拥有了BFC属性后,这个元素就可以看做隔离了的独立容器,容器内的元素不会影响容器外的元素。

overflow值不为visible的元素        html根元素        display

避免外边距重叠        清除浮动        阻止元素被浮动元素覆盖

伸缩盒布局,弹性盒布局(display:flex)

给容器父元素使用,将子元素放在一行排列布局

垂直居中

法一:父元素设置border,子元素设置border和margin

法二:父元素设置padding和边框盒子

法三:子元素绝对定位,父元素相对定位,并且给子元素设置定位属性全部为0(top、left、bottom 、right),margin:auto

法四:子元素绝对定位,父元素相对定位,并且给子元素设置定位属性top:50%,left:50%,margin-left:-width/2,margin-top:-height/2

法五:父元素设置伸缩盒布局,在父元素中设置子元素在主轴和交叉轴的对齐方式都为居中(display: flex; justify-content: center; 和 align-items: center;)

文本溢出显示省略

text-overflow: ellipsis;        white-space: nowrap;        overflow: hidden;

link和@import的区别?

link是HTML标签,@import是CSS提供

页面被加载时,link会同时被加载,@import得等到页面被加载完再加载

link无兼容问题,@import只在IE5以上版本才能识别

link方式的样式权重高于@import

src和href的区别?

src:把资源下载到页面中

href:超文本引用,指向资源的位置,建立与目标文件的联系

display:none、visibility:hidden和opacity:0的区别?

display:none是彻底消失,不在文档流中占位,浏览器不会解析该元素,不可点击,不可继承

visibility:hidden是视觉上消失,在文档流中占位,浏览器会解析该元素,不可点击,可继承

opacity:0是是视觉上消失,在文档流中占位,浏览器会解析该元素,可点击,不可继承

px、em、rem和vh/vw的区别?

px:绝对单位,页面按精确像素显示

em:相对单位,相对父节点字体的大小

rem:相对单位,相对根节点html字体的大小

vh/vw:用于页面视口大小布局

媒体查询?

在不改变内容的情况下,改变页面的布局以精确适应不同的设备

实现响应式布局?

媒体查询、百分比、vw/vh、rem

typeof

检测数据类型,可检测到string、number、boolean、undefined、object、function

检测一个属性是否属于某个对象,返回true或false

'属性名' in obj:自有属性或者继承属性

obj.hasOwnProperty('属性名'):自有属性

obj.propertyIsEnumerable('属性名'):自有属性且可枚举

instaceof

检测是否是构造函数的实例

undefined 与null关系

undefined继承null,但是null表示空对象,undefined表示未定义;

数组API

arr.toString()将数组转化为字符串
arr.join("分隔符")将数组转化为字符串
Array.from(arr)将类数组对象转换为一个数组
Array.prototype.slice.call(childs,0);将字符串转换为一个数组
let [...str] = 'hello';将字符串转换为一个数组
Array.isArray(arr)判断是否为数组
arr.push('tom',{age:13})添加最后一个元素,返回新的长度改变原数组
arr.pop()删除并返回最后一个元素改变原数组
arr.unshift([5,6,7,8],function test(){})添加第一个元素,返回新的长度改变原数组
arr.shift()删除并返回第一个元素改变原数组
arr.reverse()颠倒顺序改变原数组
arr.sort()排序改变原数组
arr.sort(function(a,b){ })按指定规则排序改变原数组
arr.concat(arr1,arr2,arr3)拼接数组不改变原数组
arr.slice(1,2)

截取并返回新数组

参数是索引( start end(不包含))

不改变原数组
arr.splice(1)删除并返回下标从1开始到结尾的数组改变原数组
arr.splice(0,2)删除并返回下标从0开始长度为2的数组改变原数组
arr.splice(2,0,'lavender')在下标为2的位置上添加元素,并返回空数组改变原数组
arr.indexOf('zhangsan111')返回索引不改变原数组
arr.lastIndexOf("tom")返回索引不改变原数组
arr.every(function(item,index,arr){return item>12; })所有元素通过检测返回true不改变原数组
arr.some(function(item,index,arr){return item>12;})只要有一个元素通过检测返回true不改变原数组
arr.map(function(item,index,arr){return item.id; })返回对每一项数组元素做了操作之后的一个新数组不改变原数组
arr.filter(function(item,index,arr){return item.id; })返回符合条件的元素创建的新数组不改变原数组

arr.forEach(function(item,index,arr)

{ })

调用数组的每一个元素

没有返回值

不改变原数组

ES6数组静态方法和实例方法API扩展

Array.of():创建数组,参数:数组元素,返回值:新数组

arr.find(): 参数:回调函数 返回值:返回第一个满足条件的元素

arr.findIndex():参数:回调函数,返回值:返回满足条件的第一个元素的索引或者-1

arr.fill():修改(填充)原数组,参数:填充的数组元素,返回值:填充好的新数组

对象API

对象序列化即将对象转换为JSON字符串:JSON.stringify(obj)

反序列化即将字符串还原为对象:JSON.parse(json)

ES6对象静态API扩展

Object.is():判断两个值是否相等

Object.assign():两个参数:复制/拷贝,三个参数:合并对象

Object.getPrototypeOf():获取原型对象

Object.setPrototypeOf():设置原型对象

Object.keys():获取属性名组成的数组,参数:目标对象

Object.values():获取属性值组成的数组,参数:目标对象

Object.entries():获取键值对(属性名和属性值)组成的数组,参数:目标对象

什么是原型?

每一个构造函数都有一个原型对象(Object.prototype),

每一个原型对象都有一个指针指向构造函数(Object.prototype.constructor)

实例都包含一个指向原型对象的指针(obj.__proto__)

this指针

在方法中,this 表示该方法所属的对象。

普通函数调用,this 表示全局对象。

如果单独使用,this 表示全局对象。

在事件中,this 指向接受事件的html元素。

箭头函数的this始终指向函数声明时所在作用域下的 this 的值

函数名.call(执行环境对象,实参列表);

函数名.apply(执行环境对象,实参列表数组);

函数名.bind(执行环境对象)(实参列表);:bind方法返回的只是一个修改过后的函数

new操作符做了什么

创建了对象---this指向这个对象---执行函数体---返回这个对象

四种模式

        批量创建对象,封装创建对象的函数,提高代码复用性。

工厂模式:创建出来的对象都是Object类型,无法区分对象种类。将函数声明成全局变量解决方法空间浪费,但是会产生方法冗余问题

构造函数模式可以区分对象种类,但方法冗余

原型模式:解决了方法冗余,所有实例共享的属性和方法,但是私有属性得不到维护

        原型模式不单独使用,构造函数中什么都不放,将所有的属性和方法都放到原型对象中

组合模式:构造函数模式+原型模式

        构造函数中放实例私有的属性,构造函数原型对象中放公共属性和方法

继承

原型链继承子构造函数的原型指向父构造函数的实例

构造函数继承、经典继承在子类构造函数内调用父类构造函数

组合继承(原型继承+经典继承)

DOM0级事件和DOM2级事件的区别

DOM0级事件--不可追加事件

DOM2级事件--可追加事件

追加:addEventListener(事件类型,事件处理程序,布尔值)

        true--在捕获阶段执行,false--在冒泡阶段执行

解绑:removeEventListener(事件类型,事件处理程序(具名函数))

阻止事件冒泡

event.stopPropagation()

阻止事件默认行为

event.preventDefault()

CommonJS和ES6的区别

ES6输出的是值的引用(浅拷贝),CommonJS输出的是值的拷贝/复制(深拷贝)

ES6模块是编译时输出接口,CommonJS模块是运行时加载

Symbol

表示独一无二的值---全局注册表

Symbol.for(key) :创建的的symbol 会被放入一个全局symbol 注册表中。

Symbol.keyFor():检测symbol值是否在全局注册过,返回key或者Undefined。

迭代器Iterator

Array、Map、Set、String、TypedArray、arguments、NodeList

for-of实现原理就是调用迭代器的next()方法

Set

Set类似于数组,但是成员的值都是唯一的,没有重复的值。

Map

Map类似于对象,也是键值对的集合,但是“键”的范围不限于字符串。

数组去重

使用双层for循环+splice()进行数组去重(删除数组中重复的元素)

利用indexOf()+push()进行数组去重(在新数组中添加新数组查找不到的元素)

利用includes()+push()进行数组去重(在新数组中添加新数组不包含的元素)

利用set进行数组去重(set成员唯一的,数组转set再转数组)

Promise

回调函数的两个参数分别是resolve和reject

Promise的三种状态pending(进行中)、fulfilled(已成功)和rejected(已失败)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值