前端面试题总结

it2023-01-11  58

css部分

1、css盒模型?

盒子由:content、padding、border、margin四部分组成。

盒子模型有两种:

标准盒模型怪异盒模型

标准和怪异模型的转换: 1.box-sizing:content-box; 标准盒模型 2.box-sizing:border-box; 怪异盒模型 3.box-sizing:inherit; 规定应从父元素继承 box-sizing 属性的值。

2、css布局中的BFC问题

BFC就是格式化上下文的意思,它是一块独立的布局环境,内部元素不受外界影响,也不会影响外部

如何触发BFC?

overflow: auto/ hidden;position: absolute/ fixed;float: left/ right;display: inline-block/ table-cell/ table-caption/ flex/ inline-flex

解决问题:父子边距重叠、兄弟边距重叠

1.父级边距重叠可以把父元素设置为BFC(overflow:hidden) 2.同级边距重叠可通过添加空元素或伪类元素,设置overflow:hidden;

BFC的应用场景?

1.可以用来自适应布局 2.可以清除浮动 3.解决垂直边距重叠

3、清除浮动的几种方式

为什么要清除浮动?

答:清除浮动主要是为了解决,父元素因为子级元素浮动引起的内部高度为0的问题

清除浮动的几种方式:

1.添加空标签:给谁清除浮动,就在该标签后面添加一个空标签,并设置clear:both属性
2.给父级添加overflow:hidden方法
3.使用after伪元素清除浮动

注: zoom(IE专有属性)可解决ie6,ie7浮动问题

用法:

.clearfix:after{/*伪元素是行内元素 正常浏览器清除浮动方法*/ content: ""; display: block; height: 0; clear:both; visibility: hidden; } .clearfix{ *zoom: 1;/*ie6清除浮动的方式 *号只有IE6-IE7执行,其他浏览器不执行*/ }
4.使用before和after双伪元素清除浮动

用法:

.father{ border: 1px solid black; *zoom: 1; /*ie6清除浮动的方式 *号只有IE6-IE7执行,其他浏览器不执行*/ } .clearfix:after,.clearfix:before{ content: ""; display: block; clear: both; }
5.给父元素设置固定高度

4. div上下水平垂直居中

方法一:父相自绝后,子元素分别向左向上移动本身宽度和高度的一半(也可以用 transform:translate(-50%,-50%))

子元素代码: position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px;

方法二:父元素设置成弹性盒,子元素横向居中,纵向居中
方法三:父向子绝,子元素所有定位为0,margin设置auto自适应。

js部分

一、原型,原型链

1. prototype

每个函数都有一个prototype属性,被称为显示原型

2._ proto _

每个实例对象都会有_ _proto_ _属性,其被称为隐式原型

每一个实例对象的隐式原型_ _proto_ _属性指向自身构造函数的显式原型prototype

3. constructor

每个prototype原型都有一个constructor属性,指向它关联的构造函数。

4. 原型链

获取对象属性时,如果对象本身没有这个属性,那就会去他的原型__proto__上去找,如果还查不到,就去找原型的原型,一直找到最顶层(Object.prototype)为止。Object.prototype对象也有__proto__属性值为null。

注意:Object是属于原型链的顶层,所有构造函数的的prototype都指向 Object.prototype

二、作用域

概念

变量作用域:就是一个变量可以使用的范围。

作用域种类

js中有一个最外层的作用域,全局作用域js中可以通过函数来创建一个独立作用域称为函数作用域,函数可以嵌套,所以作用域也可以嵌套es6中新增了块级作用域(大括号,比如:if{},for(){},while(){}…)

注意: es6作用域,只适用于const,let

三、自由变量

自由变量的概念: 当前作用域没有定义的变量

注:所有的自由变量的查找,是在函数定义的地方,向上级作用域查找 不是在执行的地方!!!

作用域链

自由变量向上级作用域一层一层查找,直到找到为止,最高找到全局作用域,就形成了作用域链。

变量提升(预解析)

var声明的变量,function声明的函数存在变量提升 let const 不会变量提升

四、闭包

1. 如何产生闭包(closure)

