前端常见面试题

162 阅读22分钟

一,JavasSript 基础

1.数据类型

int( 数 值 ), string( 字 符 串 ), boolean( 布 尔 ), null( 空 ),undefined(未定义), object(对象)

2. typeof 和 instanceof 的区别?

typeof 可以判断变量的数据类型,返回值是字符串; a instanceof b 是判断 b 是不是在 a 的原型链上, 也可以实现判断数据类型, 返回值为布尔.

3.列举和数组操作相关的方法

push:将元素添加到数组的末尾, 返回值是数组长度
pop:将数组最后一个元素弹出, 返回值是被弹出的元素
unshift:在数组的开头插入一个元素,返回值是数组的长度
shift:将数组第一个元素弹出,返回值是被弹出的元素
splice(index,len):删除数组中指定元素
concat:连接数组
reverse: 翻转数组

4. 列举和字符串操相关的方法

substr: 截取字符串
toUpperCase:将字符串转成大写
toLowerCase:将字符串转成小写
replace:替换字符串特定的字符
charAt:获取字符串中指定索引的字符

5.分别阐述 split(),slice(),splice(),join()

split 可以使用一个字符串切割另外一个字符串, 返回值是数组;
slice 可以从数组中截取一部分(字符串对象也有 slice 方法);
splice(index,len)可以删除指定的数组元素;
join 可以将数组元素使用特定的连接符拼接成字符串

二,Javascript 高级

1.原型对象?

每一个构造函数都有一个 prototype 的属性, 这个属性的值是一个对象, 这个对象就叫做构造函数的原型对象; 一般建议将构造函数的成员属性绑定在原型对象 prototype 上, 因为原型对象 prototype身上的属性默认可以通过实例对象访问到; 这样做可以保证在每次通过 new 关键字创建实例对象的时候, 这些方法不会被重复在内存中创建.

2.原型链?

每个构造函数都有一个 prototype 属性, 即原型对象, 通过实例对象的 proto 属性也可访问原型对象;而原型对象本质也是一个对象, 是对象就有自己的原型对象, 最终形成的链状的结构称为原型链.

3. 构造函数

构造函数本质也是一个函数, 只不过这个函数在定义的时候首字母一般需要大写; 构造函数调用的时候,必须通过一个 new 关键字来调用; 我们一般不直接使用构造函数, 而是使用构造函数创建出来的实例对象. 构造函数是 js 面向对象的一个重要组成部分.

4.闭包

闭包是一个跟函数相关的概念,表现形式是一个父函数内部,嵌套了一个子函数, 子函数直接或间接的被返回给外部作用域, 并且子函数中会使用到父函数局部作用域中的变量.当我们在外部调用这个子函数的时候, 就会发生闭包现象. 闭包的作用:闭包可以延展一个函数的作用域 注意事项:不能滥用闭包, 会导致内存泄漏

5. 内存泄漏, 哪些操作会引起内存泄漏?

内存泄漏是指本应该被垃圾回收机制回收的内存空间由于某种特殊原因没有及时被回收, 称之为内存泄漏. 滥用全局变量和滥用闭包都会导致内存泄漏.

6.预解析

JS 代码在执行之前,解析引擎会对代码进行一个预先的检查, 主要会对变量和函数的声明进行提升, 将变量和函数的声明提到代码的最前面.变量只提升声明, 不提升赋值.

7. this 关键字的理解

this 在不同的场景下指向不太一样, 主要分为一下几种情况:
普通函数中指向全局 window;
对象的成员方法中指向该方法的宿主对象;
构造函数中指向 new 出来的实例对象;
事件处理函数中指向事件源;
回调函数中指向全局 window

8.call/apply/bind 的区别

这三个方法都是函数这个特殊对象的方法,通过这三个方法都可以改变函数内部 this 的指向.
不同点:
call 和apply 会调用一次函数, 而 bind 不会调用函数, 只会在内存中创建一个函数的副本(修改过 this 指向的函数).
call 从第二个参数开始需要一个参数列表,
apply 第二个参数需要是一个数组

