2021前端面试题(不包括react)

一、HTML

1、什么是盒模型,盒模型包括哪些?

盒模型就是把html里面的元素看做是矩形的框,类似于一个盒子的模型。

标准盒模型:width+padding+border+margin

怪异盒模型:width+margin

怪异盒模型就是把padding和border包括在width里面,平时经常使用的box-sizing:boder-box;就是把标准盒模型变成怪异盒模型。

2、怪异盒模型和普通盒模型有哪些区别?

标准盒模型: content-box

怪异盒模型: border-box

二、CSS

1、css的定位有哪几种,分别什么作用

static:静态定位 relative相对元素本身的定位 absolute相对父元素的绝对定位,脱离文本流 fixed相对可视窗的固定定位。

2、垂直居中水平居中等有哪些解决方案(侧面考验对块级元素、行内元素、行内块级元素的了解)

3、动画和过度的熟练度

动画:animation  @keyframes

过度:transition

三、JS(包括ES6)****(****函数递归****)

1、什么是基本数据类型和****引用****数据类型?

基本数据类型:保存在栈中的大小确定的值

引用数据类型:就是堆中的一个对象,他的变量是保存在栈中的一个引用地址,通过引用地址可以快速找到堆中的对象。

2、赋值、浅拷贝、深拷贝的区别,并且分别有哪些方法?

> **赋值:**基本类型数据直接在栈中简单赋值,两个独立不影响。引用类型直接拷贝内存地址。

> **浅拷贝: **遍历引用类型中的每一个属性,并且将其基本类型的值的指针进行拷贝,如果遇到复杂类型的值,直接拷贝内存地址。

** 深拷贝:**完全独立的拷贝出新的一块内存地址,两个变量互不干涉,互不影响。

深拷贝的方法:(循环遍历,递归遍历)

3、原型的理解

> **原型(原型对象):**就是一个对象,prototype就是一个原型对象,在每一个函数里面都存在的一个对象。

>** 对象原型:**每个对象都有一个原型_ _proto_ _,是这个对象的原型,他指向的是他的构造函数的原型对象prototype

** 构造函数(coustructor):**原型对象(prototype)对象原型(_ proto _)里面都有这个属性,他指向的是构造函数的本身。

** 原型作用:**共享方法。构造函数中所有的方法都可以定义在原型对象中,所有的实例都可以共享这个方法,实例化对象的时候就不需要单独的开辟一块内存空间了,提高性能,也节省了内存。

** 原型链:**当访问一个对象属性的时候,会先从这个对象本身属性上去查找,没找到,则会去他的proto的原型上去查找,如果没找到再在构造函数的Prototype的原型原型上去查找,知道查找到null为止。这样一层层上去就形成了一个链式结构。

> prototype是构造函数才有的属性,_ _proto_ _每个对象都有的属性

4、闭包

> **能获取函数内部变量的函****数****(声明在函数内部的函数)**

闭包优点:1、防止外界变量污染 2、读取函数内部变量  3、使变量一直保存在内存中。

闭包优点:1、会造成内存溢出(内存泄漏)

let add = null

function a() {

    let num =1;

   add = () => { num+=1 }

   //下面这个就是闭包

    return () => {

        console.log( num )

    }

}

//执行以下代码输出:

const res= a()

res()   //1

add()   //变量+1了,并且一直保存在内存中

res()  //2 

5、本地存储

localStorage: 一直存储在本地,一直存在

sessionStorage:页面关闭,存储消失

6、变量提升****(****js预加载技术****)

7、变量作用域****(****全局作用域、局部作用域、块级作用域****)

8、call、apply、bind的作用和用法,利用call(),apply()实现继承

call、apply、bind作用是改变对象的执行上下文(改变this的指向)。

call,apply是立即执行的,bind是返回一个函数,在需要使用的时候再调用。

const student = {name:'lili',age:12}

function s(a,b) {

    console.log(a+b)

}
//call直接执行,参数用,分隔。并输出结果3

s.call(student,1,2)   

//apply直接执行,参数以数组的形式传递。并输出结果3

s.apply(student,[1,2])

//bind不执行,作用只是改变this的指向

s.bind(student)

9、继承

(1)原型继承,实例共用原型链,属性为引用类型,则会互相影响。

  Child.prototype= new Parsent()

(2)构造函数继承,无法继承原型上的属性和方法。

   Parsent.call(this)

(3)组合式继承 结合

    Parsent.call(this)    

    Child.prototype= new Parsent()

    Child.prototype.constructor = Child

10、this的指向问题

当在全局作用于中,this指向window

普通函数作用域下:非严格模式,指向window ,严格模式undefined