2. 闭包的应用场景

闭包应用场景1,封装对象的私有属性和方法

隐藏数据 做一个简单的缓存工具

// 闭包隐藏数据,只提供 API function createCache() { const num=100 const data = {} // 闭包中的数据,被隐藏,不被外界访问 return { num:num, set: function (key, val) { data[key] = val }, get: function (key) { return data[key] } } } const c = createCache() console.log(c.num)//num此时就作为c私有属性 c.set('a', 100) //set此时作为c的私有方法 console.log( c.get('a') )
闭包应用场景2,闭包作用回调函数
<body> <a href="#" id="as1">20</a> <a href="#" id="as2">40</a> </body> <script> function changeSize(size){ return function(){ document.body.style.fontSize=size+'px'; } } var size20=changeSize(20); var size40=changeSize(40); document.getElementById('as1').onclick=size20; document.getElementById('as2').onclick=size40; </script>
闭包应用场景3,函数节流防抖
<body> <!-- 函数防抖是指在函数被高频触发时当停止触发后延时n秒再执行函数, (即每次触发都清理延时函数再次开始计时),一般用于resize scroll,mousemove --> <!-- 函数节流 原理 函数被高频出发时延时n秒后才会再次执行,防抖主要是用户触发一次时间后,延迟一段时间触发, 而节流会规定的事件内触发一次事件 --> </body> <script> // 函数节流:是确保函数特定的时间内至多执行一次。 // 函数防抖:是函数在特定的时间内不被再调用后执行。 //防抖 var debounce = function(func, delay) { var timer = null return function() { var that = this; var args = arguments; if(timer) { clearTimeout(timer); } timer = setTimeout(function() { func.apply(that, args); }, delay) } } ipt.addEventListener('keyup', debounce(function(e){ console.log(e.target.value); }, 400)) </script>

3.面试问:怎么理解闭包

1.什么是闭包?

①函数嵌套函数; ②内部函数可以直接访问外部函数的内部变量或参数; ③变量或参数不会被垃圾回收机制回收。

2.闭包优点?

①变量长期驻扎在内存中; ②避免全局变量的污染; ③私有成员的存在。

3.闭包的应用场景?

①函数作为参数被传递 ②函数作为返回值被返回 ③实际应用(隐藏数据):为什么说隐藏数据了呢,因为普通用户只能通过get、set等api对数据进行查看和更改等操作,没法对data直接更改,达到所谓隐藏数据的效果;jquery就利用了这一特性,必须调用$.ajax()才能访问内部属性方法。 封装功能时(需要使用私有的属性和方法), 函数防抖、函数节流 单例模式

4.闭包的缺点?

常驻内存,增大内存的使用量,使用不当会造成内存泄漏。

五、this

5大调用场景:

普通函数、 对象方法、 call apply bind class 箭头函数

注意:this取什么值,是在执行时确认的,定义时无法确认

全局下,普通函数fn1执行,相当于window执行了fn1函数,所以this是window call apply bind可以修改this

function fn1(this={x:100}){ fn1,call({x:100}) ==> console.log(this) }

bind也可以修改,但是多了一步执行。

对象方法中的this,指向当前对象(因为当前对象执行了方法)。 setTimeout函数中的this,相当于普通函数中的this,因为setTimeout触发的函数执行,并不是外部对象执行的。 setTimeout中函数是箭头函数,this为当前对象。因为箭头函数中的this始终是父级上下文中的this.

es6 class中的this,当前实例本身。

this总结 (重要)

普通函数中调用,this指向window 对象方法中调用,this指向当前对象 call apply bind中调用, this指向被传入的对象 class中的方法中调用, this指向实例对象 箭头函数,this就是父级上下文中的this

六、什么是宏任务和微任务

宏任务包括:setTimeout setInterval Ajax DOM事件 微任务:Promise async/await 微任务比宏任务的执行时间要早

任务列队和event loop(事件循环)