9. new 操作符具体干了什么

第一步创建一个空对象;
第二步将 this 指向空对象;
第三步动态给刚创建的对象添加成员属性;
第四步隐式返回 this

三,WebAPI

1.事件委托

本应该注册给子元素的事件, 注册给父元素

2. 事件委托的原理

事件冒泡, 因为有事件冒泡的存在, 所以子元素的事件会向外冒泡,触发父元素的相同事件, 根据事件对象可以找到真正触发事件的事件源.

四,H5新特性

1.H5 都新增了那些新特性

语义化的标签(header,nav,footer,aside,article,section) 本地存储 sessionStorage,localStorage; 拖拽释放(Drag and drop) API 音频、视频 API(audio,video) 画布(Canvas) API 表单控件,calendar、date、time、email、url、search

2. sessionStorage,localStorage 和 cookie 三者有什么区别?

共同点:它们三者都是浏览器端的存储介质, 可以存储一些数据. 不同点: sessionStorage 是将数据存储在页面的内存中, 所以数据会跟随页面的关闭而销毁, 存储数据相对较少(5M 左右), 只能存储字符串; localStorage 是将数据存储在电脑的磁盘上, 存储数据量大(20M 左右),需要手动删除, 只能存储字符串; cookie 是http 协议的重要组成部分, 存储数据量相对比较少(4K 左右),存储cookie 的时候可以设置过期时间, 到达过期时间后, 会自动销毁,如果没有设置, 则跟随浏览器的关闭而销毁. cookie 中存储的数据会伴随每一次http 请求被发送到服务端, 所以不建议在cookie 中存储大量数据.

五,数据交互(ajax)

1.. 常见 HTTP 状态码

400 => 参数出现错误 401 => 未认证,没有登录网站 403 => 禁止访问,没有权限 404 => 客户端访问的地址不存在 500 => 未知的服务器错误 503 => 服务器超负荷

2. HTTP 请求方式有几种

GET,HEAD,POST,PUT,DELETE,PATCH

3.ajax 工作原理

第一步:创建一部对象 var xhr=new XMLHttpRequest() 第二步:设置请求行 xhr.open(‘请求方式’,请求地址); 第三步:发送请求 Get 方式 xhr.send(null), 如果是 post 请求还要设置请求头

4.如何解决跨域问题?

jsonp, 服务器代理, cors

5.. jsonp 跨域的原理是什么?

动态在页面中创建一个 script 标签, 使其 src 属性指向后端数据接口,后 端 数 据 接 口 必 须 返 回 一 个 js 函 数 的 调 用 字 符 串 ( 如cb(‘{“name”:”zs”,”age”:18}’)), 将要返回给前端的 json 数据作为函数的实参, 当 script 标签加载完毕后会在浏览器中执行后端返回的函数调用,所以前端必须事先对调用的函数进行声明. 因为函数是在 js 中声明的, 所以可以在函数内部拿到服务端调用的时候传入的实参, 所以就间接实现了跨域请求数据.间由于某种特殊原因没有及时被回收, 称之为内存泄漏. 滥用全局变量和滥用闭包都会导致内存泄漏.

6. 什么是同步和异步, 那种执行方式更好?

同步是指一个程序执行完了接着去执行另外一个程序, 异步是指多个程序同时执行. 所以异步效率更高, 因为异步不会出现阻塞现象, 前一个程序的执行不会影响后一个程序的执行.

7. GET 和POST 的区别,何时使用 POST?

get 是将要传递的参数拼在 url 中进行传递,传递数据量少, 不安全 post 是将传递的参数放在请求体里传递, 携带数据量大, 相对安全.要提交一些敏感数据(比如登录密码),上传文件时, 必须使用 post请求.

8.JavaScript 的同源策略

同源策略是浏览器的一项安全策略, 浏览器只允许 js 代码请求和当前所在服务器域名,端口,协议相同的数据接口上的数据,这就是同源策略.

9.. 一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?