在构造函数中,this指向此构造实例对象,

在对象方法中,this指向该对象

> 箭头函数更改了this的指向,指向词法作用域的外层。

11、异步请求:promise\async await \callback

12、数组用typeof判断出来的类型是什么,哪些方法可以判断是数组?

   undefined, boolean,string,number,object,function

    Array.isArray(arr)  /  arr instanceof  Array  

13、setTimeOut / Promise.resolve().then的执行顺序,宏任务和微任务知识点

    /**

     * 宏任务:setTimeOut, setInterval, setImmediate, I/O

    * 微任务:Promise.resolve(), process.nextTick,promise.resolve().then()

    * */

14、Boolean类型的强制转换,

  例:let a = [], b = {}, c = 0 ;

   写出输出值: console.log(a && b) ;  console.log(a && c);  console.log(a && b && c) ; console.log(!a && c) ; console.log(a && !c) 

15、判断是否为一个数组类型的方法(两种法法)

    例: let arr = [1,2,3,4]
  1. 利用原型判断,判断这个变量的原型链是否是数组对象: arr instanceof Array //true

  2. Object.prototype.toString.call(arr) 准确判断任何类型

3)利用es6新增的内置对象的方法:Array.isArray(arr) //true

16、什么是事件流?事件流分哪几个阶段?

    > 事件流指的是:事件传播的过程.(冒泡、捕获)

    (1)事件捕获阶段(2) 处于目标阶段 (3)事件冒泡阶段

**17、熟悉使用Element.addElementListener('事件',‘函数’,true/false) **

     最后的ture/false,什么意思?有什么作用?

    true 事件按照事件捕获的方式执行, false 事件按照事件冒泡的方式执行

18、'use strict'严格模式,必须写在第一行吗?回答使用'use strict'的优缺点?

    是的、但是如果上面是注释的代码,也算是写在最上面,如果没写在最上面,

    那么'use strict'会失效。

19、async/await作用

1、await作为求值关键字(后面可以跟promise或表达式),可以直接获取promise的值和表达式的值

2、将异步代码操作变为同步代码的写法。

20、window.onLoad 和$(document).ready()的区别

window.onLoad是数据资源全部加载完毕才执行,ready是dom渲染完毕就执行。

21、作用域和上下文:

作用域:可访问的变量的范围、区域。

上下文:同一个作用域中的变量

22、jsonp的跨域原理:

浏览器是有同源策略限制的,但是src属性不被同源策略限制,所以利用动态插入script标签并且设置src属性,就解决了跨域问题。

23、instanceof原理

instanceof 是判断右边的变量原型prototype是不是在左边的变量的原型链上。

结果为true :

Object instanceof Object / Function instanceof Object / Object instance Function

24、垃圾回收机制,和避免内存泄漏:

当执行遇到函数的时候,会创建一个函数执行上下文,并添加到调用堆栈的栈顶,函数的作用域中包含了函数中声明的所有的变量,当函数执行完毕,对应的执行上下文从栈顶弹出,函数的作用域随之销毁,函数中包含的所有声明的变量统一释放并自动回收。

垃圾回收:就是不定期寻找不再使用的变量,释放并回收内存。

垃圾:就是不再使用的变量或者未被引用的对象。

怎么实现垃圾回收:利用标记-清除法,进行垃圾回收。

1、少创建全局变量

2、手动清除定时器

3、少用闭包

4、清除dom的引用

25、函数柯里化

定义:只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数

fun(1,2,4)===》 fun(1)(2)(4)

作用:延迟执行、参数复用、提前确认(利用自执行函数,提前确认走那个方向。然后返回一个函数)。

26、new操作符的作用,并写一个js方法实现new运算符

[图片上传失败...(image-dc15e4-1631860993689)]

function ObjectNew() {    
//创建一个实例对象对象  
  let obj = {}   
 //取得方法的第一个参数为构造函数 
   const Constructor = [].shift.apply(arguments)  
  //将该对象的原型指向构造函数的原型对象   
 obj.__proto__ = Constructor.prototype  
  //更改构造函数的this指向实例对象,并取得返回值
   const res = Constructor.apply(obj, arguments)    
//如果有返回对象,就返回对象,没有就返回实例对象    
return typeof res === 'object' ? res : obj 
 }

27、js事件循环机制(Event Loop)

(单线程非阻塞,主线程、执行栈、事件队列)