1)所有的同步任务都在主线程上执行,行成一个执行栈。 2)除了主线程之外,还存在一个任务列队,只要异步任务有了运行结果,就在任务列队中植入一个时间标记。 3)主线程完成所有任务(执行栈清空),就会读取任务列队,先执行微任务队列在执行宏任务队列。 4)重复上面三步。

只要主线程空了,就会读取任务列队,这就是js的运行机制,也被称为 event loop(事件循环)。

执行顺序

1.主线程上宏任务、微任务执行顺序

console.log('---start---');//第一轮主线程 setTimeout(() => { console.log('setTimeout'); // 将回调代码放入个宏任务队列,第二轮宏任务执行 }, 0); new Promise((resolve, reject) => { console.log('---Promise第一轮微任务同步执行---');//第一轮微任务同步执行 resolve() }).then(()=>{ console.log('Promise.then实例成功回调执行'); // 将回调代码放入微任务队列,第一轮宏任务执行完后立即执行 }); console.log('---end---');//第一轮主线程结束

执行顺序:主线程 >> 主线程上创建的微任务 >> 主线程上创建的宏任务

2.宏任务中包含微任务

// 宏任务队列 1 setTimeout(() => { // 宏任务队列 2.1 console.log('timer_1'); setTimeout(() => { // 宏任务队列 3 console.log('timer_3') }, 0) new Promise(resolve => { resolve() console.log('new promise') }).then(() => { // 微任务队列 1 console.log('promise then') }) }, 0) setTimeout(() => { // 宏任务队列 2.2 console.log('timer_2') }, 0) console.log('========== Sync queue ==========')

执行顺序:主线程 >> 主线程上的宏任务队列1 >> 宏任务队列1中创建的微任务

七、事件代理(委托)

概念:

事件委托,又名事件代理。事件委托就是利用事件冒泡,就是把子元素的事件都绑定到父元素上。如果子元素阻止了事件冒泡,那么委托也就没法实现了。

好处:

提高性能,减少了事件绑定,从而减少内存占用

应用场景 在vue中事件委托

我们经常遇到vue中v-for一个列表,列表的每一项都绑定了@click处理事件。我们都知道绑定这么多监听,从性能方面来说是不太好的。那我们我们可以通过把每个item的click事件委托给父元素的形式来实现。

获取item元素中title值为edit的id

//html <table @click="edit"> <tr v-for="item in list"> <td>{{item.name}}</td> ... <td> <button :data-id="item.id" title="eidt">编辑</button> </td> </tr> </table> //js edit (event){ if(event.target.title == "edit"){ //如果点击到了edit let id = evenr.target.dataset.id; //拿着id参数执行着相关的操作 this.$router.push({path:'/detail',query:{id:id}}) } }

八、Promise

1. 为什么有Promises这个东西 ?

同步的方式写异步的代码,用来解决回调地狱问题。此外,promise对象提供统一的接口,使得控制异步操作更加容易。

2. 什么是Promise?

Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的的最终状态(成功或失败)。Promise是一个构造函数,对外提供统一的 API,自己身上有all、reject、resolve等方法,原型上有then、catch等方法。

3.Promise的两个特点?

1、Promise对象的状态不受外界影响

1)pending 初始状态

2)fulfilled 成功状态

3)rejected 失败状态

Promise 有以上三种状态,只有异步操作的结果可以决定当前是哪一种状态,其他任何操作都无法改变这个状态

2、Promise的状态一旦改变,就不会再变,任何时候都可以得到这个结果,状态不可以逆,只能由 pending变成fulfilled或者由pending变成rejected


4.使用 new 来创建一个promise对象

Promise接受一个「函数」作为参数,该函数的两个参数分别是resolve和reject。这两个函数就是就是「回调函数」

resolve函数的作用:在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;

reject函数的作用:在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。


5.Promise的API

then()方法

then 方法就是把原来的回调写法分离出来,在异步操作执行完后,用链式调用的方式执行回调函数。

而 Promise 的优势就在于这个链式调用。我们可以在 then 方法中继续写 Promise 对象并返回,然后继续调用 then 来进行回调操作。

可有两个参数,第一个是成功 resolve 调用的方法,第二个是失败 reject 调用的方法


九、async await

定义

