前端面试题js+vue(2019年5月总结)

大部分来源于互联网,本人仅做了总结!!!

js、H5、css部分

数据类型

1,介绍js的基本数据类型。    

Undefined、Null、Boolean、Number、String

2,类型判断用到哪些方法?

typeof

typeof xxx得到的值有以下几种类型:undefined boolean number string object function、symbol ,比较简单,不再一一演示了。这里需要注意的有三点:

* typeof null结果是object ,实际这是typeof的一个bug,null是原始值,非引用类型

* typeof [1, 2]结果是object,结果中没有array这一项,引用类型除了function其他的全部都是object

* typeof Symbol() 用typeof获取symbol类型的值得到的是symbol,这是 ES6 新增的知识点

 

instanceof

用于实例和构造函数的对应。例如判断一个变量是否是数组,使用typeof无法判断,但可以使用[1, 2] instanceof Array来判断。因为,[1, 2]是数组,它的构造函数就是Array。同理:

function Foo(name) {

   this.name = name

}

var foo = new Foo('bar’)

console.log(foo instanceof Foo) // true

3,JavaScript有几种类型的值?,你能画一下他们的内存图吗?

栈:原始数据类型(Undefined,Null,Boolean,Number、String)

堆:引用数据类型(对象、数组和函数)

两种类型的区别是:存储位置不同;

(1)原始数据类型直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储;

(2)引用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定,如果存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体

在参数传递方式上,原始类型是按值传递,引用类型是按共享传递

JS 中这种设计的原因是:按值传递的类型,复制一份存入栈内存,这类类型一般不占用太多内存,而且按值传递保证了其访问速度。按共享传递的类型,是复制其引用,而不是整个复制其值(C 语言中的指针),保证过大的对象等不会因为不停复制内容而造成内存的浪费。

4,介绍js有哪些内置对象?    

Object 是 JavaScript 中所有对象的父对象  

数据封装类对象:Object、Array、Boolean、Number 和 String    

其他对象:Function、Arguments、Math、Date、RegEx、Error

5,如何区分数组和对象?    

1、从原型入手,Array.prototype.isPrototypeOf(obj);  利用isPrototypeOf()方法,判定Array是不是在obj的原型链中,如果是,则返回true,否则false。Array.prototype.isPrototype([]) //true

2、也可以从构造函数入手,利用对向的constructor属性

3、根据对象的class属性(类属性),跨原型链调用toString()方法。Object.prototype.toString.call(Window);

4、Array.isArray()方法。

 

6,null,undefined 的区别?

null        表示一个对象被定义了,值为“空值”;

undefined   表示不存在这个值。

typeof undefined //"undefined"

undefined :是一个表示"无"的原始值或者说表示"缺少值",就是此处应该有一个值,但是还没有定义。当尝试读取时会返回 undefined;

例如变量被声明了,但没有赋值时,就等于undefined

typeof null //"object"

null : 是一个对象(空对象, 没有任何属性和方法);

例如作为函数的参数,表示该函数的参数不是对象;

注意:

在验证null时,一定要使用 === ,因为 == 无法分别 null 和 undefined

undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。典型用法是:

1)变量被声明了,但没有赋值时,就等于undefined。

2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。

3)对象没有赋值的属性,该属性的值为undefined。

4)函数没有返回值时,默认返回undefined。

null表示"没有对象",即该处不应该有值。典型用法是:

1) 作为函数的参数,表示该函数的参数不是对象。

2) 作为对象原型链的终点。

 

数组和对象有哪些原生方法,列举一下?

 数组的常用方法:

方法

说明

slice() 数组对象.slice(start,end)

获取数组中的某段数组元素

unshift() 数组对象.unshift(新元素1,新元素2,…,新元素n);

在数组开头添加元素

push() 数组对象.push(新元素1,新元素2,…,新元素n);

在数组末尾添加元素

shift() 数组对象.shift();

删除数组中第一个元素

pop() 数组对象.pop();

删除数组最后一个元素

toString() 数组对象.toString()

将数组转换为字符串

join() 数组对象.join("分隔符")

将数组元素连接成字符串

concat() 数组1.concat(数组2,数组3,…,数组n)

多个数组连接为字符串concat,就是“合并”的意思。

