前端面试题

加粗样式 前端面试

**
自我介绍就不再这里说了,相信经历过面试的小伙伴已经知道怎么说了,但是还有一些没有经历过面试的小伙伴,提醒一下,要尽量说出自己的优点,如果是985或者211的学校,可以说出自己在哪个学校毕业的,在学校获得什么奖项,比如成绩优异,得过奖学金,这些都是加分项 ,如果是普通的二本院校,就不要说了,好了,废话不多说,下面开始上正餐。

1.什么是mvvm 、 mvc 模型?
  MVC: MVC即model-view-controller(模型-视图-控制器)是项目的一种分层架构思想,它把复杂的业务逻辑,抽离为职能单一的小模块,每个模块看似相互独立,其实又各自有相互依赖关系。它的好处是:保证了模块的智能单一性,方便程序的开发、维护、耦合度低。
  
  2. 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变更的双向绑定效果。
 
3. vue的生命周期有哪些?
一、创建前 / 后

在beforeCreate生命周期函数执行的时候,data和method 还没有初始化

在created 生命周期函数执行的时候,data和method已经初始化完成

二、渲染前/后

在beforeMount 生命周期函数执行的时候,已经编译好了模版字符串、但还没有真正渲染到页面中去

在mounted 生命周期函数执行的时候,已经渲染完,可以看到页面

三、数据更新前/后

在beforeUpdate生命周期函数执行的时候,已经可以拿到最新的数据,但还没渲染到视图中去。

在updated生命周期函数执行的时候,已经把更新后的数据渲染到视图中去了。

四、销毁前/后

在beforeDestroy 生命周期函数执行的时候,实例进入准备销毁的阶段、此时data 、methods 、指令等还是可用状态

在destroyed生命周期函数执行的时候,实例已经完成销毁、此时data 、methods 、指令等都不可用

  1. v-if 和v-show有什么区别?
  2. v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建,操作的实际上是dom元素的创建或销毁。

v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换 它操作的是display:none/block属性。

一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。

5.async await 是什么?它有哪些作用?

async await 是es7里面的新语法、它的作用就是 async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成。它可以很好的替代promise 中的then

async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。

6.数组有哪几种循环方式?分别有什么作用?
every() 方法测试一个数组内的所有元素是否都能通过某个指定函数的测试。它返回一个布尔值。

filter() 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。

forEach() 方法对数组的每个元素执行一次提供的函数。

some() 方法测试是否至少有一个元素可以通过被提供的函数方法。该方法返回一个Boolean类型的值。

7.什么是原型链?
每一个实例对象上有一个proto属性,指向的构造函数的原型对象,构造函数的原型

对象也是一个对象,也有proto属性,这样一层一层往上找的过程就形成了原型链。

8.闭包(closure)指有权访问另一个函数作用域中变量的函数。简单理解就是 ,一个作用

域可以访问另外一个函数内部的局部变量。

function fn() {
    var num = 10;
    function fun() {
        console.log(num); 
    }
    return fun;
}
var f = fn(); 
f();

作用:延长变量作用域、在函数的外部可以访问函数内部的局部变量,容易造成内层泄露,因为闭包中的局部变量永远不会被回收

  1. 后台管理系统中的权限管理是怎么实现的?
    登录:当用户填写完账号和密码后向服务端验证是否正确,验证通过之后,服务端会返回一个token,拿到token之后(我会将这个token存贮到cookie中,保证刷新页面后能记住用户登录状态),前端会根据token再去拉取一个 user_info 的接口来获取用户的详细信息(如用户权限,用户名等等信息)。

权限验证:通过token获取用户对应的 权限,动态根据用户的 权限算出其对应有权限的路由,通过 router.addRoutes 动态挂载这些路由。

具体思路:

登录成功后,服务端会返回一个 token(该token的是一个能唯一标示用户身份的一个key),之后我们将token存储在本地cookie之中,这样下次打开页面或者刷新页面的时候能记住用户的登录状态,不用再去登录页面重新登录了。

ps:为了保证安全性,我司现在后台所有token有效期(Expires/Max-Age)都是Session,就是当浏览器关闭了就丢失了。重新打开游览器都需要重新登录验证,后端也会在每周固定一个时间点重新刷新token,让后台用户全部重新登录一次,确保后台用户不会因为电脑遗失或者其它原因被人随意使用账号。

用户登录成功之后,我们会在全局钩子router.beforeEach中拦截路由,判断是否已获得token,在获得token之后我们就要去获取用户的基本信息了