首先根据域名查询 DNS 服务器获取服务器 IP,然后拿着服务器 IP 和域名请求对应的服务器, 请求成功后 web 服务器会根据一系列运算, 将客户端需要的数据通过网络传输到客户端浏览器, 最终由浏览器解析后呈现给终端用户.

10.网站从 http 协议切换到 https 协议需要对代码做哪些处理?

不需要对代码做任何处理, 只需要在 web 服务器中加入一个 ssl 的安全认证模块即可.

六,性能优化

1.渐进增强和优雅降级

渐进增强(progressive enhancement):针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。(从被所有浏览器支持的基本功能开始,逐步地添加那些只有新式浏览器才支持的功能,向页面添加无害于基础浏览器的额外样式和功能。当浏览器支持时,它们会自动地呈现出来并发挥作用。) 优雅降级(graceful degradation):一开始就构建完整的功能,然后再针对低版本浏览器进行兼(Web站点在所有新式浏览器中都能正常工作,如果用户使用的是老式浏览器,则代码会检查以确认它们是否能正常工作。由于 IE 独特的盒模型布局问题,针对不同版本的IE 的 hack 实践过优雅降级了,为那些无法支持功能的浏览器增加候选方案,使之在旧式浏览器上以某种形式降级体验却不至于完全失效。) 区别:优雅降级是从复杂的现状开始,并试图减少用户体验的供给,而渐进增强则是从一个非常基础的、能够起作用的版本开始,并不断扩充,以适应未来环境的需要。

2. 页面的回流和重绘

回流是指当页面的结构或者标签的尺寸发生变化的时候, 浏览器需要对页面进行重排, 并重新渲染; 重绘是指当页面上的标签的外观(比如字体颜色,或背景颜色)发生改变的时候, 浏览器需要重新对页面进行渲染.所以回流一定会引起页面的重绘, 重绘不一定会引起回流. 要提高页面性能, 就要尽可能的减少页面的回流和重绘.

3.针对页面性能优化,你有哪些优化方案

资源加载方面: 减少 http 请求次数, 具体方案, 代码合并(合并 css,js), 使用精灵图; 减少 http 请求数据量, 代码压缩(css,js,html), 合理设置缓存; 启用 CDN 加速服务; 代码层面: 避免滥用全局变量, 减少作用域查找(能用局部变量就不要声明全局变量), 不要滥用闭包; 减少 DOM 操作, 操作 DOM 的时候对已经查找到的 DOM 对象进行缓存, 避免重复查找; 使用图片懒加载, 避免单次加载图片数量过多导致页面卡顿; 将script 标签写在页面底部, 因为 js 的加载会阻塞页面的渲染; 不要在本地书写大量 cookie, 因为 cookie 会伴随每一次 http 请求;

4.SEO

搜索引擎优化,就是让搜索引擎去抓取我们的网页. 为了让搜索引擎抓取我们的网页, 我们可以在书写代码 的时候做一些工作, 比如合理设置网页 title(标题), keywords(关键字),description(描述); 因为搜索引擎在抓取到网页以后首先回去分析这几个关键信息.

5.Js 是单线程还是多线程?

单线程, 单位时间内只能处理一个进程

6. Js 是如何实现异步操作的?

Js 虽然是单线程的, 但是浏览器是多线程的, js 中的异步操作基本都是由浏览器提供的子线程来完成的.

7.事件循环的机制

因为js是单线程的,所以为了防止某一个函数执行时间太长造成阻塞,所以会将所有的同步任务压到栈中,所有的异步函数推到队列里,又分为微任务队列和宏任务队列,栈中的任务执行完之后会去执行微任务队列中的任务,执行完会去宏任务队列取出一个宏任务检查这个宏任务中存在微任务吗 如果存在就执行完这些微任务,然后再去执行下一个宏任务......不断地循环

8.防抖和节流