async 是“异步”的简写, async 用于申明一个异步的 functionawait 可以认为是 async wait 的简写,await 用于等待一个异步方法执行完成。

特点:

asayc的用法,它作为一个关键字放到函数前面,这样普通函数就变为了异步函数异步async函数调用,跟普通函数的使用方式一样异步async函数返回一个promise对象async函数配合await关键字使用(阻塞代码往下执行) 是异步方法,但是阻塞式的

async/await的优点

1.方便级联调用:即调用依次发生的场景;

2.同步代码编写方式: Promise使用then函数进行链式调用,一直点点点,是一种从左向右的横向写法;async/await从上到下,顺序执行,就像写同步代码一样,更符合代码编写习惯;

3.多个参数传递: Promise的then函数只能传递一个参数,虽然可以通过包装成对象来传递多个参数,但是会导致传递冗余信息,频繁的解析又重新组合参数,比较麻烦;async/await没有这个限制,可以当做普通的局部变量来处理,用let或者const定义的块级变量想怎么用就怎么用,想定义几个就定义几个,完全没有限制,也没有冗余工作;

4.同步代码和异步代码可以一起编写: 使用Promise的时候最好将同步代码和异步代码放在不同的then节点中,这样结构更加清晰;async/await整个书写习惯都是同步的,不需要纠结同步和异步的区别,当然,异步过程需要包装成一个Promise对象放在await关键字后面;

5.async/await是对Promise的优化: async/await是基于Promise的,是进一步的一种优化,不过在写代码时,Promise本身的API出现得很少,很接近同步代码的写法;

使用场景

async主要来处理异步的操作,


十、箭头函数与普通函数区别

一、箭头函数是匿名函数,不能作为构造函数,不能使用new 二、箭头函数不绑定arguments,取而代之需要用展开运算符解决…解决 三、箭头函数不绑定this,会捕获其所在的上下文的this值,作为自己的this值 四、箭头函数通过 call() 或 apply() 方法调用一个函数时,只传入了一个参数,对 this 并没有影响。 五、箭头函数没有原型属性

十一、结构赋值

解构赋值就是提取数组和对象中的值,对变量进行赋值定义和赋值必须要放在一起,否则就会给你报错,取不到数据,解构赋值就是对js的赋值运算符的扩展它的好处就是让我们能够快速的能从复杂的对象中取出我们想要的数据

十二、JavaScript中let、const、var 的区别

1.是否存在变量提升?

var声明的变量存在变量提升 let和const不存在变量提升

2.是否存在暂时性死区?

let和const存在暂时性死区。即只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。

总之,暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。

3.是否允许重复声明变量?

var允许重复声明变量。 let和const在同一作用域不允许重复声明变量。

4.是否存在块级作用域?

var不存在块级作用域。 let和const存在块级作用域。

5. 是否能修改声明的变量?

var和let可以。 const声明一个只读的常量。一旦声明,常量的值就不能改变。const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。

十三、vue常用的指令

v-model 多用于表单元素实现双向数据绑定v-for 格式: v-for="(item,index) in/of 数组json" 循环数组或jsonv-show 显示内容 ,通过display=block/none来控制元素隐藏出现v-hide 隐藏内容 同上v-if 显示与隐藏 (dom元素的删除添加 同angular中的ng-if 默认值为false)v-else-if 必须和v-if连用v-else 必须和v-if连用 不能单独使用 否则报错 模板编译错误v-bind 动态绑定 作用: 及时对页面的数据进行更改v-on:click 给标签绑定函数,可以缩写为@,例如绑定一个点击函数 函数必须写在methods里面v-text 解析文本v-html 解析html标签v-bind:class 三种绑定方法 1、对象型 ‘{red:isred}’ 2、三元型 ‘isred?“red”:“blue”’ 3、数组型 ‘[{red:“isred”},{blue:“isblue”}]’v-once 进入页面时 只渲染一次 不在进行渲染v-cloak 防止闪烁 该属性需配合 样式使用: <style> [v-cloak]{display:none} </style> <div id="app" v-cloak> <div> {{message}} </div> </div> <script type="text/javascript"> new Vue({ el:'#app', data:{ message:'hello world' } }) </script> v-pre 把标签内部的元素原位输出