页面会先从 cookie 中查看是否存有 token,没有,就走一遍上一部分的流程重新登录,如果有token,就会把这个 token 返给后端去拉取user_info,保证用户信息是最新的。 当然如果是做了单点登录得功能的话,用户信息存储在本地也是可以的。当你一台电脑登录时,另一台会被提下线,所以总会重新登录获取最新的内容。

先说一说我权限控制的主体思路,前端会有一份路由表,它表示了每一个路由可访问的权限。当用户登录之后,通过 token 获取用户的 role ,动态根据用户的 role 算出其对应有权限的路由,再通过router.addRoutes动态挂载路由。但这些控制都只是页面级的,说白了前端再怎么做权限控制都不是绝对安全的,后端的权限验证是逃不掉的。

我司现在就是前端来控制页面级的权限,不同权限的用户显示不同的侧边栏和限制其所能进入的页面(也做了少许按钮级别的权限控制),后端则会验证每一个涉及请求的操作,验证其是否有该操作的权限,每一个后台的请求不管是 get 还是 post 都会让前端在请求 header里面携带用户的 token,后端会根据该 token 来验证用户是否有权限执行该操作。若没有权限则抛出一个对应的状态码,前端检测到该状态码,做出相对应的操作。

使用vuex管理路由表,根据vuex中可访问的路由渲染侧边栏组件。

具体实现:

创建vue实例的时候将vue-router挂载,但这个时候vue-router挂载一些登录或者不用权限的公用的页面。

当用户登录后,获取用role,将role和路由表每个页面的需要的权限作比较,生成最终用户可访问的路由表。

调用router.addRoutes(store.getters.addRouters)添加用户可访问的路由。

使用vuex管理路由表,根据vuex中可访问的路由渲染侧边栏组件。

10.es6有哪些新特性?
ES6是2015年推出的一个新的版本、这个版本相对于ES5的语法做了很多的优化、例如:新增了let、const

let和const具有块级作用域,不存在变量提升的问题。新增了箭头函数,简化了定义函数的写法,同时可以巧用箭头函数的this、(注意箭头函数本身没有this,它的this取决于外部的环境),新增了promise解决了回调地域的问题,新增了模块化、利用import 、export来实现导入、导出。新增了结构赋值,ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。新增了class类的概念,它类似于对象。

11.组件中的data为什么要定义成一个函数而不是一个对象?
每个组件都是 Vue 的实例。组件共享 data 属性,当 data 的值是同一个引用类型的值时,改变其中一个会影响其他

12.平时都是用什么实现跨域的?
jsonp: 利用

JSONP优点是简单兼容性好,可用于解决主流浏览器的跨域数据访问的问题。缺点是仅支持get方法具有局限性,不安全可能会遭受XSS攻击。

声明一个回调函数,其函数名(如show)当做参数值,要传递给跨域请求数据的服务器,函数形参为要获取目标数据(服务器返回的data)。

创建一个

服务器接收到请求后,需要进行特殊的处理:把传递进来的函数名和它需要给你的数据拼接成一个字符串,例如:传递进去的函数名是show,它准备好的数据是show(‘我不爱你’)。

最后服务器把准备的数据通过HTTP协议返回给客户端,客户端再调用执行之前声明的回调函数(show),对返回的数据进行操作。

CORS:跨域资源共享(CORS)是一种机制;当一个资源访问到另外一个资源(这个资源放在

不同的域名或者不同的协议或者端口),资源就会发起一个跨域的HTTP请求需要浏览器和服务器同时支持;

  1. 整个CORS通信,都是浏览器自动完成。浏览器发现了AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉;
  2. 实现CORS的关键是服务器,只要服务器实现了CORS接口,就可以跨源通信
  3. 服务器对于不同的请求,处理方式不一样; 有简单请求和非简单请求

13.cookie 、localstorage 、 sessionstrorage 之间有什么区别?

  • 与服务器交互:
    • cookie 是网站为了标示用户身份而储存在用户本地终端上的数据(通常经过加密)
    • cookie 始终会在同源 http 请求头中携带(即使不需要),在浏览器和服务器间来回传递
    • sessionStorage 和 localStorage 不会自动把数据发给服务器,仅在本地保存
  • 存储大小:
  • cookie 数据根据不同浏览器限制,大小一般不能超过 4k
  • sessionStorage 和 localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大
  • 有期时间:
    • localStorage 存储持久数据,浏览器关闭后数据不丢失除非主动删除数据
    • sessionStorage 数据在当前浏览器窗口关闭后自动删除
    • cookie 设置的cookie过期时间之前一直有效,与浏览器是否关闭无关

14.this 的指向有哪些?
1、普通函数中的this指向window