在进行窗口的 resize、scroll,输入框内容校验等操作时,如果事件处理函数调用的频率无限制,会加重浏览器的负担,导致用户体验非常糟糕此时我们可以采用 debounce(防抖)和 throttle(节流)的方式来减少调用频率,同时又不影响实际效果 ​ 函数防抖:当持续触发事件时,一定时间段内没有再触发事件,事件处理函数 才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时 ​ 函数节流:当持续触发事件时,保证一定时间段内只调用一次事件处理函数 ​ 区别: 函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理 函数,而函数防抖只是在最后一次事件后才触发一次函数。比如在页面的无限加载场景下,我们需要用户在滚动页面时,每隔一段时间发一次Ajax 请求,而不是在用户停下滚动页面操作时才去请求数据。这样的场景,就适合用节流技术来实现

七,ES6/7/8 新特性

1. ES6 新增了那些特性?

const(声明常量), let(声明变量)关键字; map 和 set 数据类型; 模板字符串; 对象数组解构赋值; 函数剩余参数;(...arg) 延展运算符;(...) 函数默认参数;fn(name=’zs’) 对象字面量的增强(属性名和属性值相同, 可缺省); Promise 异步对象; class 类的支持

2.使用 let 声明的变量和 var 声明的变量有什么区别?

使用 let 声明的变量有块级作用域, 并且没有变量的声明提升( 使用let 声明的变量在声明之前调用会报语法错误); 使用 var 声明的变量有声明提升(在声明之前调用会报 undefined), 没有块级作用域.

3.谈谈 async/await 的使用方式和场景

async 是用来修饰函数的声明, 使用async 修饰的函数会变成一个异步函数. await 用来修饰函数的调用, 被 await 修饰的函数必须返回一个promise 异步对象, 使用 await 修饰后, 就会将 promise 异步对象转换成一个同步操作.

4.箭头函数有什么作用及实际应用场景?

箭头函数可以使函数内部的 this 指向和函数外部保持一致; 箭头函数之所以可以让函数内部的 this 指向和外部保持一致是因为箭头函数内部没有 this 指向. 可以在 ajax 的回调函数中使用箭头函数让回调函 数中的 this 指向事件源; 可以在定时器的第二个参数中使用箭头函数,避免函数内部的 this 指向全局 window.

5.谈谈对 Promise 的理解

Promise 本身并没有提供任何的代码逻辑, 它可以帮助我们改造或优化传统的使用回调函数实现的异步操作, 让我们以一种更优雅的方式来实现异步操作. 最显著的一个特点就是通过 Promise 可以解决传统的回调地狱. 代码层面 Promise 提供了一个构造函数, 在使用的时候必须通过 new 创建一个实例对象, 在创建实对象的时候需要传递一个匿名函数, 这个匿名函数需要两个参数(resolve,reject), resolve 成功处理函数, reject 失败处理函数. 什么时候触发成功处理函数和失败处理函数, 由具体的业务逻辑来决定.resolve 和 reject 需要通过Promise 实例对象提供的 then 方法来传递.Promise 提供了两个静态方法 all,race,all 可以一次执行多个 Promise 实例, 返回值是数组; race 也可以一次执行多个 Promise 实例, 哪个实例最先执行完, 就返回哪个的执行结果.

八,Vue

1.computed 和 watch 的区别?

computed 是计算属性, 可以根据 data 中的数据成员,动态计算出一个新的数据成员(这个数据成员在 data 中并不存在), 计算属性的函数必须有返回值; watch 是监视器, 可以监视 data 中某一个数据成员的改变或路由中的某些属性的改变, 可以根据这个改变, 做一些其他操作(不仅仅局限于更新其他相关数据).

2. 插槽

Vue 中的插槽分为三种, 匿名插槽, 具名插槽, 作用域插槽.通过插槽可以动态指定某一个组件模板部分的渲染, 我们在调用组件的时候, 在组件的调用标签中间传递了什么样的标签结构, 那么该组件就会把我们传递的标签结构放在他的模板部分进行渲染.

3.v-show 和 v-if 在隐藏一个元素的时候有什么不同, 应该如何来选择?

