2018面试题小结

1、MVVM和MVC的区别?
(1)MVC中M表示Model模型,V表示view视图, C表示controller控制器;MVVM中M表示model模型,V表示view视图,VM表示viewmodel;
(2)MVC的看法是界面上的每个变化都是一个事件,我们只需要针对每个事件来写一堆代码,来把用户的输入转换成model里的对象,而这段转换的代码就是controller。简言之,MVC是单向通信,view和model必须通过controller来承上启下。
        MVVM的看法是我给view里面的各种控件也定义一个对应的数据对象,只需要修改这个数据对象,view里面显示的内容就会自动更新,而view里做了任何操作,这个数据对象也会跟着更新。这就是所谓的双向数据绑定。viewmodel就是与界面view对应的model,因为数据库结构往往是不能直接和界面控件一一对应,所以我们需要再定义一个数据对象专门对应view上的控件,而viewmodel的职责就是把model对象封装成可以显示和接受输入的界面数据对象。简单来说,viewmodel就是view和model的连接器,view和model通过viewmodel实现双向绑定。
(3)MVC各部分通信如下:
 
view传送指令到controller,controller完成业务逻辑后,要求model改变状态,model将新的数据发送到view,用户得到反馈。
 
MVVM各部分通信如下:
 
各部分之间的通信都是双向的,view与model不发生联系,而通过viewmodel传递,view非常薄,不部署任何业务逻辑,称为‘被动视图’,即没有任何主动性,而viewmodel非常厚,所有的逻辑都部署在那里。
MVVM和MVP的主要区别在于,MVVM采用的是双向绑定,view的变动自动反映在viewmodel上,反之亦然。angular、ember、vue都采用这种模式。
 
2、Mobx和Redux的区别?
(1)Mobx的优势来源于可变数据和可观察数据;Redux的优势来源于不可变数据。
(2)redux和mobx都没有使用传统的mvc/mvvm形式,而是采用flux的结构,action处理请求,然后将请求dispatch到store中,这样设计也十分契合react单向数据流的概念。两者使用flux结构也略有不同,mobx在store和view中处理数据是使用双向绑定。双向绑定无疑会增加性能消耗,但是mobx在双向绑定的同时禁掉了react自身的刷新。
(3)框架体验,开发效率,学习成本方面mobx更好
 
3、angular和vue的区别?
(1)数据绑定
angular和vue都是双向绑定,但是vue在不同组件之间强制使用单项数据流,这样使应用中的数据流更加清晰易懂。
(2)指令和组件
在vue中指令和组件分得很清晰。指令只封装dom操作,而组件代表自给自足独立的单元,就是有自己的视图和数据逻辑。
在angular中,每件事都由指令来做,而组件只是一种特殊的指令。
 
4、axios
(1)处理并发请求助手函数(两个请求都完成才执行操作)
axios.all(iterable),axios.spread(callback)
function getUserAccount() {
    return axios.get('/user/123456')
}
 
function getUserPermissions() {
    return axios.get('/user/123456/permissions')
}
 
axios.all([getUserAccount(), getUserPermissions()])
.then(axios.spread(function(acct, perms) {
    // 两个请求现在都执行完成
}))
 
(2)拦截器:在请求或响应被then或者catch处理之前拦截他们
// 添加请求拦截器
axios.interceptors.request.use(function(config) {
    // 在发送请求前做些什么
    return config
}, function(error) {
    // 对请求错误做些什么
    return Promise.reject(error)
});
 
// 添加响应拦截器
axios.interceptors.response.use(function(response){
    // 对响应数据做些什么
    return response
}, function(error) {
    // 对响应错误做些什么
    return Promise.reject(error)
})
如果想在稍后移除拦截器:
var myInterceptor = axios.interceptors.request.use(function(){});
axios.interceptors.request.eject(myInterceptor);
 
(3)、使用cancel token取消请求
可以使用CancelToken.source工厂方法创建cancel token:
var CancelToken = axios.CancelToken;
var source = CancelToken.source();
 
axios.get('/user/123456', {
    cancelToken: source.token
}).catch(function(throw) {
    if (axios.isCancel(throw)) {
        console.log('request cancel', throw.message)
    } else {
        // 处理错误
    }
})
 