js是单线程非阻塞的,js只有一个主线程来处理所有的任务,因为js是单线程的,js同一时间只能执行一个方法,这些方法依次排列在执行栈中被依次执行,当方法被执行完毕的时候。js会退出执行环境并且销毁执行环境。当遇到异步事件时,会将这个异步事件挂起,继续执行执行栈中的其他任务,异步事件返回结果后,会将事件添加到事件队列中,等待执行栈中的所有任务执行完毕之后,主线程会去查找事件队列中是否有任务,如果有,主线程会将事件队列中的回调放入执行栈中并依次执行。这样事件就形成了一个循环,叫做事件循环。

28、前端跨页面通信有哪些方法

同源下的页面之间:

1、利用事件监听document.addElementListener(‘click’,fun,false)

2、window.postMessage()

3、h5的本地存储localStorage

非同源下的页面之间

1、JSONP

2、iframe

29、重排和重绘(尽量减少重排重绘)

重排(回流):重新生成布局,重新排列元素

重绘:某些元素的外观被改变,比如color变化。

重绘不一定导致重排,重排一定导致重绘。

30、前端性能优化

(1)外部引入css,script,并且将script放在body的最后。

(2)减少重排重绘

(3)减少去除多余代码,减小代码量

31、浏览器渲染页面的流程:

(1)输入网址,DNS查询,将域名解析为ip

(2)浏览器和服务器建立tcp或者udp连接

(3)浏览器给服务器发送http请求

(4)服务器处理响应请求

(5)服务器返回一个html响应

(6)客户端渲染html

32、模块化

什么是模块化:

(1)将复杂的程序依据一定的规范封装成几个模块,并组合在一起。

(2)块的内部数据与实现是私有的,只是简单向外部暴露一些接口与外部其他模块通信。

模块化方式:

(1)函数模块

(2)对象模块

(3)IIFE(闭包)

模块化的优点:

(1)避免变量命名冲突

(2)更好的分离,按需引入加载

(3)更高的复用性

(4)更高的维护性

33、promise原理

prmise有三种状态:等待pending、成功fulfilled、拒绝rejected。promise一旦改变状态就是不可逆的,当变成fulfilled状态,会立即执行回调函数,回调函数返回的结果被当做参数闯入函数被使用。

四、VUE

1、vue全家桶,分别什么作用?

    > vue-cli脚手架:快速搭建vue开发环境,继承资源加载,打包、热更新等一体的vue开发工具。

    > vue -router: vue的路由插件,有两种模式hash模式和history模式。

    > vuex:状态管理模式,集中式存储管理所有组件的状态,并以相应的规则保证可预测的发生变化。

    > axios: 基于promise的http库,实现数据的交互。

    >vue的第三方框架,例如element-ui , mint-ui

2、vuex模块

vuex是针对vue.js创建的状态管理仓库。分为state,getter,mutation,action,module五个模块部分,

> state:存储view视图的公共数据

> getters: 计算变量,跟vue中的computed数据相似,具有缓存功能,只有依赖的数据源发生变化,才被重新计算。

> mutations: 提交state数据源状态的唯一方法,只操作同步操作。

> actions: 异步方法请求的地方,通过dispatch触发。能通过commit触发mutations方法。

> modules: store分割的子模块

3、什么是MVVM模式,怎么实现数据双向绑定,数据双向绑定的原理?

    model数据交互层逻辑, view视图层展示页面, viewModel中间传送带,是model和view交互的中间键。

采用数据劫持结合发布订阅者模式来改变view层数据。通过Object.defineProperty()中的get,set劫持数据的变化,发布消息给订阅者watcher,触发响应的监听回调更新视图。

通过监听input、change事件赋值改变model层数据

    > model变化view视图更新:在vue创建实例的时候,会遍历data中的属性,并通过Object.defineProperty()方法,设置属性的setter/getter,听属性值的变化,当监听到属性值的变化,触发dep.notify()通知订通过observe监阅者,执行watcher.update()方法,执行compile中的回调,改变DOM中的值。

    > view视图更新model数据变化:通过文本输入框的change/input事件,获取dom中value值,改变model层数据。

vue2.x:利用object.defineproperty()劫持数据,但是object.defineproperty()不能监听数组的变化,数组中的push,shift等方法无法触发set,vue是通过重写数组这些方法实现数据的劫持。并且要手动递归遍历深层次的对象属性

vue3.0:利用proxy劫持数据,proxy针对的是整个对象,所以对象里面的属性变化,都可以劫持到。能监听到数组的变化,不需要重写数组的方法。嵌套对象需要递归调用proxy。

4、vue中数组和对象是怎么渲染的?

    >  vue实例初始化之前就在data对象里面定义好的的属性,类型可以是Object、Array、String、Number等各种类型的数据,这样能监听到data里面属性的变化,而重新渲染页面数据,没在data中定义的属性,无法坚监听到数据的变化,可以使用this.$set()方法为属性添加监听事件。