v-show 是通过 css 的方式来隐藏元素, 而 v-if 是根据条件是否成立决定是否要创建元素. 如果某个元素需要频繁切换显示状态的话, 建议是使用 v-show, 因为频繁创建销毁 DOM 需要性能开销.

4.什么是 Vuex, 在那种场景下使用?

Vuex 是针对 vue 的一个状态管理工具. 有几个核心的部分: state 存储状态数据; mutations: 更新数据的方法, actions: 调用 mutations 中的方法, 更新 state 数据; getters: 对 state 中的数据进行预处理 当组件的关系比较复杂的时候, 可以使用 vuex 简化组件间的传值.

5.. jsonp 跨域的原理是什么?

动态在页面中创建一个 script 标签, 使其 src 属性指向后端数据接口,后 端 数 据 接 口 必 须 返 回 一 个 js 函 数 的 调 用 字 符 串 ( 如cb(‘{“name”:”zs”,”age”:18}’)), 将要返回给前端的 json 数据作为函数的实参, 当 script 标签加载完毕后会在浏览器中执行后端返回的函数调用,所以前端必须事先对调用的函数进行声明. 因为函数是在 js 中声明的, 所以可以在函数内部拿到服务端调用的时候传入的实参, 所以就间接实现了跨域请求数据.间由于某种特殊原因没有及时被回收, 称之为内存泄漏. 滥用全局变量和滥用闭包都会导致内存泄漏.

6. Vue 路由的使用步骤?

第一步:下载路由模块 vue-router; 第二步:创建路由对象; 第三步:配置路由规则; 第四步:将路由对象注册为 vue 实例对象的成员属性

7.MVVM 的理解

MVVM 由三部分组成M(model 数据层), V(view 视图层),VM(view-model)视图模型层. 是一种框架的设计思想, vue 就是基于 mvvm 来设计的. 其中 M(model) 层 是 负 责 初 始 化 数 据 ,V(view) 只 负 责 页 面 展示,VM(view-model)用来连接 view 层和 model 层, 将数据层的数据传递一个视图层进行展示, 将视图层的操作传递到数据层进行持久化.

8.Vue 的生命周期?

创建阶段: 只执行一次 beforeCreate(开始进行一些数据和方法的初始化的操作, data 中的数据和 methods 中的方法还不能用), created(已经完成数据和方法的初始化, data 中的数据和 methods 中的方法可以使用了), beforeMount(开始渲染虚拟 DOM), mounted(已经完成了虚拟 DOM 的渲染, 可以操作 DOM 了, 只执行一次) 运行阶段: 执行多次 beforeUpdate(data 中的数据即将被更新, 会执行多次) updated(data 中的数据已经更新完毕, 会执行多次) 销毁阶段: 只执行一次 beforeDestroy(vue 实例即将销毁, 此时 data 中的数据和 methods 中的方法依然处于可用状态) destroyed(vue 实例已经销毁, 此时 data 中的数据和 methods 中的方法已经不可用)

9.数据双向绑定的原理

Vue 是使用数据劫持, 结合发布者订阅者模式实现双向数据绑定的读取 title 或者 msg 的时候 get 方法会自动触发; 重新给 title 或 msg赋值的时候,set 方法会被自动触发(可以在此处通知界面层更新)

10. Vue 创建组件的时候,data 为什么要使用匿名函数 return 一个对象?

因为对象是一种引用数据类型,在内存中只有一份. 如果 data 的值直接是一个对象的话, 那么后期组件在不同的地方多次调用的时候, 会相互产生影响, 因为每一次调用操作的 data 对象是一样的. 使用函数的方式返回对象, 可以保证组件的每一次调用都会创建一个新对象,这样组件的每一次调用不会相互产生影响.

11.父传子,子传父

第一步: 在子组件的调用标签上声明一个自定义属性, 属性值来自父 组件的 data 第二步: 在子组件的定义部分声明一个属性 props, 值是一个数组, 将 自定义属性的名字在 props 中进行声明; 在子组件的模板部分可以使 用 props 中声明过的数据. 第一步: 在子组件的调用标签只上通过 v-on 动态绑定一个自定义事 件, 自定义事件的处理函数必须在父组件的 methods 中提前声明, 这 个函数需要一个形参, 来接收子组件传递过来的数据. 第二步: 在子组件中通过 this.$emit(自定义事件,数据)触发自定义事 件的执行, 此动作可以放在子组件的 created/mounted 生命周期中, 可以放在某个事件处理函数中.