2、定时器中的this指向window

3、箭头函数没有this,它的this指向取决于外部环境、

4、事件中的this指向事件的调用者

5、 构造函数中this和原型对象中的this,都是指向构造函数new 出来实例对象

6、类 class中的this 指向由constructor构造器new出来的实例对象

7、自调用函数中的this 指向window

13.什么是递归,递归有哪些优点或缺点?
递归:如果一个函数在内部可以调用其本身,那么这个函数就是递归函数。简单理解:函

数内部自己调用自己, 这个函数就是递归函数

优点:结构清晰、可读性强

缺点:效率低、调用栈可能会溢出,其实每一次函数调用会在内存栈中分配空间,而每个进程的栈的容量是有限的,当调用的层次太多时,就会超出栈的容量,从而导致栈溢出。->性能

14.谈谈你平时都用了哪些方法进行性能优化?
减少http请求次数、打包压缩上线代码、使用懒加载、使用雪碧图、动态渲染组件、CDN加载包。

15.什么是深拷贝、什么是浅拷贝?
浅拷贝:创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。

深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。拷贝前后两个对象互不影响。

16.js的执行机制是怎么样的?
js是一个单线程、异步、非阻塞I/O模型、 event loop事件循环的执行机制

所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务。异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

17.请写至少三种数组去重的方法?(原生js)

在这里插入代码片    //利用filter
    function unique(arr) {
      return arr.filter(function(item, index, arr) {
        //当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素
        return arr.indexOf(item, 0) === index;
      });
    }
        var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
            console.log(unique(arr))

    //利用ES6 Set去重(ES6中最常用)
    function unique (arr) {
      return Array.from(new Set(arr))
    }
    var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
    console.log(unique(arr))
     //[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {}, {}]

    //利用for嵌套for,然后splice去重(ES5中最常用)
    function unique(arr){            
            for(var i=0; i<arr.length; i++){
                for(var j=i+1; j<arr.length; j++){
                    if(arr[i]==arr[j]){         //第一个等同于第二个,splice方法删除第二个
                        arr.splice(j,1);
                        j--;
                    }
                }
            }
    return arr;
    }
    var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
        console.log(unique(arr))
        //[1, "true", 15, false, undefined, NaN, NaN, "NaN", "a", {…}, {…}]     //NaN和{}没有去重,两个null直接消失了

18.谈谈set 、 map 是什么?
set 是es6 提供的一种新的数据结构,它类似于数组,但是成员的值都是唯一的。

map 是es6 提供的一种新的数据结构,它类似于对象,也是键值对的集合,但是键的范围不仅限于字符串,各种类型的值都可以当做键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。

19.常见的布局方法有哪些?他们的优缺点是什么?
页面布局常用的方法有浮动、定位、flex、grid网格布局、栅格系统布局

浮动:

  • 优点:兼容性好。
  • 缺点:浮动会脱离标准文档流,因此要清除浮动。我们解决好这个问题即可。

绝对定位

  • 优点:快捷。
  • 缺点:导致子元素也脱离了标准文档流,可实用性差。

flex 布局(CSS3中出现的)

  • 优点:解决上面两个方法的不足,flex布局比较完美。移动端基本用 flex布局。

网格布局(grid)

  • CSS3中引入的布局,很好用。代码量简化了很多。

19.vue中computed 和watch 的区别是什么?
computed计算属性就是为了简化template里面模版字符串的计算复杂度、防止模版太过冗余。它具有缓存特性

computed用来监控自己定义的变量,该变量不在data里面声明,直接在computed里面定义,然后就可以在页面上进行双向数据绑定展示出结果或者用作其他处理;

watch主要用于监控vue实例的变化,它监控的变量当然必须在data里面声明才可以,它可以监控一个变量,也可以是一个对象,一般用于监控路由、input输入框的值特殊处理等等,它比较适合的场景是一个数据影响多个数据,它不具有缓存性
  • watch:监测的是属性值, 只要属性值发生变化,其都会触发执行回调函数来执行一系列操作。
  • computed:监测的是依赖值,依赖值不变的情况下其会直接读取缓存进行复用,变化的情况下才会重新计算。

除此之外,有点很重要的区别是:计算属性不能执行异步任务,计算属性必须同步执行。也就是说计算属性不能向服务器请求或者执行异步任务。如果遇到异步任务,就交给侦听属性。watch也可以检测computed属性。