// 取消请求,message参数是可选的
source.cancel('Operation canceled by the user');
还可以通过传递一个executor函数到CancelToken的构造函数来创建cancelToken:
var CancelToken = axiox.CancelToken;
var cancel;
 
axios.get('/user/123', {
    cancelToken: new CancelToken(function executor(c) {
        // executor函数接收一个cancel作为参数
        cancel = c
    })
})
 
// 取消请求
cancel();
可以使用同一个cancel token取消多个请求。
 
5、promise
promise是为了解决回调地狱的问题,是异步编程的一种解决方案。简单来说,它就是一个容器,里面存放着某个未来才会结束的事件(通常是一个异步操作的结果)。从语法上说,他就是一个对象(构造函数),从它可以获取异步操作的消息。它提供统一的API,各种异步操作都可以用同样的方法进行处理。
promise的原理并不难, 它有三个状态,分别是pending、fulfilled、rejected。pending是对象创建后的初始状态,当对象fulfill(成功)时变为fulfilled,当对象reject(失败)时变为rejected。且只能从pending变为fulfilled或rejected,而不能逆向或者从fulfilled变为rejected或者从rejected变为fulfilled。
(1)promise.all()方法是等所有异步操作都执行完毕后才执行then回调
(2)promise.race()
race就是赛跑的意思,所以它是指只要有一个异步操作执行完成就会立刻执行then回调,其他没有执行完成的异步操作仍然在继续执行,而不是停止。
 
(1)less和sass在语法上有些共性:(8个)
  • 混合:class中的class(将一个定义好的class A引入到另一个class B中,从而简单实现class B继承了class A的所有属性)
  • 参数混合: 可以将class像函数的参数一样进行传递
  • 嵌套规则:class中嵌套class,从而减少重复的代码(在一个选择器中嵌套另一个选择器来实现继承)
  • 运算: css中的数学计算(在css中使用加减乘除进行数学计算,主要运用于属性值和颜色的运算)
  • 颜色功能:可以编辑你的颜色(颜色的函数运算,颜色会被先转化成HSL色彩空间,然后在通道级别操作)
  • 命名空间: 样式分组,从而方便被调用(将一些变量或者混合模块打包封装,更好的组织css和属性集的重复使用)
  • 作用域:局部修改样式(先从本地查找变量或者混合模块,如果没有找到的话就会去父级作用域中查找,直到找到为止,这一点和其他程序语言的作用域非常的相似)
  • js表达式:在css样式中使用js表达式赋值(在less或者sass文件中可以使用js的表达式,用来赋值)
(2)less和sass之间的区别:
他们之间的主要区别在于实现方式不同,less是基于js运行,所以less是在客户端处理;sass是基于ruby的,是在服务器端处理的。
很多开发者不选择less是因为less输出修改过的css到浏览器需要依赖于js引擎,而js引擎需要额外的时间来处理代码。关于这个有很多种方式,我选择的是只在开发环节使用less。一旦开发完成,我就复制粘贴less输出到一个压缩器,然后到一个单独的css文件来替代less文件。另一种方式是使用less app来编译和压缩你的less文件。两种方式都将是最小化你的样式输出,从而避免由于用户的浏览器不支持js而可能引起的任何问题。
 
7、es6
(1)、新增了let和const命令
let用来声明变量,用法类似var,但是所声明的变量只在let命令所在的代码块内有效,const一般用作声明常量,只声明不赋值就会报错;
let和const都不存在变量提升,也就是说只能在声明后使用,否则报错;
let和const都存在‘暂时性死区’,就是说只要在块级作用域内存在const或者let命令声明的变量,那么它声明的变量就绑定这个区域,不再受到外部的影响,这就叫‘暂时性死区’;
let和const不允许在相同作用域内重复声明同一个变量;
let和const实际上是为js新增了块级作用域。
 