12. Vue 中有几种路由模式?

Vue中的路由模式有两种:hash,history; 默认是hash模式; 可以在创建路由对象的时候, 使用 mode 属性来切换路由模式.

13.Vue 路由导航守卫是什么, 以及应用场景

路由守卫是在页面进行路由跳转的时候做一些处理, 比如拦截.

14.vue 中 v-for 指令循环遍历中 key 属性的作用?

Key 属性的作用是在数据层和视图层之间建立一一对应关系, 方便后期对页面进行局部更新. 如果某一条数据发生改变, 只更新当前数据对应的 DOM 元素.

15.列举 Vue 中常用的指令

v-model:实现双向数据绑定; v-bind: 绑定属性; v-on:注册事件; v-html: 设置标签内容(允许内容 html) v-text: 设置标签的内容(不允许包含 html) V-for: 循环遍历数组或对象数据.间由于某种特殊原因没有及时被回收, 称之为内存泄漏. 滥用全局变量和滥用闭包都会导致内存泄漏.

16.vue 中如何实现给样式添加作用域?说明其实现原理

vue 中要给样式添加作用域, 只需要给 style 标签添加 scoped 属性即可. 实现原理: 添加了scoped 属性的style 标签内的样式会被改写成一个交集选择器,会在原来类名的基础上添加一个随机属性(如.container[v-abcde]), 同时 引 用 该 类 名 的 标 签 也 会 添 加 一 个 相 同 的 属 性 ( 如 <divclass=”container” v-abcde>) , 这样的话, 这个类名就可以对引用它的标签生效, 同时不会影响其他同类名的标签.

17.Vue 中有何优化页面的加载效率?

使用路由懒加载和组件懒加载; 不要打包一些公共的依赖(vue, 组件库); 使用 CDN 加载这些依赖文件

18.什么是路由懒加载? 路由懒加载有什么好处? 如何实现路由 懒加载?

路由懒加载是指通过异步的方式来加载对应的路由组件(默认情况是 将所有的组件全部加载并打包). 路由懒加载的好处: 可以提高页面的加载速度, 尤其是首页的加载速 度(因为使用了懒加载后, 加载首页的时候, 就不需要加载其他页面对 应的组件, 在需要的时候再加载)

19.Vue 中 keep-alive 组件的作用是什么?

keep-alive 可以将被包裹的组件暂存在内存当中, 当页面切换的时候,组件不会被重复的销毁和创建, 从而可以提高整体性能, 同时也可以保存组件的一些状态.

20. . vm.$nextTick(fn)的作用是什么?

延迟某个操作的执行, 直到 dom 更新以后在执行.

21.vue 中的混入(mixin)有什么作用?

混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。当组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”。比如,数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先。同名钩子函数将合并为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用。

22.什么是 ssr? 如何实现 ssr?

ssr 是全拼(server side rendering) ,中文意思, 服务端渲染, 让页面的渲染在服务端完成, 生产环境必须部署nodeJS 的环境, 因为服务端渲染必须借助 nodeJS 来完成. vue 中可以使用 nuxt 框架实现服务端渲染.

23.什么是 SPA?

SPA(Single Page Application), 单页面应用程序, 使用vue, react, angular创建的项目都属于 SPA. 因为整个项目只有一个页面, 其他页面都是在该页面的基础上局部刷新而来的. 传统方式创建的项目都是 MPA(Mutilple Page Application)多页面应用程序.

24. 使用 vue,react,angular 开发的 SPA 单页面应用有什么优缺点?

单页面应用虽然性能方面得到了提升, 但是有一个致命的缺点就是不利于 seo, 搜索引擎几乎不会抓取单页面应用.