十四、组件封装

我用vue开发的所有项目,都是采用组件化的思想开发的。一般我在搭建项目的时候,会创建一个views目录和一个commen目录和一个feature目录,views目录中放页面级的组件,commen中放公共组件(如:head(公共头组件),foot(公共底部组件)等),feature目录内放功能组件(如:swiper(轮播功能组件),tabbar(切换功能组件)、list(上拉加载更多功能组件))

首先,组件可以提升整个项目的开发效率。能够把页面抽象成多个相对独立的模块,解决了我们传统项目开发:效率低、难维护、复用性低等问题。

使用Vue.extend方法创建一个组件,然后使用Vue.component方法注册组件。但是我们一般用脚手架开发项目,每个 .vue单文件就是一个组件。在另一组件import 导入,并在components中注册,子组件需要数据,可以在props中接受定义。而子组件修改好数据后,想把数据传递给父组件。可以采用emit方法。

十五、父子通信

第一种:父传子:主要通过 props 来实现的

具体实现:父组件通过 import 引入子组件,并注册,在子组件标签上添加要传递的属性,子组件通过 props 接收,接收有两种形式一是通过数组形式[‘要接收的属性’ ],二是通过对象形式{ }来接收,对象形式可以设置要传递的数据类型和默认值,而数组只是简单的接收

第二种:子传父:主要通过$emit 来实现

具体实现: 子组件通过通过绑定事件触发函数, 在其中设置this.e m i t ( ‘ 要 派 发 的 自 定 义 事 件 ’ , 要 传 递 的 值 ) ,emit 中有两个参数一是要派发的自定义事件,第二个参数是要传递的值

第三种:兄弟之间传值有两种方法:

方法一:通过 event bus 实现

具体实现:创建一个空的 vue 并暴露出去,这个作为公共的 bus,即当作两个组件的桥梁,在两个兄弟组件中分别引入刚才创建的bus,在组件 A 中通过 bus.e m i t ( ’ 自 定 义 事 件 名 ’ , 要 发 送 的 值 ) 发 送 数 据 ,在组件B中通过bus.on(‘自定义事件名‘,function(v) { //v 即为要接收的值 })接收数据

十六、vuex

1.定义:Vuex是一个专为Vue.js应用程序开发的状态管理模式。Vuex的状态存储是响应式的:就是当你的组件使用到了这个Vuex的状态,一旦它改变了,所有关联的组件都会自动更新相对应的数据,它采用集中式储存管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

2.使用场景:在我们开发一个中大型项目时,这时就用到了Vuex,因为在组件中有很多兄弟组件之间的通信,很繁琐。这样的话我们就把数据都存放在Vuex中,A1、A2、A3组件需要数据的话都去Vuex里面去拿,这样的话就不用组件之间的通信了

3.优点:在state中定义了一个数据之后,可以在任何一个组件里进行获取、进行修改、并且你的修改可以得到全局的响应变更。

4.运行机制 在组件中通过dispath派发actions,然后在actions中通过context.commit提交到mutations,在mutations中完成对store的修改。store中的数据只能由mutations来修改

5.核心: ①state: 存储数据的地方,类似一个仓库 ②mutations:同步操作,只有mutations才可以修改state中的数据 ③actions:异步操作,其实就是调用mutations里面的方法。 ④module:面对复杂的应用程序,当管理的状态比较多时;我们需要将vuex的store对象分割成模块(modules)。模块化 modeA, modeB,modeC ⑤getters:是state的计算属性。

语法糖辅助函数

语法糖,四大金刚辅助函数:mapState,mapActions,mapMutations,mapGetters当一个组件需要多个状态是,这些状态都声明成计算属性过于冗长。于是有了辅助函数

十七、vue-router 两种模式

hashhistory

hash模式原理

history模式的原理

十八、路由传参两种形式

十九、路由拦截

二十、路由懒加载

效果

三种方法

二十一、axios拦截

二十二、api接口封装

最新回复(0)