(2)、对字符串进行了扩展
比如模板字符串:
模板字符串是增强版的字符串,用反引号(`)标识,它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。模板字符串中嵌入变量,需要将变量名写在${}中。
 
(3)、箭头函数
箭头函数在定义之后,this的指向就不会发生改变了,无论用什么方式调用它,this的指向都不会改变。因为:
函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象;
不可以当作构造函数,也就是说不可以使用new命令,否则报错;
不可以使用arguments对象,该对象在函数体内不存在,如果要用,可以用rest参数代替;
不可以使用yield命令,因此箭头函数不能用作Generator函数。
eg:
 
 
(4)promise
 
(5)变量的解构赋值
ES6允许按照一定的模式,从数组和对象中提取值,对变量进行赋值,这被称为解构。本质上,这种写法属于‘模式匹配’,只要等号两边的模式相同,左边的变量就会被赋予对应的值。
对象的解构与数组有一个重要的不同,数组元素是按照次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
 
 
解构赋值允许指定默认值:
 
还有很多。。。。。
 
8、cookie、sessionStorage、localStorage异同点
(1)数据生命周期
cookie生成时就会被指定一个maxAge值,这就是cookie的生存周期,在这个期间内cookie都有效,默认是浏览器关闭失效;
sessionStorage页面会话期间可用;
localStorage除非数据被清除,否则一直存在。
 
(2)存放数据大小
cookie4k左右,因为每次http请求,都会携带cookie;
sessionStorage和localStorage一般5M或者更大;
 
(3)与服务器通信
cookie由对服务器的请求来传递,每次都会携带在http头中,如果使用cookie保存过多的数据会带来性能问题;
sessionStorage和localStorage数据不是由每个服务器请求传递的,而是只有在请求时使用数据,不参与与服务器的通信
 
(4)易用性
cookie需要自己封装setCookie和getCookie;
sessionStorage和localStorage可以用源生接口,也可以再次封装来对object和array有更好的支持
 
(5)共同点
都是保存在浏览器端,和服务器端的session机制不同
 
9、JSONP的原理
ajax请求受到同源策略的影响,不允许进行不跨域请求,而script标签的src属性中的链接却可以访问跨域的js脚本,利用这个特性,服务端不再返回json格式的数据,而是返回一段调用某个函数的js代码,在src中进行了调用,这样就实现了跨域。
 
10、vue的生命周期
beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy、destroyed
 
11、什么是闭包?
闭包就是能够读取其他函数内部变量的函数。例如在js中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解为‘定义在一个函数内部的函数’。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。
 
12、原型链
(1)、构造函数、原型、实例的关系
构造函数都有一个proptotype属性;
原型对象prototype里面有一个constructor属性,该属性指向原型对象所属的构造函数;
实例对象都有一个__proto__属性,该属性也指向构造函数的原型对象,他是一个非标准属性,不可以用于编程,是浏览器自己使用的。
 
(2)prototype和__proto__关系
prototype是构造函数的属性,__proto__是实例对象的属性。这两者都指向同一个对象。
 
(3)原型链属性搜索(什么是原型链)?
在访问对象的某个成员的时候,会先从对象本身进行查找,如果对象中查找不到,那么就会去它的构造函数的原型对象中进行查找,如果没有找到,那么就会去它的原型对象的原型对象中查找,这样一层一层往上查找,直到object的原型对象的原型是null为止。
 
13、如何理解同步和异步?
所有任务都可以分成两种,一种是同步任务(syn),另一种是异步任务(asyn)。同步任务指的是在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程,而进入‘任务队列’的任务,只有‘任务对列’通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
运行机制如下:
(1)所有同步任务都在主线程上执行,形成一个执行栈
(2)主线程外,还存在一个任务队列,只要异步任务有了运行结果,就在任务队列中放置一个事件
(3)一旦执行栈中的所有同步任务执行完毕,系统就会读取任务队列,看看里面有哪些事件。那些对应的异步任务就会结束等待状态,而进入执行栈,开始执行
(4)主线程上不断重复上面三步。
 
14、webpack
(1)什么是webpack?
webpack可以看作是模块打包机,她做的事情是分析你的项目结构,找到js模块以及其他的一些浏览器不能直接运行的拓展语言(sass、typescript等),并将其转换和打包为合适的格式供浏览器使用。
 
(2)webpack的工作方式
wenpack的工作方式是把你的项目当作一个整体,通过一个给定的主文件(如index.js),webpack将从这个文件开始找到你项目的所有依赖文件,使用loaders处理他们,最后打包为一个或者多个浏览器可识别的js文件
 
(3)打包原理
把所有依赖打包成一个bundle.js文件,通过代码分割成单元片段并按需加载。
 
(4)webpack的核心思想
一切皆模块:正如js文件可以是一个模块,其他文件css、image或者html也可以视作模块,因此,可以require('xxx.css'),这意味着我们将事物分割成更小的易于管理的片段,从而达到重复利用的目的。
 
按需加载:传统的模块打包工具最终将所有的模块编译生成一个庞大的bundle.js文件,但是在真实的app里面,bundle.js文件可能有10M或者15M之大,可能会导致应用一直处于加载中状态。因此webpack使用很多特性来分割代码然后生成多个bundle.js文件,而且异步加载部分代码以实现按需加载。
 
15、vue双向数据绑定的原理
主要是通过object对象的defineProperty属性,重写data的set和get函数来实现的。
 
16、React组件生命周期过程说明
(1)实例化
首次实例化:
  • getDefaultProps
  • getInitialState
  • componentWillMount
  • render
  • componentDidMount
实例化完成后的更新:
  • getInitialState
  • componentWillMount
  • render
  • componentDidMount
 
(2)存在期
组件已存在时的状态改变:
  • componentWillReceiveProps
  • shouldComponentUpdate
  • componentWillUpdate
  • render
  • componentDidUpdate
 
(3)销毁&清理期
  • componentWillUnmount
 
(4)说明
声明周期共提供了10个不同的API
 
getDefaultProps:作用于组件类,只调用一次,返回对象用于设置默认的props,对于引用值,会在实例中共享。
 
getInitialState:作用于组件的实例,在实例创建时调用一次,用于初始化每个实例的state,此时可以访问this.props。
 
componentWillMount:在完成首次渲染之前调用,此时仍可以修改组件的state。
 
render:必选的方法,创建虚拟DOM,该方法具有特殊的规则:
  • 只能通过this.props和this.state访问数据
  • 可以返回null、false或者任何React组件
  • 只能出现一个顶级组件(不能返回数组)
  • 不能改变组件的状态
  • 不能修改DOM的输出
 
componentDidMount:真实的DOM被渲染出来后调用,在该方法中可以通过this.getDOMNode()访问到真实的DOM元素,此时已经可以使用其他类库来操作这个DOM。
在服务器端,该方法不会被调用。
 
componentWillReceiveProps:组件接收到新的props时调用,并将其作为参数nextProps使用,此时可以更改组件props以及state。
componentWillReceiveProps: function(nextProps) { if (nextProps.bool) { this.setState({ bool: true }); } }
 
shouldComponentUpdate:组件是否应当渲染新的props或state,返回false表示跳过后续的生命周期方法,通常不需要使用以避免出现bug。在出现应用的瓶颈时,可以通过该方法进行适当的优化。
在首次渲染期间或者调用了forceUpdate方法后,该方法不会被调用。
 
componentWillUpdate:接收到新的props或者state后,进行渲染前调用,此时不允许更改props或者state。
 
componentDidUpdate:完成渲染新的props或者state后调用,此时可以访问到新的DOM元素。
 
componentWillUnmount:组件被移除之前调用,可以用于做一些清理工作,在componentDidMount方法中添加的所有任务都需要在该方法中撤销,比如创建的定时器或者添加的事件监听器。
 
17、React+Mobx核心概念
(1)state----状态
状态是驱动应用的数据
 
(2)observable(value)&&@observable
observable值可以是JS基本数据类型、引用类型、普通对象、类实例、数组和映射。其修饰的state会暴露出来供观察者使用。
 
(3)observer(观察者)
被observer修饰的组件,将会根据组件内使用到的被observable修饰的state的变化而自动重新渲染
 
(4)action(动作)
只有在actions中,才可以修改Mobx中的state的值。
注意:当你使用装饰器模式时,@action中的this没有绑定在当前这个实例上,要用@action.bound来绑定使得this绑定在实例对象上
 
(5)computed
计算值(computed values)是可以根据现有的状态或者其他计算值衍生出的值
getter:获取计算得到的新的state并返回
setter:不能用来直接改变计算属性的值,但是他们可以用来作‘逆向’衍生。
 

猜你喜欢

转载自www.cnblogs.com/sup9278/p/8934525.html