sort() 数组对象.sort(函数名)

数组元素正向排序

reverse() 数组对象.reverse();

数组元素反向排序

 

 对象的常用方法

obj.assign(),

字符串有哪些原生方法,列举一下?

charAt()    返回在指定位置的字符。
charCodeAt()    返回在指定的位置的字符的 Unicode 编码。
concat()    连接字符串。
indexOf()    检索字符串。
match()    找到一个或多个正则表达式的匹配。
replace()    替换与正则表达式匹配的子串。
search()    检索与正则表达式相匹配的值。
slice()    提取字符串的片断,并在新的字符串中返回被提取的部分。
split()    把字符串分割为字符串数组。
toLocaleLowerCase()    把字符串转换为小写。
toLocaleUpperCase()    把字符串转换为大写。
toLowerCase()    把字符串转换为小写。
toUpperCase()    把字符串转换为大写。
substr()    从起始索引号提取字符串中指定数目的字符。
substring()    提取字符串中两个指定的索引号之间的字符。
 

 null和undefined的区别

null是一个表示"无"的对象,转为数值时为0;undefined是一个表示"无"的原始值,转为数值时为NaN。

== 和 === 的区别 

 1.===:三个等号我们称为等同符,当等号两边的值为相同类型的时候,直接比较等号两边的值,值相同则返回true,若等号两边的值类型不同时直接返回false。

     例:

100===“100”   //返回false
abc===“abc”   //返回false
 ‘abc’===“abc”  //返回true
NaN===NaN   //返回false
 false===false  //返回true

2.==:两个等号我们称为等值符,当等号两边的值为相同类型时比较值是否相同,类型不同时会发生类型的自动转换,转换为相同的类型后再作比较。
类型转换规则:

1)如果等号两边是boolean、string、number三者中任意两者进行比较时,优先转换为数字进行比较。
 2)如果等号两边出现了null或undefined,null和undefined除了和自己相等,就彼此相等
     例:

 100==“100”    //返回true
 1==true          //返回true
“1”==“01”      //返回false,此处等号两边值得类型相同,不要再转换类型了!!
 NaN==NaN  //返回false,NaN和所有值包括自己都不相等。

关于变量和常量

let

let 用来声明变量,类似于变量,但是所声明的变量,只在let命令所在的代码块内有效

需要注意的地方:

1.不存在变量提升,未声明直接报错

2.暂时性死区

3.for循环具有两个作用域,外面的变量和里面的变量互不干扰

 

const

用来声明一个只读的常量,一旦尚明,常量的值就不可以改变了,而且声明的时候必须赋值

 

需要注意的地方:

引用类型储存的是一个地址,所以用const声明的引用数据类型,只要不改变指针地址,就可以

如果为常量赋其他的值,就会报错。

数组的深拷贝

const a1 = [1,2];

1.const a2 = [...a1];

2.const [...a2] = a1;

关于本地存储和会话存储

常用浏览器存储方案有,cookie,session,localstorage,sessionstroage,区别在于:

1.方式: cookie通过请求头发送,在浏览器与服务器之间来回传递,sessionStroage与   localStroage不会把数据发给服务器,仅在本地保存

2.存储量​:cookie存储量小,一般在4到8kb,其余存储量大5M

3.数据有效期不同,

     sessionStorage:仅在当前浏览器窗口关闭前有效,自然也就不可能持久保存

     localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据

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

4.作用域​

     sessionStorage不能在不同的浏览器窗口*享,即使是同一个页面;

     localStorage 在所有同源窗口中都是共享的

     cookie也是在所有同源窗口中都是共享的。

关于异步处理:Generator   async   promise  的区别

详细理解:https://www.jianshu.com/p/f17d577f677e

移动端适配的技术方案:

(1)通过媒体查询的方式即CSS3的meida queries

(2)以天猫首页为代表的 flex 弹性布局

(3)以淘宝首页为代表的 rem+viewport缩放 (推荐)

(4)rem 方式(推荐)

详细参考:https://blog.****.net/chenjuan1993/article/details/81710022

ES6常用特性

变量定义(let和const,可变与不可变,const定义对象的特殊情况)

解构赋值

模板字符串

数组新API(例:Array.from(),entries(),values(),keys())

