一 、Js部分
1、js里面的数据类型
boolean,null,undefined,number,string,object,再加上es6提供的symbol,目前js一共有6+1种数据类型
2、tyepof和instanceof有何区别?
typeof用来判断变量的数据类型,只有六个值boolean,number,string,null。undefined,object
console.log(typeof (123));//typeof(123)返回"number"
console.log(typeof ("123"));//typeof("123")返回"string"
var param1 = "string";
var param2 = new Object();
var param3 = 10;
console.log(typeof(param1)+"\n"+typeof(param2)+"\n"+typeof(param3));
// string object number
instanceof用来判断一个变量或者一个类型是否存在于一个对象的原型链上
如 :var a=new Array();
alert(a instanceof Array); // true,
同时 alert(a instanceof Object) //也会返回 true;
这是因为 Array 是 object 的子类。
再如:function test(){};
var a=new test();
alert(a instanceof test) 会返回true
alert(a==b); //flase
console.log(Object instanceof Object);//true
console.log(Function instanceof Function);//true
console.log(Number instanceof Number);//false
console.log(String instanceof String);//false
console.log(Function instanceof Object);//true
console.log(Foo instanceof Function);//true
console.log(Foo instanceof Foo);//false
3. typeof判断类型有什么缺点?解决方法是什么?
typeof有三个缺点:
第一个缺点:无法判断NaN,解决方法使用Number.isNaN,如果Number.isNaN无法使用,可以用强类型判断x !== x。
第二个缺点:无法判断数组类型,因为数组也是一个object类型。解决方法:使用Array.isArray()来判断,如果该方法无法使用,则使用原型链来判断。
var isArray = function (x) {
if (!Array.isArray){
return Object.prototype.toString().call(x) === '[object Array]';
}
return Array.isArray(x);
}
第三个缺点:typeof null的结果也是object,无法判断空类型,解决方法:
typeof x== 'object' && x == null //或者原型对象的toString大法
4.ie和w3c标准下的兼容性写法有哪些?举些例子。
a、var ev = ev || window.event
document.documentElement.clientWidth || document.body.clientWidth
Var target = ev.srcElement||ev.target
b、获取事件目标元素:var target = ev.srcElement||ev.target
c、innerText
5、new操作符具体干了什么呢?
1)、创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。
2)、属性和方法被加入到 this 引用的对象中。
3)、新创建的对象由 this 所引用,并且最后隐式的返回 this 。
3、js中哪些内置函数
——Object、Array、Boolean、Number、String、Function、Date、RegExp、Error
6、说明this几种不同的使用场景
—— 1、作为构造函数执行
2、作为对象属性执行
3、作为普通函数执行
4、call、apply、bind
7、同步和异步的区别
——同步会阻塞代码执行,而异步不会。
8、
==和===有什么区别
== 用于比较 判断 两者相等 ==在比较的时候可以转自动换数据类型
true=='1'//true
===用于严格比较 判断两者严格相等 ===严格比较,不会进行自动转换,要求进行比较的操作数必须类型一致,不一致时返回flase。
true==="1"//false
9.什么是option请求?
option用来处理复杂跨域请求的方法。
在正式跨域的请求前,浏览器会根据需要,发起一个“PreFlight”(也就是Option请求),用来让服务端返回允许的方法(如get、post)、被跨域访问的Origin(来源,或者域)、还有是否需要Credentials(认证信息)。
跨域请求分两种:简单请求、复杂请求;
符合以下任一情况的就是复杂请求:
a.使用方法put或者delete;
b.发送json格式的数据(content-type: application/json)
c.请求中带有自定义头部;
如果跨域的请求是Simple Request(简单请求 ),则不会触发“PreFlight”。Mozilla对于简单请求的要求是:
以下三项必须都成立:
a. 只能是Get、Head、Post方法
b. 除了浏览器自己在Http头上加的信息(如Connection、User-Agent),开发者只能加这几个:Accept、Accept-Language、Content-Type、。。。。
c. Content-Type只能取这几个值:
application/x-www-form-urlencoded
multipart/form-data
text/plain
10.为什么跨域的复杂请求需要preflight request?
复杂请求可能对服务器数据产生副作用。例如delete或者put,都会对服务器数据进行修改,所以在请求之前都要先询问服务器,当前网页所在域名是否在服务器的许可名单中,服务器允许后,浏览器才会发出正式的请求,否则不发送正式请求。
11.除了处理复杂请求的option方法之外,你还知道哪些解决跨域的方法?
https://www.cnblogs.com/ldlx-mars/p/7816316.html
11.js如何实现深拷贝和浅拷贝?
浅拷贝:
a、object.assign()来实现。
深拷贝
a、自己封装深拷贝函数
b、借用 JQ 的 extend 方法实现深拷贝。
c、借用JSON对象的 parse 和 stringify
13.get和post两种方法有什么区别?
a、最直观的区别就是GET把参数包含在URL中,POST通过request body传递参数。
b、GET请求只能进行url编码,而POST支持多种编码方式。
c、GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
d、GET请求在URL中传送的参数是有长度限制的,而POST没有有。
总而言之,post是比get更安全的传输方式。
14、http是基于tcp/ip的通信协议,从这个层面来讲,get和post有什么区别?
GET产生一个TCP数据包;POST产生两个TCP数据包。
对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);
而对于POST,浏览器先发送header,服务器响应100 continue;浏览器再发送data,服务器响应200 ok(返回数据)。
15、既然get请求只产生一个数据包,那是否可以认为get比post的效率更高,从而用GET替换POST来优化网站性能?
不可以。
a. GET与POST都有自己的语义,不能随便混用。
b. 据研究,在网络环境好的情况下,发一次包的时间和发两次包的时间差别基本可以无视。而在网络环境差的情况下,两次包的TCP在验证数据包完整性上,有非常大的优点。
c. 并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次。
16.https和http有何区别?
HTTPS协议可以理解为HTTP协议的升级,就是在HTTP的基础上增加了数据加密。在数据进行传输之前,对数据进行加密,然后再发送到服务器。这样,就算数据被第三者所截获,但是由于数据是加密的,所以你的个人信息让然是安全的。这就是HTTP和HTTPS的最大区别。
17、pc端开发和移动端开发有什么不同?
a、兼容性
pc端需要考虑浏览器兼容性,移动端主要考虑屏幕分辨率和不同系统的兼容性。
b.页面布局
PC端常用布局固定宽度980px居中,移动端屏幕的大小和分辨率不同,多用响应式布局,使用em(以父元素为基础)、rem(以根元素为基础)。
c.JS动画
移动端没有hover事件、增加了touch和touchSlide事件,需要处理键盘跳出与隐藏。考虑到性能,移动端使用的js库应尽量小。
d.开发调试
PC端用chrome后台调试,移动端大部分可以用chrome移动端模拟调试器,但有的功能还需要在手机上调试。
18、沙盒模式是什么?
简单说来,沙盒模式是一种安全功能。在沙盒模式下,Access 只对控件和字段属性中的安全且不含恶意代码的表达式求值。如果表达式不使用可能以某种方式损坏数据的函数或属性,则可认为它是安全的。例如,诸如 Kill 和 Shell 之类的函数可能被用来损坏计算机上的数据和文件,因此它们被视为不安全的。当 Access 以沙盒模式运行时,调用这些函数的表达式将会产生错误消息。
在项目中,用于执行和解析不可信的js的时候,要隔离执行代码的执行环境的时候,执行代码的可访问对象要进行限制的时候,沙箱就可派上用场了。
https://blog.csdn.net/qq_20438233/article/details/44903315
二、css部分(包括布局以及新的css3)
1、纯css实现元素水平垂直居中的方法有哪些?说得越多越好
(1)position:absolute方法配合margin进行定位,用于已知元素宽高的情况。设置元素距离它的上左初始坐标点50%,然后让margin-left、margin-top分别为 自身宽高的1/2的负值.
div.box{
weight:200px;
height:400px;
position:absolute;
left:50%;
top:50%;
margin-left:-100px;
margin-top:-200px;
}
(2)position定位+margin:auto,可用于已知或者未知宽度的情况。
div.box{
position:absolute;
left:0;
right:0;
top:0;
bottom:0;
margin:auto;
}
(3)position:absolute方法配合css3的transform属性进行定位,可用于已知或者未知宽度的情况。
div.box{
weight:200px;
height:400px;
position:absolute;
left:50%;
top:50%;
transform:translate(-50%,-50%);
}
(4)父元素使用text-align:center,子元素使用display:inline-block。
<div class="A">
<div class="B"></div>
</div>
.A{
text-align:center
}
.B{
display:inline-block;
}
(5)使用css3的flex布局:
<div class="box">
<div class="content">
</div>
</div>
.box {
background-color: #FF8C00;
width: 300px;
height: 300px;
display: flex;
justify-content: center;
align-items: center;
}
.content {
background-color: #F00;
width: 100px;
height: 100px;
}
(6)使用table-cell布局:
<div class="box">
<div class="content">
<div class="inner">
</div>
</div>
</div>
.box {
background-color: #FF8C00;//橘黄色
width: 300px;
height: 300px;
display: table;
}
.content {
background-color: #F00;//红色
display: table-cell;
vertical-align: middle;//使子元素垂直居中
text-align: center;//使子元素水平居中
}
.inner {
background-color: #000;//黑色
display: inline-block;
width: 20%;
height: 20%;
}
2、 左边固定,右边自适应
https://segmentfault.com/a/1190000010698609
3.如何用css绘制三角形?
使用border-color来解决
.d3{
margin-left: 10px;
float: left;
width: 0;
height: 0;
border-width: 100px;
border-style: solid;
border-color:#FFCCCC transparent transparent transparent;
}
/**html*/
<div class="d3"></div>
4、假如我们要实现长宽比例为 2:1 ,移动设备屏幕宽度多种多样,如何用CSS制作自适应的等比例且与屏幕等宽的长方体?
方案一:CSS3 vm单位#####
vw:viewport的宽度,1vw 等于viewport宽度的 1%。
<div class="banner-box"></div>```
.banner-box{
width: 100%;
height:50vw;
}```
使用vw可以简洁地实现,但是此属性的浏览器兼容性不好。
方案二:使用padding撑开容器#####
在 CSS 盒模型中,margin, padding 的百分比数值是相对父元素的宽度计算的。由此只需将元素垂直方向的一个 padding 值设定为与 1/2 width 相同的百分比,同时设置height: 0
就可以实现目的。但是此方案设置 max-height
无效(max-height作用于元素的内容高度,stackoverflow有更详细的讨论)。
方案三:使用伪元素撑开容器#####
.banner-box{
width: 100%;
overflow: hidden; /*防止伪元素与容器在垂直方向上产生外边距折叠*/
}
.banner-box : after {
content: '';
display: block;
margin-top: 50%; /* margin 百分比相对父元素宽度计算 */
} ```
三、html(包含css5部分)
四、webpack
1. webpack与grunt、gulp的不同?
三者都是前端构建工具,grunt和gulp在早期比较流行,现在webpack相对来说比较主流,不过一些轻量化的任务还是会用gulp来处理,比如单独打包CSS文件等。
grunt和gulp是基于任务和流(Task、Stream)的。类似jQuery,找到一个(或一类)文件,对其做一系列链式操作,更新流上的数据, 整条链式操作构成了一个任务,多个任务就构成了整个web的构建流程。
webpack是基于入口的。webpack会自动地递归解析入口所需要加载的所有资源文件,然后用不同的Loader来处理不同的文件,用Plugin来扩展webpack功能。
所以总结一下:
- 从构建思路来说
gulp和grunt需要开发者将整个前端构建过程拆分成多个`Task`,并合理控制所有`Task`的调用关系 webpack需要开发者找到入口,并需要清楚对于不同的资源应该使用什么Loader做何种解析和加工
- 对于知识背景来说
gulp更像后端开发者的思路,需要对于整个流程了如指掌 webpack更倾向于前端开发者的思路
2. 与webpack类似的工具还有哪些?谈谈你为什么最终选择(或放弃)使用webpack?
同样是基于入口的打包工具还有以下几个主流的:
- webpack
- rollup
- parcel
从应用场景上来看:
- webpack适用于大型复杂的前端站点构建
- rollup适用于基础库的打包,如vue、react
- parcel适用于简单的实验性项目,他可以满足低门槛的快速看到效果
由于parcel在打包过程中给出的调试信息十分有限,所以一旦打包出错难以调试,所以不建议复杂的项目使用parcel
3.有哪些常见的Loader?他们是解决什么问题的?
- file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件
- url-loader:和 file-loader 类似,但是能在文件很小的情况下以 base64 的方式把文件内容注入到代码中去
- source-map-loader:加载额外的 Source Map 文件,以方便断点调试
- image-loader:加载并且压缩图片文件
- babel-loader:把 ES6 转换成 ES5
- css-loader:加载 CSS,支持模块化、压缩、文件导入等特性
- style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS。
- eslint-loader:通过 ESLint 检查 JavaScript 代码
4.有哪些常见的Plugin?他们是解决什么问题的?
- define-plugin:定义环境变量
- commons-chunk-plugin:提取公共代码
- uglifyjs-webpack-plugin:通过UglifyES压缩ES6代码
5.Loader和Plugin的不同?
不同的作用
- Loader直译为"加载器"。Webpack将一切文件视为模块,但是webpack原生是只能解析js文件,如果想将其他文件也打包的话,就会用到loader。 所以Loader的作用是让webpack拥有了加载和解析非JavaScript文件的能力。
- Plugin直译为"插件"。Plugin可以扩展webpack的功能,让webpack具有更多的灵活性。 在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
不同的用法
- Loader在module.rules中配置,也就是说他作为模块的解析规则而存在。 类型为数组,每一项都是一个Object,里面描述了对于什么类型的文件(test),使用什么加载(loader)和使用的参数(options)
- Plugin在plugins中单独配置。 类型为数组,每一项是一个plugin的实例,参数都通过构造函数传入。
6.webpack的构建流程是什么?从读取配置到输出文件这个过程尽量说全
Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:
- 初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;
- 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译;
- 确定入口:根据配置中的 entry 找出所有的入口文件;
- 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;
- 完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;
- 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
- 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。
在以上过程中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果。
7.是否写过Loader和Plugin?描述一下编写loader或plugin的思路?
Loader像一个"翻译官"把读到的源文件内容转义成新的文件内容,并且每个Loader通过链式操作,将源文件一步步翻译成想要的样子。
编写Loader时要遵循单一原则,每个Loader只做一种"转义"工作。 每个Loader的拿到的是源文件内容(source),可以通过返回值的方式将处理后的内容输出,也可以调用this.callback()方法,将内容返回给webpack。 还可以通过 this.async()生成一个callback函数,再用这个callback将处理后的内容输出出去。 此外webpack还为开发者准备了开发loader的工具函数集——loader-utils。
相对于Loader而言,Plugin的编写就灵活了许多。 webpack在运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
8.webpack的热更新是如何做到的?说明其原理?
webpack的热更新又称热替换(Hot Module Replacement),缩写为HMR。 这个机制可以做到不用刷新浏览器而将新变更的模块替换掉旧的模块。
原理:
首先要知道server端和client端都做了处理工作
- 第一步,在 webpack 的 watch 模式下,文件系统中某一个文件发生修改,webpack 监听到文件变化,根据配置文件对模块重新编译打包,并将打包后的代码通过简单的 JavaScript 对象保存在内存中。
- 第二步是 webpack-dev-server 和 webpack 之间的接口交互,而在这一步,主要是 dev-server 的中间件 webpack-dev-middleware 和 webpack 之间的交互,webpack-dev-middleware 调用 webpack 暴露的 API对代码变化进行监控,并且告诉 webpack,将代码打包到内存中。
- 第三步是 webpack-dev-server 对文件变化的一个监控,这一步不同于第一步,并不是监控代码变化重新打包。当我们在配置文件中配置了devServer.watchContentBase 为 true 的时候,Server 会监听这些配置文件夹中静态文件的变化,变化后会通知浏览器端对应用进行 live reload。注意,这儿是浏览器刷新,和 HMR 是两个概念。
- 第四步也是 webpack-dev-server 代码的工作,该步骤主要是通过 sockjs(webpack-dev-server 的依赖)在浏览器端和服务端之间建立一个 websocket 长连接,将 webpack 编译打包的各个阶段的状态信息告知浏览器端,同时也包括第三步中 Server 监听静态文件变化的信息。浏览器端根据这些 socket 消息进行不同的操作。当然服务端传递的最主要信息还是新模块的 hash 值,后面的步骤根据这一 hash 值来进行模块热替换。
- webpack-dev-server/client 端并不能够请求更新的代码,也不会执行热更模块操作,而把这些工作又交回给了 webpack,webpack/hot/dev-server 的工作就是根据 webpack-dev-server/client 传给它的信息以及 dev-server 的配置决定是刷新浏览器呢还是进行模块热更新。当然如果仅仅是刷新浏览器,也就没有后面那些步骤了。
- HotModuleReplacement.runtime 是客户端 HMR 的中枢,它接收到上一步传递给他的新模块的 hash 值,它通过 JsonpMainTemplate.runtime 向 server 端发送 Ajax 请求,服务端返回一个 json,该 json 包含了所有要更新的模块的 hash 值,获取到更新列表后,该模块再次通过 jsonp 请求,获取到最新的模块代码。这就是上图中 7、8、9 步骤。
- 而第 10 步是决定 HMR 成功与否的关键步骤,在该步骤中,HotModulePlugin 将会对新旧模块进行对比,决定是否更新模块,在决定更新模块后,检查模块之间的依赖关系,更新模块的同时更新模块间的依赖引用。
- 最后一步,当 HMR 失败后,回退到 live reload 操作,也就是进行浏览器刷新来获取最新打包代码。
9.如何利用webpack来优化前端性能?(提高性能和体验)
用webpack优化前端性能是指优化webpack的输出结果,让打包的最终结果在浏览器运行快速高效。
- 压缩代码。删除多余的代码、注释、简化代码的写法等等方式。可以利用webpack的UglifyJsPlugin和ParallelUglifyPlugin来压缩JS文件, 利用cssnano(css-loader?minimize)来压缩css
- 利用CDN加速。在构建过程中,将引用的静态资源路径修改为CDN上对应的路径。可以利用webpack对于output参数和各loader的publicPath参数来修改资源路径
- 删除死代码(Tree Shaking)。将代码中永远不会走到的片段删除掉。可以通过在启动webpack时追加参数--optimize-minimize来实现
- 提取公共代码。
10.如何提高webpack的构建速度?
- 多入口情况下,使用CommonsChunkPlugin来提取公共代码
- 通过externals配置来提取常用库
- 利用DllPlugin和DllReferencePlugin预编译资源模块 通过DllPlugin来对那些我们引用但是绝对不会修改的npm包来进行预编译,再通过DllReferencePlugin将预编译的模块加载进来。
- 使用Happypack 实现多线程加速编译
- 使用webpack-uglify-parallel来提升uglifyPlugin的压缩速度。 原理上webpack-uglify-parallel采用了多核并行压缩来提升压缩速度
- 使用Tree-shaking和Scope Hoisting来剔除多余代码
11.怎么配置单页应用?怎么配置多页应用?
单页应用可以理解为webpack的标准模式,直接在entry中指定单页应用的入口即可,这里不再赘述
多页应用的话,可以使用webpack的 AutoWebPlugin来完成简单自动化的构建,但是前提是项目的目录结构必须遵守他预设的规范。 多页应用中要注意的是:
- 每个页面都有公共的代码,可以将这些代码抽离出来,避免重复的加载。比如,每个页面都引用了同一套css样式表
- 随着业务的不断扩展,页面可能会不断的追加,所以一定要让入口的配置足够灵活,避免每次添加新页面还需要修改构建配置
12.npm打包时需要注意哪些?如何利用webpack来更好的构建?
Npm是目前最大的 JavaScript 模块仓库,里面有来自全世界开发者上传的可复用模块。你可能只是JS模块的使用者,但是有些情况你也会去选择上传自己开发的模块。 关于NPM模块上传的方法可以去官网上进行学习,这里只讲解如何利用webpack来构建。
NPM模块需要注意以下问题:
- 要支持CommonJS模块化规范,所以要求打包后的最后结果也遵守该规则。
- Npm模块使用者的环境是不确定的,很有可能并不支持ES6,所以打包的最后结果应该是采用ES5编写的。并且如果ES5是经过转换的,请最好连同SourceMap一同上传。
- Npm包大小应该是尽量小(有些仓库会限制包大小)
- 发布的模块不能将依赖的模块也一同打包,应该让用户选择性的去自行安装。这样可以避免模块应用者再次打包时出现底层模块被重复打包的情况。
- UI组件类的模块应该将依赖的其它资源文件,例如.css文件也需要包含在发布的模块里。
基于以上需要注意的问题,我们可以对于webpack配置做以下扩展和优化:
- CommonJS模块化规范的解决方案: 设置output.libraryTarget='commonjs2'使输出的代码符合CommonJS2 模块化规范,以供给其它模块导入使用
- 输出ES5代码的解决方案:使用babel-loader把 ES6 代码转换成 ES5 的代码。再通过开启devtool: 'source-map'输出SourceMap以发布调试。
- Npm包大小尽量小的解决方案:Babel 在把 ES6 代码转换成 ES5 代码时会注入一些辅助函数,最终导致每个输出的文件中都包含这段辅助函数的代码,造成了代码的冗余。解决方法是修改.babelrc文件,为其加入transform-runtime插件
- 不能将依赖模块打包到NPM模块中的解决方案:使用externals配置项来告诉webpack哪些模块不需要打包。
- 对于依赖的资源文件打包的解决方案:通过css-loader和extract-text-webpack-plugin来实现,配置如下:
13.如何在vue项目中实现按需加载?
Vue UI组件库的按需加载 为了快速开发前端项目,经常会引入现成的UI组件库如ElementUI、iView等,但是他们的体积和他们所提供的功能一样,是很庞大的。 而通常情况下,我们仅仅需要少量的几个组件就足够了,但是我们却将庞大的组件库打包到我们的源码中,造成了不必要的开销。
不过很多组件库已经提供了现成的解决方案,如Element出品的babel-plugin-component和AntDesign出品的babel-plugin-import 安装以上插件后,在.babelrc配置中或babel-loader的参数中进行设置,即可实现组件按需加载了。
单页应用的按需加载 现在很多前端项目都是通过单页应用的方式开发的,但是随着业务的不断扩展,会面临一个严峻的问题——首次加载的代码量会越来越多,影响用户的体验。
通过import(*)语句来控制加载时机,webpack内置了对于import(*)的解析,会将import(*)中引入的模块作为一个新的入口在生成一个chunk。 当代码执行到import(*)语句时,会去加载Chunk对应生成的文件。import()会返回一个Promise对象,所以为了让浏览器支持,需要事先注入Promise polyfill
五、vue
1.为什么vue不能检测到数组的变动?解决方法是什么?
Vue检测数据的变动是通过Object.defineProperty实现的,所以无法监听数组的添加操作是可以理解的,因为是在构造函数中就已经为所有属性做了这个检测绑定操作。
可以使用vue的set方法或者js内置的splice方法来修改数组元素或者添加。
利用concat方法来修改数组的长度,原理是新建一个length为某长度的数组,和原数组合并。
2.vue的双向绑定原理是什么?
vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()
来劫持各个属性的setter
,getter
,在数据变动时发布消息给订阅者,触发相应的监听回调。
3、vue的nextick为什么会出现?它的使用场景是什么?
Vue 在修改数据后,视图不会立刻更新,而是等同一事件循环中的所有数据变化完成之后,再统一进行视图更新。在 created 和 mounted 阶段,如果需要操作渲染后的试图,也要使用 nextTick 方法。
应用场景例如:
a、点击按钮显示原本以 v-show = false 隐藏起来的输入框,并获取焦点。
b、点击获取元素宽度。
4、插槽是什么,作用域插槽又是什么?
插槽就是Vue实现的一套内容分发的API,将<slot></slot>元素作为承载分发内容的出口。
这句话的意思就是,没有插槽的情况下在组件标签内些一些内容是不起任何作用的,当我在组件中声明了slot元素后,在组件元素内写的内容就会出现在插槽之下。slot属性对应的内容都会和组件中name一一对应。而没有名字的,就是默认插槽!!
在template元素上添加属性slot-scope,则为作用域插槽,即我可以把组件上的属性/值,在组件元素上使用!!
https://www.cnblogs.com/chinabin1993/p/9115396.html
使用场景:
a、由于作用域插槽可以传递数据。子组件中的一些数据想在父组件中使用,或者父组件的数据想在子组件中使用的时候,可以考虑插槽。
5、vue的data为什么会是一个函数,而不是一个变量?
是为了如果两个实例引用同一个对象,当其中一个实例的属性发生改变时,另一个实例属性也随之改变,只有当两个实例拥有自己的作用域时,才不会相互干扰。
6、vue的router的两种模式是什么?
7、什么是虚拟dom?
8、vue中的keep-alive有什么用?
https://www.cnblogs.com/sysuhanyf/p/7454530.html
六、node
1、为什么用Nodejs,它有哪些缺点?
- 事件驱动,通过闭包很容易实现客户端的生命活期。
- 不用担心多线程,锁,并行计算的问题
- V8引擎速度非常快
- 对于游戏来说,写一遍游戏逻辑代码,前端后端通用
当然Nodejs也有一些缺点:
- nodejs更新很快,可能会出现版本兼容
- nodejs还不算成熟,还没有大制作
- nodejs不像其他的服务器,对于不同的链接,不支持进程和线程操作
-
错误优先(Error-first)的回调函数(Error-First Callback)用于同时返回错误和数据。第一个参数返回错误,并且验证它是否出错;其他参数返回数据。
new Promise((resolve, reject) =>
{
setTimeout(() =>
{
resolve('result');
}, 100)
})
.then(console.log)
.catch(console.error);
以下方式避免回调地狱
- 模块化:将回调函数转换为独立的函数
- 使用流程控制库,例如[aync]
- 使用Promise
- 使用aync/await
-
Promise可以帮助我们更好地处理异步操作。下面的实例中,100ms后会打印result字符串。catch用于错误处理。多个Promise可以链接起来。
new Promise((resolve, reject) => { setTimeout(() => { resolve('result'); }, 100) }) .then(console.log) .catch(console.error);
5、用什么工具保证一致的代码风格?为什么要这样?
- 团队协作时,保证一致的代码风格是非常重要的,这样团队成员才可以更快地修改代码,而不需要每次去适应新的风格。这些工具可以帮助我们:
- [ESLint] (http://eslint.org/)
- [Standard] (https://standardjs.com/)
- JSLint
- JSHint
- ESLint
- JSCS推荐
-
stub用于模块的行为。测试时,stub可以为函数调用返回模拟的结果。比如说,我们写文件时,实际上并不需要真正去写
6、什么是stub?举例说明
-
stub用于模块的行为。测试时,stub可以为函数调用返回模拟的结果。比如说,我们写文件时,实际上并不需要真正去写
var fs = require('fs'); var writeFileStub = sinon.stub(fs, 'writeFile', function(path, data, cb) { return cb(null); }); expect(writeFileStub).to.be.called; writeFileStub.restore();
- stub是用于模拟一个组件或模块的函数或程序。在测试用例中,简单的说,你可以用stub去模拟一个方法,从而避免调用真实的方法,使用stub你还可以返回虚构的结果。你可以配合断言使用stub。
-
举个例子,在一个读取文件的场景中,当你不想读取一个真正的文件时:
-
var fs = require('fs'); var readFileStub = sinon.stub(fs, 'readFile', function (path, cb) { return cb(null, 'filecontent'); }); expect(readFileStub).to.be.called; readFileStub.restore();
在单元测试中:Stub是完全模拟一个外部依赖,而Mock常用来判断测试通过还是失败
7、运算错误与程序员错误的区别
运算错误并不是bug,这是和系统相关的问题,例如请求超时或者硬件故障。而程序员错误就是所谓的bug
8、使用NPM有哪些好处?
通过NPM,你可以安装和管理项目的依赖,并且能够指明依赖项的具体版本号。对于Node应用开发而言,你可以通过package.json
文件来管理项目信息,配置脚本,以及指明依赖的具体版本
七、算法
1、数组扁平化
let arr=[1,[1,2,[7,8]]];
let newArr=new Array();
function flat(flatArr){
flatArr.forEach((item)=>{
if(Array.isArray(item)){
flat(item);
}else{
newArr.push(item);
}
})
}
console.log(this.flat(arr));
2、数组去重
let arr=[1,2,5,4,9,7,2,5,8,3,1];
function toHeavy(arr){
let obj={};
let newArr=arr.fiter((item)=>{
if(!obj.hasOwnProperty(item)){
obj[item]=1;
}
return obj.hasOwnProperty(item)==flase;
})
return newArr;
}
let newArr=toHeavy(arr);
console.log(nwwArr);
3、验证数学运算表达式是否合法
https://blog.csdn.net/notejs/article/details/20608371
4、举一个函数柯里化的例子
function curry(fn){
let args=Array.prototype.slice.call(arguments,1);
return function(){
let argsT=Array.prototype.slice.call(arguments)
let finalArgs=args.contact(argsT);
return fn.apply(null,finalAerags);
}
}
function isAdd(num1,num2){
reruen num1+num2;
}
let outCurry=curry(isAdd,2);
console.log(this.outCurry(4));//output 6
5.函数的深复制和浅复制
//封装函数 实现深浅拷贝 deep为true深拷贝 false浅拷贝
function copy(oldObj,deep){
let newObj = {};
if (oldObj instanceof Array){
newObj = [];
}
for (let key in oldObj){
let value = oldObj[key];
if (!!deep && typeof value === "object" && value !== null){ //如果原对象的某个属性是引用类型数据,递归调用copy
newObj[key] = copy(value,deep);
} else{ //如果原对象的某个属性是基本类型数据,直接将此属性赋值给新对象的相应属性
newObj[key] = value;
}
}
return newObj;
}
6、实现一个节流函数
function throttle(func, delay) {
let timer
return function (...args) {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
func.apply(this, args)
}, delay)
}
}
var func=()=>{
console.log("hello,world!");
};
//验证
throttle(func,1000);
throttle(func,2000);
7、实现一个批量请求函数
/*第二题*/
function multiResquest(urls, maxNum, callback) {
let pending_count = 0, //当前并发数
idx = 0;//当前请求的位置
while (pending_count < maxNum) {
_fetch(urls[idx++])
}
async function _fetch(url) {
if (!url) return;
pending_count++;
console.log(url + ':start','并发数: '+pending_count);
await fetch(url);//等待请求完成
pending_count--; //请求完成后当前并发数减1
console.log(url + ':done','并发数: '+pending_count);
_fetch(urls[idx++]); //执行下一个请求
pending_count || callback && callback()//全部请求完成后执行回调函数
}
}
//验证
let urls = Array.from({length: 10}, (v, k) => k);
let fetch = function (idx) {
return new Promise(resolve => {
let timeout = parseInt(Math.random() * 1e4);
setTimeout(() => {
resolve(idx)
}, timeout)
})
};
let maxNum = 4;
let callback = () => {
console.log('run callback');
};
//执行
multiResquest(urls, maxNum, callback)
8、冒泡排序,选择排序,快速排序的世间复杂度各是多少?
https://blog.csdn.net/u011110301/article/details/106326141/
9、js实现排列
function arrange(str1,str2){
if(typeof str1==null&&typeof str1==undefined)
return;
if(str1=='')
console.log(str2);
for(var i=0;i<str1.length;i++){
arrange(str1.substring(1),str2+str1.charAt(i));
}
}
console.log(arrange('1234',''))
10、线性数据转化为树。
function changeToTree(data_list,parent_index){
let tree=[];
data_list.forEach(item => {
if(item.parent_index==parent_index){
let obj=item;
let temp=changeToTree(data_list,obj.index);
if(temp.length>0)
obj.children=temp;
tree.push(obj);
}
});
return tree;
}
let data=[
{
index:1,
item_name:"1",
parent_index:2
},
{
index:2,
item_name:"1",
parent_index:3
},
{
index:3,
item_name:"1",
parent_index:0
}
,{
index:4,
item_name:"1",
parent_index:3
},
{
index:5,
item_name:"1",
parent_index:2
},
{
index:6,
item_name:"1",
parent_index:4
}
]
console.log(changeToTree(data,0))