20.什么vuex ,谈谈你对它的理解?

  1. 首先vuex的出现是为了解决web组件化开发的过程中,各组件之间传值的复杂和混乱的问题
  2. 将我们在多个组件中需要共享的数据放到store中,
  3. 要获取或格式化数据需要使用getters,
  4. 改变store中的数据,使用mutation,但是只能包含同步的操作,在具体组件里面调用的方式this.$store.commit(‘xxxx’)
  5. Action也是改变store中的数据,不过是提交的mutation,并且可以包含异步操作,在组件中的调用方式this.$store.dispatch(‘xxx’); 在actions里面使用的commit(‘调用mutation’)

21.promise是什么?它有哪些作用?
Promise 是异步编程的一种解决方案.简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,可以从改对象获取异步操作的消息。

它可以解决回调地狱的问题,也就是异步深层嵌套问题

22.post和get 请求有哪些区别?
GET:一般用于信息获取,使用URL传递参数,对所发送信息的数量也有限制,一般在2000个字符

POST:一般用于修改服务器上的资源,对所发送的信息没有限制。

GET方式需要使用Request.QueryString来取得变量的值,而POST方式通过Request.Form来获取变量的值,也就是说Get是通过地址栏来传值,而Post是通过提交表单来传值。

然而,在以下情况中,请使用 POST 请求:

无法使用缓存文件(更新服务器上的文件或数据库)

向服务器发送大量数据(POST 没有数据量限制)

发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠

23.http状态码分别代表什么意思?
1xx 表示HTTP请求已经接受,继续处理请求

2xx 表示HTTP请求已经处理完成(200)

3xx 表示把请求访问的URL重定向到其他目录(304资源没有发生变化,会重定向到本地资源)

4xx 表示客户端出现错误(403禁止访问、404资源不存在)

5xx 表示服务端出现错误

24.BFC是什么?
BFC(会计格式化上下文),一个创建了新的BFC的盒子是独立布局的,盒子内元素的布局不会影响盒子外面的元素。在同一个BFC中的两个相邻的盒子在垂直方向发生margin重叠的问题。

BFC是值浏览器中创建了一个独立的渲染区域,该区域内所有元素的布局不会影响到区域外元素的布局,这个渲染区域只对块级元素起作用

25.token是什么?(加密)
1.token也可以称做令牌,一般由 uid+time+sign(签名)+[固定参数] 组成
2.token在客户端一般存放于localStorage,cookie,或sessionStorage中。在服务器一般存于数据库中
3.token可以抵抗csrf,cookie+session不行
5. session时有状态的,一般存于服务器内存或硬盘中,当服务器采用分布式或集群时,session就会面对负载均衡问题。负载均衡多服务器的情况,不好确认当前用户是否登录,因为多服务器不共享session
6. 客户端登陆传递信息给服务端,服务端收到后把用户信息加密(token)传给客户端,客户端将token存放于localStroage等容器中。客户端每次访问都传递token,服务端解密token,就知道这个用户是谁了。通过cpu加解密,服务端就不需要存储session占用存储空间,就很好的解决负载均衡多服务器的问题了。这个方法叫做JWT(Json Web Token)

26.一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?
01.浏览器查找域名对应的IP地址(DNS 查询:浏览器缓存->系统缓存->路由器缓存->ISP DNS 缓存->根域名服务器)

02.浏览器向 Web 服务器发送一个 HTTP 请求(TCP三次握手)

03.服务器 301 重定向(从 http://example.com 重定向到 http://www.example.com)

04.浏览器跟踪重定向地址,请求另一个带 www 的网址

05.服务器处理请求(通过路由读取资源)

06.服务器返回一个 HTTP 响应(报头中把 Content-type 设置为 ‘text/html’)

07.浏览器进 DOM 树构建

08.浏览器发送请求获取嵌在 HTML 中的资源(如图片、音频、视频、CSS、JS等)

09.浏览器显示完成页面

10.浏览器发送异步请求
27.call、apply、bind三者的异同
共同点 : 都可以改变this指向;

不同点:

call 和 apply 会调用函数, 并且改变函数内部this指向.

call 和 apply传递的参数不一样,call传递参数使用逗号隔开,apply使用数组传递

bind 不会调用函数, 可以改变函数内部this指向.

应用场景

  1. call 经常做继承.
  2. apply经常跟数组有关系. 比如借助于数学对象实现数组最大值最小值
  3. bind 不调用函数,但是还想改变this指向. 比如改变定时器内部的this指向

最后总结:这里面的面试题不全,有小伙伴会问到为啥你不写组件传值,在这里我想说的是,这个我默认大家是会的,都准备面试了,这个问题肯定会,有什么错误遗漏的地方,欢迎大家的纠正和指出

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值