箭头函数(rest参数,扩展运算符,::绑定this)

特点:箭头函数中的this始终指向箭头函数定义时的离this最近的一个函数,如果没有最近的函数就指向window。

箭头函数其实只是一个匿名函数的语法糖,区别在于普通函数作用域中的this有特定的指向,一般指向window,而箭头函数中的this只有一个指向那就是指当前函数所在的对象,其实现原理其实就是类似于之前编程的时候在函数外围定义that一样,用了箭头函数就不用定义that了直接使用this

Set和Map数据结构(set实例成员值唯一存储key值,map实例存储键值对(key-value))

(1) Set 类似于数组,但数组可以允许元素重复,Set 不允许元素重复 


(2)Map 类似于对象,但普通对象的 key 必须是字符串或者数字,而 Map 的 key 可以是任何数据类型 


Promise对象(前端异步解决方案进化史,generator函数,async函数)

Class语法糖(super关键字)

 

总结前端性能优化的解决方案

 

优化的方向有两个:

减少页面体积,提升网络加载

优化页面渲染

 

减少页面体积,提升网络加载

静态资源的压缩合并(JS 代码压缩合并、CSS 代码压缩合并、雪碧图)

静态资源缓存(资源名称加 MD5 戳)

使用 CDN 让资源加载更快

优化页面渲染

CSS 放前面,JS 放后面

懒加载(图片懒加载、下拉加载更多)

减少DOM 查询,对 DOM 查询做缓存

减少DOM 操作,多个操作尽量合并在一起执行(DocumentFragment)

事件节流

尽早执行操作(DOMContentLoaded)

使用 SSR 后端渲染,数据直接输出到 HTML 中,减少浏览器使用 JS 模板渲染页面 HTML 的时间
 

Ajax原理

(1)创建对象

var xhr = new XMLHttpRequest();

(2)打开请求

xhr.open('GET', 'example.txt', true);

(3)发送请求

xhr.send(); 发送请求到服务器

(4)接收响应

xhr.onreadystatechange =function(){}

(1)当readystate值从一个值变为另一个值时,都会触发readystatechange事件。

(2)当readystate==4时,表示已经接收到全部响应数据。

(3)当status ==200时,表示服务器成功返回页面和数据。

(4)如果(2)和(3)内容同时满足,则可以通过xhr.responseText,获得服务器返回的内容。

浅拷贝和深拷贝

jQuery.extend第一个参数可以是布尔值,用来设置是否深度拷贝的

jQuery.extend(true, { a : { a : "a" } }, { a : { b : "b" } } );
jQuery.extend( { a : { a : "a" } }, { a : { b : "b" } } ); 

最简单的深拷贝

aa = JSON.parse( JSON.stringify(a) )

浅复制--->就是将一个对象的内存地址的“”编号“”复制给另一个对象。深复制--->实现原理,先新建一个空对象,内存中新开辟一块地址,把被复制对象的所有可枚举的(注意可枚举的对象)属性方法一一复制过来,注意要用递归来复制子对象里面的所有属性和方法,直到子子.....属性为基本数据类型。总结,深复制理解两点,1,新开辟内存地址,2,递归来刨根复制。

 

事件冒泡和事件捕捉 https://blog.****.net/qq_40510139/article/details/89320892

闭包   https://blog.****.net/qq_40510139/article/details/78825156

div上下左右居中

position: absolute;
margin: auto;
top: 0; left: 0; bottom: 0; right: 0;

参考:https://blog.****.net/qq_36658051/article/details/81985024

js面试题扩展:https://www.jianshu.com/p/f1f39d5b2a2e

vue部分

重中之重、Vue的双向数据绑定原理是什么?

实现数据绑定的做法有大致如下几种:

  • 发布者-订阅者模式(backbone.js)
  • 脏值检查(angular.js)
  • 数据劫持(vue.js)

答:vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

前端面试题js+vue(2019年5月总结)
具体步骤:

已经了解到vue是通过数据劫持的方式来做数据绑定的,其中最核心的方法便是通过Object.defineProperty()来实现对属性的劫持,达到监听数据变动的目的。 
要实现mvvm的双向绑定,就必须要实现以下几点: 
1、实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者 
2、实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数 
3、实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图 
4、mvvm入口函数,整合以上三者

