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

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

js、H5、css部分

css部分

less特点:1. 变量 2. 混合(Mixins) 3. 嵌套规则 4. 运算 5. 函数 6. 命名空间 7. 作用域 8. 注释 9. 导入(Import)

数据类型

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 的区别?

console.log(null==undefined);    //true  因为两者都默认转换成了false
console.log(typeof undefined);    //"undefined"  
console.log(typeof null);       //"object"  
console.log(null===undefined);    //false   "==="表示绝对相等,null和undefined类型是不一样的,所以输出“false”

null表示没有对象,即该处不应该有值

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

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

undefined表示缺少值,即此处应该有值,但没有定义

1)定义了形参,没有传实参,显示undefined

2)对象属性名不存在时,显示undefined

3)函数没有写返回值,即没有写return,拿到的是undefined

4)写了return,但没有赋值,拿到的是undefined

null和undefined转换成number数据类型

null 默认转成 0

undefined 默认转成 NaN

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

 数组的常用方法:

方法

说明

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.csdn.net/chenjuan1993/article/details/81710022

ES6常用特性

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

解构赋值

模板字符串

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

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

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

1不能作为构造函数,不能使用new

2不能使用argumetns,取而代之用rest参数...解决

3不绑定this,会捕获其定义时所在的this指向作为自己的this。由于在vue中自动绑定 this 上下文到实例中,因此不能使用箭头函数来定义一个周期方法。箭头函数的this永远指向上下文的this,call、apply、bind也无法改变

4箭头函数没有原型对象

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

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

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

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


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


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

Class语法糖(super关键字)

 

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

https://segmentfault.com/a/1190000022205291

优化的方向有两个:

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

优化页面渲染

 

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

静态资源的压缩合并(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.csdn.net/qq_40510139/article/details/89320892

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

div上下左右居中

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

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

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

js设计模式:

https://www.cnblogs.com/imwtr/p/9451129.html

HTTP协议:

https://www.cnblogs.com/123blog/articles/10297650.html

vue部分

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

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

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

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

前端面试题js+vue(2019年5月总结)_第1张图片
具体步骤:

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

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

provide/inject的学习

https://segmentfault.com/a/1190000014095107?utm_source=tag-newest

一、什么是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,具体来说看需求咯。技术只是手段,目的达到才是王道。)

父子组件互相调用方法

父组件中定义好了方法 hello(),在子组件中直接用:this.$parent.hello();

父组件调用子组件的方法:this.$refs.pass.fn1;

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

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

主要有两种方式:

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

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

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

七、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有哪几种属性?

工作原理:

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

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

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

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

4、mutation来更改数据,数据变更之后会触发dep对象的notify,通知所有Watcher对象去修改对应视图(vue的双向数据绑定原理)。

前端面试题js+vue(2019年5月总结)_第2张图片
(3)不用Vuex会带来什么问题?
可维护性会下降,想修改数据要维护三个地方;
可读性会下降,因为一个组件里的数据,根本就看不出来是从哪来的;
增加耦合,大量的上传派发,会让耦合性大大增加,本来Vue用Component就是为了减少耦合,现在这么用,和组件化的初衷相背。

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

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

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

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

将当前组件的