其中Array类型直接改变数组长度 或 利用下标改变数组无法监听到变化,所以页面无法重新渲染。

Object类型:利用delete删除对象某一属性 或 为对象添加某一属性,则无法监听到数据变化。

5、vue-router的两种模式

> hash模式:vue默认使用hash模式,并且如果浏览器不支持history模式的情况,会重新定向为使用hash模式。从#之后的一串数据都属于hash值。改变hash值会触发hashChange事件,然后通过hash值去查找相应的路由,改变视图。使用以下两种方法改变页面内容和浏览器浏览记录:

    hashHistory.push()  / hashHistory.replace()

history模式:是HTML5中的新增的两个API history.pushState() / history.replaceSate(),能够改变url地址且不会发送请求,可以改变浏览器历史记录栈。需要后端配合使用。

history 致命的缺点就是当改变页面地址后,强制刷新浏览器时,(如果后端没有做准备的话)会报错,因为刷新是拿当前地址去请求服务器的,如果服务器中没有相应的响应,会出现 404 页面。

6、vue2.0和vue3.0的不同,vue3.0有哪些优化?

   vue2.x:页面载入时,不管是不是可区域渲染的数据,都会创建监听观察者,所以在页面载入时的性能较低,较慢。

    vue3.0:页面是需要用到什么引入什么,不会有冗余的和多余的数据,只有在可见区域中才会为数据创建观察者,初始载入时性能好。

| vue2.x | vuee3.0 |
| 采用Object.defineProperty()进行数据劫持|采用proxy进行数据劫持|
|页面载入时,为data里面的所有数据创建观察者,性能低|页面载入时,只有可见区域的变量创建观察者|
|利用vue.set()为对象添加属性时,这个对象的所有watcher会重新运行|
利用vue.set()为对象添加属性时,只有依赖那个属性的watcher才会重新运行
|
|this指向当前组件|取消了this关键之,直接使用setup携带的参数|

7、vue的生命周期钩子

> beforeCreate   实例初始化之后,数据观测(data observer)和event/watcher 事件配置可以调用

> created  实例创建完成后被立即调用,但是实例还没挂载,不可获取dom

> beforeMount  实例挂载之前调用 ,相关的render函数首次被调用。 (服务器渲染期间不被调用)

> mounted  实例挂载后调用,但是不能保证能获取子组件的dom。使用$nextTick()则能获取整个视图dom

> beforeUpdate  数据更新时调用,dom更新之前

> updated 发生在dom更新之后调用。

> activated 被keep-alive缓存组件激活时调用

> deactivated 被keep-alive缓存组件停用时调用

> beforeDestroy 实例销毁之前调用,仍然可以获取到实例dom

> destroyed 实例销毁之后调用

> errorCaptured  捕获一个来自子孙组件的错误时被调用

8、父子组件的生命周期的顺序

> 父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted ->父mounted

->父beforeUpdate -> 子beforeUpdate ->子updated -> 父updated

-> 父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed

9、解释vue的单页面应用

单页面应用指,在vue初始化页面的时候只请求一次资源,之后的页面交互,数据交互都是通过router和ajax来完成,页面并没有刷新。

10、数据的响应式

> 数据分为普通数据类型和引用数据类型(数组、对象),在实例data定义过的property ,都会将其转化为 getter/setter,让其响应数据变化。

(1)普通数据类型

改变数据,直接响应变化

(2)数组

    响应式的:push(),split(),slice()等方法、this.$set()方法

    非响应式:利用数组下标(arr[0].name)、修改数组长度( arr.length=2)

(3)对象

    响应式的:直接赋值(this.obj = {})、this.$set()方法、直接属性赋值存在的属(this.obj.name = '11')

    非响应式:对象不存在的属性名赋值(obj.name ='a')、删除某一属性(delete obj.name)

11、vue-router有哪几种导航钩子

(1)全局导航钩子

router.beforeEach(to,form,next)//路由跳转前判断

router.afterEach((to,from)=>{ });// 跳转后判断

(2)组件内的钩子

beforeRouteEnter(to, from, next) {

// 在渲染该组件的对应路由被 confirm 前调用

},

beforeRouteUpdate(to, from, next) {

// 在当前路由改变,但是依然渲染该组件是调用

},

beforeRouteLeave(to, from ,next) {

// 导航离开该组件的对应路由时被调用

}

(3)单独路由独享组件:是在路由配置上直接定义

const router = newVueRouter({

    routes:[{

    path:'/file',

        component:File,

        beforeEnter:(to,from,next)=>{/*路由钩子*/}

    }]

});