详细理解:https://www.jianshu.com/p/f194619f6f26

一、什么是MVVM?
MVVM是Model-View-ViewModel的缩写。MVVM是一种设计思想。Model 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑;View 代表UI 组件,它负责将数据模型转化成UI 展现出来,ViewModel 是一个同步View 和 Model的对象。
在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。
ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。

二、mvvm和mvc区别?它和其它框架(jquery)的区别是什么?哪些场景适合?
mvc和mvvm其实区别并不大。都是一种设计思想。主要就是mvc中Controller演变成mvvm中的viewModel。mvvm主要解决了mvc中大量的DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。
区别:vue数据驱动,通过数据来显示视图层而不是节点操作。
场景:数据操作比较多的场景,更加便捷

三、vue的优点是什么?
低耦合。视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的"View"上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
可重用性。你可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。
独立开发。开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计。
可测试。界面素来是比较难于测试的,而现在测试可以针对ViewModel来写。

四、 组件之间的传值?(重点)

1.父组件与子组件传值
父组件传给子组件:子组件通过props方法接受数据;
子组件传给父组件:$emit方法传递参数
2.非父子组件间的数据传递,兄弟组件传值
eventBus,就是创建一个事件中心,相当于中转站,可以用它来传递事件和接收事件。项目比较小时,用这个比较合适。(虽然也有不少人推荐直接用VUEX,具体来说看需求咯。技术只是手段,目的达到才是王道。)

五、路由之间跳转
声明式(标签跳转) 编程式( js跳转)

vue-router基本原理:(重点)

vue-router通过hashHistory interface两种方式实现前端路由,更新视图但不重新请求页面。

主要有两种方式:

1、hash ---- 利用URL中的hash(“#”)

2、利用History interface在 HTML5中新增的方法,

详细理解:https://www.jianshu.com/p/4295aec31302

六、vue.cli中怎样使用自定义的组件?有遇到过哪些问题吗?
第一步:在components目录新建你的组件文件(indexPage.vue),script一定要export default {}
第二步:在需要用的页面(组件)中导入:import indexPage from ‘@/components/indexPage.vue’
第三步:注入到vue的子组件的components属性上面,components:{indexPage}
第四步:在template视图view中使用,
例如有indexPage命名,使用的时候则index-page

七、vue如何实现按需加载配合webpack设置
webpack中提供了require.ensure()来实现按需加载。以前引入路由是通过import 这样的方式引入,改为const定义的方式进行引入。
不进行页面按需加载引入方式:import home from '../../common/home.vue'
进行页面按需加载的引入方式:
const home = r => require.ensure( [], () => r (require('../../common/home.vue')))

八、vuex面试相关(重点)
(1)vuex是什么?怎么使用?哪种功能场景使用它?
vue框架中状态管理。在main.js引入store,注入。新建一个目录store,…… export 。场景有:单页应用中,组件之间的状态。音乐播放、登录状态、加入购物车
(2)vuex有哪几种属性?

工作原理:

前端面试题js+vue(2019年5月总结)

通过官方文档提供的流程图我们知道,vuex的工作流程,

1、数据从state中渲染到页面;

2、在页面通过dispatch来触发action

3、action通过调用commit,来触发mutation

4、mutation来更改数据,数据变更之后会触发dep对象的notify,通知所有Watcher对象去修改对应视图(vue的双向数据绑定原理)。
(3)不用Vuex会带来什么问题?
可维护性会下降,想修改数据要维护三个地方;
可读性会下降,因为一个组件里的数据,根本就看不出来是从哪来的;
增加耦合,大量的上传派发,会让耦合性大大增加,本来Vue用Component就是为了减少耦合,现在这么用,和组件化的初衷相背。

九、 v-show和v-if指令的共同点和不同点
v-show指令是通过修改元素的display的CSS属性让其显示或者隐藏
v-if指令是直接销毁和重建DOM达到让元素显示和隐藏的效果

十、 如何让CSS只在当前组件中起作用
将当前组件的

十一、的作用是什么?
包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免重新渲染。

十二、Vue中引入组件的步骤?
1)采用ES6的import … from …语法或CommonJS的require()方法引入组件
2)对组件进行注册,代码如下

十三、如何让CSS只在当前组件中起作用?

将当前组件的<style>修改为<style scoped>

十四、在Vue中使用插件的步骤
采用ES6的import … from …语法或CommonJSd的require()方法引入插件
使用全局方法Vue.use( plugin )使用插件,可以传入一个选项对象Vue.use(MyPlugin, { someOption: true })

十五、请列举出3个Vue中常用的生命周期钩子函数
created: 实例已经创建完成之后调用,在这一步,实例已经完成数据观测, 属性和方法的运算, watch/event事件回调. 然而, 挂载阶段还没有开始, el属性目前还不可见mounted:el被新创建的vm. el属性目前还不可见mounted : el被新创建的 vm.el属性目前还不可见mounted:el被新创建的vm.el 替换,并挂载到实例上去之后调用该钩子。如果 root 实例挂载了一个文档内元素,当 mounted 被调用时 vm.$el 也在文档内。
activated: keep-alive组件**时调用

十六、active-class是哪个组件的属性?
vue-router模块的router-link组件。

十七、箭头函数和普通函数的区别

参考:https://www.jianshu.com/p/73cbeb6782a0

十九、生命周期相关面试题
总共分为8个阶段:

beforeCreate(创建前) 在数据观测和初始化事件还未开始
created(创建后) 完成数据观测,属性和方法的运算,初始化事件,$el属性还没有显示出来
beforeMount(载入前) 在挂载开始之前被调用,相关的render函数首次被调用。实例已完成以下的配置:编译模板,把data里面的数据和模板生成html。注意此时还没有挂载html到页面上。
mounted(载入后) 在el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用。实例已完成以下的配置:用上面编译好的html内容替换el属性指向的DOM对象。完成模板中的html渲染到html页面中。此过程中进行ajax交互。
beforeUpdate(更新前) 在数据更新之前调用,发生在虚拟DOM重新渲染和打补丁之前。可以在该钩子中进一步地更改状态,不会触发附加的重渲染过程。
updated(更新后) 在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用。
beforeDestroy(销毁前) 在实例销毁之前调用。实例仍然完全可用。
destroyed(销毁后) 在实例销毁之后调用。调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。

(1)、什么是vue生命周期
答: Vue 实例从创建到销毁的过程,就是生命周期。也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。

(2)、vue生命周期的作用是什么
答:它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑。

(3)、vue生命周期总共有几个阶段
答:可以总共分为8个阶段:创建前/后, 载入前/后,更新前/后,销毁前/销毁后

(4)、第一次页面加载会触发哪几个钩子
答:第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个钩子

(5)、DOM 渲染在 哪个周期中就已经完成
答:DOM 渲染在 mounted 中就已经完成了。

(6)、简单描述每个周期具体适合哪些场景
答:生命周期钩子的一些使用方法:
beforecreate : 可以在这加个loading事件,在加载实例时触发
created : 初始化完成时的事件写在这里,如在这结束loading事件,异步请求也适宜在这里调用
mounted : 挂载元素,获取到DOM节点
updated : 如果对数据统一处理,在这里写上相应函数
beforeDestroy : 可以做一个确认停止事件的确认框
nextTick : 更新数据后立即操作dom

详细原理请看:https://www.jianshu.com/p/69d447321740

二十、说出至少4种vue当中的指令和它的用法?
v-if:判断是否隐藏;v-for:数据循环;v-bind:class:绑定一个属性;v-model:实现双向绑定

二十二、scss是什么?在vue.cli中的安装使用步骤是?有哪几大特性?
答:css的预编译。
使用步骤:
第一步:先装css-loader、node-loader、sass-loader等加载器模块
第二步:在build目录找到webpack.base.config.js,在那个extends属性中加一个拓展.scss
第三步:在同一个文件,配置一个module属性
第四步:然后在组件的style标签加上lang属性 ,例如:lang=”scss”
特性:
可以用变量,例如($变量名称=值);
可以用混合器,例如()
可以嵌套

二十四、为什么避免 v-if 和 v-for 用在一起
当 Vue 处理指令时,v-for 比 v-if 具有更高的优先级,通过v-if 移动到容器元素,不会再重复遍历列表中的每个值。取而代之的是,我们只检查它一次,且不会在 v-if 为否的时候运算 v-for。