12、描述下虚拟DOM

虚拟dom就是一个js对象,用来描述希望在屏幕上看到的内容,能都实现高效更新真实dom。

13、描述数据变化,dom怎么更新

在第一次渲染页面时就创建一份虚拟dom,当数据变化,利用diff算法对比两个虚拟dom的不同,更新不同处。

14、router和route的区别

route:是当前路由的信息,能获取路由和参数

router:是全局路由(VueRouter)实例对象,可以进行路由跳转

15、vue.use()原理

vue.use()是注册使用全局组件,首先回去判断组件有无被注册过,不会重复注册组件。并且可接受的参数类型为对象或者函数。如果是对象,则包含install方法,去调用install方法,install方法的第一个参数为Vue.如果是函数,则直接执行函数,函数接收的第一个参数也是Vue。

16、vue-loader是什么,什么作用?

处理特定语言块。

vue-loader是一个webpack的loader能够处理.vue结尾的单文件页面。

17、非父子组件之间的数据传递:

1、使用vuex数据管理仓库

2、new一个新的vue实例,作为中央事件总线,然后使用emit和on进行数据的传递和接收。

18、v-for为什么要添加key

vue 在更新渲染dom的时候是根据新旧dom进行对比,用key标识每一个节点,使diff算法比较虚拟dom的时候更准确。

19、computed原理:

内部通过dirty属性判断是否从新计算赋值,初始化时dirty设置成true,会读取data中的依赖变量值进行赋值操作。赋值完毕将dirty设置成false,只有当依赖的data变量发生变化时,才会将dirty赋值为true,重新计算值。

20、vue.nextTick()原理

因为DOM更新是异步执行的,DOM更新会加入到任务队列中.先执行完同步代码,再进行DOM的异步更新,所以需要nextTick()的回调是在dom更新之后的任务队列中执行。nextTick的原理是使用promise、mutationObserver、setImmediate、setTimeout顺序来使用。

21、数组哪些方法能被监听到,怎么实现改变dom的?

vue 内部对数组的push、unshift、pop、shift、reverse、sort、splice等七个方法进行拦截,如果数组变化,就通知订阅者更新视图。

22、keep-alive原理和使用

获取keep-alive包裹的组件和组件名,判断组件名是否包含在include中,通过key值查找该组件是否被缓存过,被缓存过,直接获取cache中缓存的vnode,并且更新key值顺序。没被缓存过,则直接返回组件实例,并添加缓存的key值。之后检查被缓存的组件实例是否超出max,超出了,直接删除最原始的缓存数据。

23、为什么组件里面的data必须是函数?

因为每一个vue组件就是一个vue实例,通过new Vue()来实例化,如果data定义为一个对象,就相当于原型中定义一个对象,实例化对象的时候,那么此对象指向同一地址。那么组件复用的时候data都是指向同一个内存地址,改变其一,牵动其二,组件相互影响。如果使用函数,复用组件的时候,每个组件都有各自的data作用域,互相独立。

24、** vm.$set(target,key,val)方法的原理 **

使用这个方法可以给响应式数据添加和更改响应式数据。

首先会判断目标对象时数组还是对象,如果是数组使用splice()方法,替换更改数组。如果是对象,并且添加的属性已存在,则直接赋值,如果对象不存在此属性,先判断此对象是否是响应式变量,如果不是,直接添加键值对,如果是响应式,通过defineReactive()方法进行响应式处理。

五、网络请求

1、http和https的区别

http:安全性低

https:通过加密协议处理过,更安全

2、get和post请求

get:数据通过url传递,直接可见,数据长度受限。

post:数据通过params传递,安全性能更高,能接受的数据容量也更大。

3、http的状态码有哪些,分别代表什么意思

200成功,401需要验证身份,403服务器拒绝请求,404找不到资源,500服务器出错,503服务器不可用。

六、vue3

** 1、vue3有哪些新特性 **
(1)framents(支持多个根节点)


image.png

(2)teleport(通过<teleport>标签包裹的元素可插入到任意的元素中,to中可以是id,也可以是class)


image.png

(3)composition Api (组合式api)更容易维护代码。
** 2、vue3有哪些方面的提升**
(1)diff算法方面的提升,增加了静态标记

一些非静态的节点会增加一个flag标记,在发生变化的时候,有flag标记的地方才会进行diff算法进行比较。
(2)静态提升
对不参与更新的DOM元素,做今天提升,元素节点只会被创建一次,在渲染时直接复用,节省了在运行时的内存占用。也不会进行diff算法。
(3)体积减小了,采用组合式api,按需引入。
(4)使用proxy进行响应式数据xie

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容