笔试面试整理
作者:©Mrlin(史密斯林)
简介:学习记录,笔试面试过程中遇到的问题及整理汇总。
题1
1、编程:①数字转格式,前面加上,三位拆分添加一个”,”,小数点后保留两位,不需要考虑四舍五入,例如1234578.7889,输出,三位拆分添加一个”,”,小数点后保留两位,不需要考虑四舍五入,例如1234578.7889,输出1,234,578.78
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 function transferNum (num){
var arr = num.toString().split('.');
// var result = arr[0].toString().replace(/(?=(\d{3})+$)/g,',');
var dept = 3;
var num = arr[0];
var result = '';
while(num.length > dept){
result = ','+num.slice(-dept)+result;
num = num.slice(0,num.length - dept);
}
if(num) {
result = num + result;
}
return result;
}
console.log(transferNum(12345678.956))
题2
2、实现fibonacci数列,并且实现数组缓存。题目分析,主要关键点在于实现数组缓存,及将fibonacci的每一项都保存下来。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 //基本fibonacci数列定义
function fibonacci(n){
if(n==0||n==1){
return n;
}else{
return fibonacci(n-1)+fibonacci(n-2);
}
}
let fibonacci = function() {
let temp = [0, 1];
return function(n) {
let result = temp[n];
if(typeof result != 'number') {
result = fibonacci(n - 1) + fibonacci(n - 2);
temp[n] = result; // 将每次 fibonacci(n) 的值都缓存下来
}
return result;
}
}(); // 外层立即执行
// console.log(fibonacci(4));
console.log(fibonacci(5));
var temp = [0,1];
var fibonacci= function(){
return function(n){
var result = temp[n];
if(typeof result != 'number'){
result = fibonacci(n-1) + fibonacci(n-2);
temp[n] = result;
}
return result;
}
}();
console.log(fibonacci(5));
console.log(temp);
题3
3、表单提交的两种方法及其优缺点
1
2 为get时,输入的数据会附在URL之后,客户端发送给服务器。优点:速度快。缺点:数据长度有限。默认情况(method未指定)为该值。
post表单数据与URL是分开发送。用户端在通知服务器来取数据。优点:数据长度无限制。缺点:响应时间
题4
4、匹配括号,若一个字符串中只有{},(),{}等出现时,配置正确的输出。如{()})),[()]{},{[()]}等。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 // 解题思路,使用堆栈,当数据为'('、'{'、'['时,入栈,当数据为'}'、']'、')'时,判断当前节点与即将出栈的数据是否匹配,匹配则出栈,
// 否则返回false,当字符串长度遍历完成,判断当前栈的长度。若为0则证明括号是一一匹配的,若不为0则不匹配。
/**
* @param {string} s
* @return {boolean}
*/
var isValid = function(s) {
var example = {
')':'(',
']':'[',
'}':'{'
}
var stack = [];
for(var i=0;i < s.length; i++){
var temp = s.charAt(i);
if(temp in example){
var res = stack.length != 0?stack.pop():'';
if(res != example[temp]){
return false;
}
}else{
stack.push(temp);
}
}
return stack.length == 0;
};
题5
5、简述一下http,并且说一下如何提高浏览器加载速度。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 超文本传输协议HTTP规定了浏览器与服务器之间的请求和响应的格式与规则,它是万维网上能够可靠地交换文件的重要基础。
HTTP的操作过程
浏览器分析指向页面的URL
浏览器向DNS系统请求解析域名所对应的服务器IP地址
DNS系统解析出服务器的IP,并返回给主机
浏览器与该服务器的进程建立TCP链接(三次握手,端口默认为80)
浏览器发出HTTP请求:如GET /article/index.html
服务器收到请求并作出相应处理,把文件index.html发送给浏览器
释放TCP链接(四次握手)
浏览器解析index.html文件,将web页显示出来。
HTTP协议的特点
HTTP协议是无状态的,即多次访问一个服务器上的页面,服务器并不知道你曾经访问过,每次访问的响应都当做第一次访问一样。所以,在实际应用中,通常使用CooKie加数据库的方式记录和跟踪用户的活动。
HTTP有非持久连接和持久连接:
采用非持久连接时,网页的每个元素对象(如.png,jpeg图等)的传输都需单独建立一个TCP连接(第三次握手可携带请求信息)
采用持久连接时,仅需建立一次TCP连接,服务器发送响应后仍保持连接,客户和服务器可以继续在这条连接上发送请求和响应报文。
Cookie以及其作用
CooKie是由服务器生成,但存储在用户主机上的文本文件,它保存了服务器和客户之间传递的状态信息,作为识别用户的手段。通过Cookie服务器就能从数据库中查询该用户的活动记录,进而可以执行一些个性化操作
题6
HTTP请求报文中常见的几个方法
1
2
3
4
5
6
7
8
9
10 方法 意义
GET 请求读取由URL所标志的信息
HEAD 请求读取由URL所标志的信息的首部
POST 给服务器添加信息
CONNECT 用于代理服务器
get和post方法的区别:
一般我们在浏览器输入一个网址访问网站都是GET请求;在FORM表单中,可以通过设置Method指定提交方式为GET或POST,默认时为GET提交方式。
get请求一般不会修改服务器的信息,仅用于请求页面;post请求可能会修改服务器中的资源信息,如提交评论、博客等都是通过post请求实现。
get请求的信息附加在URL后面,这些被显示的暴露在外面。post请求的数据放在包体中,不容易暴露,因此一般用户登录等保密性高的不宜采用get请求,而用post请求。
题7
提高浏览器加载速度
1
2
3
4
5
6 1、减少页面请求
2、优化图片
3、使用免费的cdn加载第三方资源
4、合并压缩css js
5、代码优化,去除冗余代码
6、http1.0 和http2.0的区别
题8
HTTP2.0和HTTP1.X相比的新特性
1
2
3
4
5
6
7 新的二进制格式(Binary Format),HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。
多路复用(MultiPlexing),即连接共享,即每一个request都是是用作连接共享机制的。一个request对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的 id将request再归属到各自不同的服务端请求里面。
header压缩,如上文中所言,对前面提到过HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。
服务端推送(server push),同SPDY一样,HTTP2.0也具有server push功能。
题9
实现add(1) = 1,add(1)(2) = 3,add(1)(2)(3) = 6.
1
2
3
4
5
6
7
8
9
10
11 var add = function(m){
function sum(n){
m += n;
return sum;
}
sum.toString =function(){
return m;
}
return sum;
};
题10
实现bind函数
bind() 方法会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,
之后的一序列参数将会在传递的实参前传入作为它的参数。(来自于 MDN )
1
2
3
4
5
6
7
8
9
10
11
if(!Function.prototype.bind){
Function.prototype.bind = function(){
var self = this;
var context = [].shift.call(arguments);
var arg = [].slice.call(arguments);
return function(){
self.apply(context,[].concact.call(arg,[].slice.call(arguments)));
}
}
}
题11
原型链定义
1 在javascript中每一个对象都一个指向他的原型(prototype)对象的内部链接。每个原型对象又有自己的原型,直到某个对象的原型为null位置,组成这条链的最后一环。
题12
继承就是把父函数的一个实例给子元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 // (1)
function Parent(){
this.name = '父函数';
this.arr = [1,2,3];
}
function Child(){
this.age = 18;
}
Child.prototype = new Parent();
var obj1 = new Child();
var obj2 = new Child();
obj1.name = 'hhh';
obj1.arr[1] = 'h';
console.log(obj2.name);
console.log(obj1.name);
console.log(obj1.arr);
console.log(obj2.arr);
来自原型对象的引用属性所有实例共享
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 // (2)借用构造函数
function Parent(){
this.name = '父函数';
this.arr = [1,2,3];
}
function Child(){
this.age = 18;
Parent.call(this);
}
var child1 = new Child();
var child2 = new Child();
child1.arr[1] = "aha";
console.log(child1.arr);
console.log(child2.arr);
借父类的构造函数,复制属性和方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 // (3)组合继承
function Parent(name,arr){
this.name = name;
this.arr = arr;
}
function Child(age,name,arr){
this.age = age;
Parent.call(this,name,arr);
}
Parent.prototype.run = function(){
return "我是父类的run方法";
}
Child.prototype = new Parent();
var obj1 = new Child("张三",[1,2,3]);
var obj2 = new Child("李四",[1,2,3,4]);
console.log(obj1.run());
题13
闭包
1
2
3
4
5
6
7
8
9
10
11
12
13 function fun(n,o){
console.log(o);
return {
fun:function(m){
return fun(m,n);
}
}
}
var a = fun(0); a.fun(1);a.fun(2);a.fun(3);//undefined 0 0 0
var b = fun(0).fun(1).fun(2).fun(3);//undefined 0 1 2
var c = fun(0).fun(1); c.fun(2);c.fun(3);//undefined 0 1 1
题14
判断一个对象是否为数组类型的方法
1
2
3
4
5
6 var arr = new Array();
function isArray(arr){
// return Array.prototype.isPrototypeOf(arr);
return typeof arr == 'object' && arr.constructor == Array;
}
console.log(isArray(arr));
题15
移动端适配方案有哪些(重点)
1 1、媒体查询
题16
vue实现数据绑定的原理。
1
2
3
4
5
6
7 defineProperty get set
vue实现双向绑定主要是通过:
1、数据挟持结合发布者订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的getter,setter.在数据变动时发布消息给订阅者,触发相应的监听回调。
2、把一个普通的javascript对象传给Vue实例来作为他的data选项时,vue将遍历它的全部属性,用Object.defineProperty将他们转化成getter和setter.
3、vue数据的双向绑定将MVVM作为数据绑定的入口,整合Observer,Compile和Watcher三者。
通过Observer来监听自己model的数据变化,通过compile来解析编译模板指令(view);最终通过Watcher搭起Observer和Compile之间的通信桥梁。
达到数据变化更新视图。视图交互变化更新数据。 从而完成整个双向绑定的过程。
题17
浏览器输入一个网址到页面加载完成是一个什么过程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 1)首先在网页输入URL
2)进行缓存解析(依次去查看浏览器缓存->系统缓存->路由器缓存),若从缓存中能获取全部内容,则不再继续进行。若无法取得,则进行第三步。
3)进行域名解析(即DNS解析),该操作实现从域名到IP地址的转换。
4)TCP连接,进行三次握手。
4.1客户端先服务端发送请求报文,syn = 1,seq= x
4.2服务端接收客户端发送的连接请求之后回复ack报文,并为此次连接分配资源
4.3客户端接收到ack报文后也向服务器端发送ack报文,并分配资源。
连接成功,浏览器向服务器发送http请求,请求数据包。
5)服务器响应http请求。
6)浏览器解析html代码,并请求html代码中的资源(如js,css图片等)
6.1从上到下,先解析head标签中的代码
6.2先下载head标签中引用的外部文件。
6.3当遇到script标签时,暂停解析,将控制权交给javaScript引擎。如果script标签引用了外部脚本,就下载该脚本,否则直接执行,执行完毕将控制权交给浏览器渲染引擎。
6.4如果遇到link标签引入的css文件,下载改文件,同时往下解析。
6.5当head中解析完毕,开始解析body中的代码。如果外部文件还是没有下载结束,将继续下载。若此时重新与到script标签,同样会将控制权交给javascripy引擎。解析完毕后将控制权交还给浏览器引擎。
6.6当body中的代码解析完毕,且css样式也加载完毕,css会重新渲染整个页面。
6.7按照之前的描述,script标签放在body内尾部比较合适
6.8同时,如果js脚本中采取window.onload或者$(document).ready或$(function(){})时,相当于将script标签放置在文件的最后。
7)断开TCP连接
四次挥手:
7.1第一次挥手客户端发送一个fin,用来关闭client到server的数据传送,client进入到fin_wait_1状态。
7.2server收到fin后,发送一个ack给Client,确认收到客户端的请求,server进入到close_wait状态。
7.3server发送一个fin,用来关闭server到client的数据传送,server进入到last_lock状态。
7.4client收到fin后,client进入到time_wait状态,紧接着发送一个ack给server,确认收到请求。此时server进入close状态。
8)浏览器对页面进行渲染并展现给用户
8.1浏览器从磁盘或者网络读取html的原始字节,并根据文件的指定编码将他们转换成各个字符串。
8.2浏览器根据W3c HTML5的语法规则,解析html,body等标签。
8.3根据词法将标签转换成其规则定义的对象。
8.4最后根据层级关系,创建dom结构,此时DOM树构建完成。
8.5于此同时在解析html是如果遇到css样式文件,构建完成dom后,则会创建CSSOM(css 对象模型),此过程与构建DOM树基本·一致。
8.6此时的DOM树和CSSOM树是是彼此完全独立的对象,此时需要将CSSOM和DOM树合并成渲染树。
8.7布局计算每个对象的位置以及大小。
8.8绘制,将渲染树绘制到屏幕上。
如果dom树或者cssom树被修改,需要执行一遍上述所有步骤,重新渲染。
题18
15、左右固定宽度,中间自适应。
题19
16、一个大小大概为10000的数组,随机打乱,时间复杂度和空间复杂度是多少
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 function shuffle(arr){
let i = arr.length;
while(i){
let j = Math.floor(Math.random()*i--);
[arr[j],arr[i]] = [arr[i],arr[j]];
}
return arr;
}
function shuffle2(arr){
for(let i=0,len = arr.length;i<len;i++){
let temp = parseInt(Math.random()*(len-1));
let current = arr[i];
arr[i] = arr[temp];
arr[temp] = current;
}
return arr;
}
题20
一个大小固定为10000的数组,将奇数放在前面,偶数放在后面,并且排序。空间复杂度和时间复杂度是多少。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 function resort(arr){
if(arr instanceof Array){
arr.sort(function(a,b){
if(a%2 === 0){
if(b%2 === 0){
return a-b;
}
return 1;
}else{
if(b%2 !== 0){
return a-b;
}
return -1;
}
})
}
}
题21
横屏的实现。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 // 移动端横屏,在html页面的head中
<meta name="viewport" content="width=divece-width, user-scalable=no,initial-scale=1">
设置屏幕宽度为设备宽度,禁止用户手动调整缩放,页面初始缩放程度为1.
1、通过媒体查询横屏还是竖屏
@media screen and (orientation:portrait) {
// 竖屏
}
@media screen and (orientation:landscape) {
// 横屏
}
// 2、js判断横屏还是竖屏
window.addEventListener("orientationchange" in window?"orientationchange":"resize",function(){
if(window.orientation === 180 ||window.orientation ===0){
// 横屏状态
}else if(window.orientation === 90 || window.orientation === -90){
// 竖屏状态
}
})
题22
vue 中有一个数组arr;当更改arr[1] = 2时,页面是否会重新渲染。为什么?
1
2
3
4
5
6
7 如果这个数组属性一开始就已经在state里面定义的话,页面会重新渲染。但是如果这个属性为新增属性,则页面不会渲染。
这种情况可以有三种解决方案。
1、最好提前在store中初始化所有所需的参数。
2、当需要在对象上添加新属性时,可以使用
Vue.set(obj,'newProp',123);this.$set
3、以新对象替换老对象或者采用es6的对象展开运算符。
state.obj = {...state.obj,newProp:123}
题23
获取当前节点的兄弟结点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 // 1、采用jquery的形式
$("#id").siblings() //获取当前元素的所有兄弟结点
$("#id").prev() //当前元素的前一个结点
$("#id").prevAll() //当前元素之前的所有结点
$("#id").next() //当前元素的下一个结点
$("#id").nextAll() //当前元素之后的所有结点
// 2、采用原生js的形式
var s = document.getElementById("test");
clearText(s); //关键步骤,清除掉多余的文本结点
var childs = s.childNodes;//此时获取到的才是我们需要的标签结点
s.parentNode; //s的父节点
s.nextSibling; //s下一个兄弟结点
s.previousSibling; //s上一个兄弟结点
s.firstChild;//s的第一个子节点
s.lastChild; //s的最后一个子节点
题24
说出a=xx;b=xx;交互a,b的方法有哪些?
1
2
3
4
5
6
7
8 // 1、中间值交换
var temp =a;
a=b;
b = temp;
// 2、加减法
a = a+b;
b = a-b;
a = a-b;
题目25
为什么 vue 组件中 返回的数据 data{return{}};使用这种方式。
1
2 1、不使用return包裹的数据在全局可见,会造成变量污染。
2、使用return包裹后数据中的变量仅在当前可组件中可用,不会影响其他组件。
题目26
vue通过路由传值的方式有哪些,不同的方式有什么区别。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 // 1、实现router.push(),通过path带参数跳转。
this.$router.push({
path:`/describe/${id}`
});
// 路由配置
{
path:'/describe/:id',
name:'Describe',
component:Describe
}
// 子组件中可以通过,this.$route.params.id获取参数
// 2、通过name来匹配路由,通过params传递参数
this.$router.push({
name:'Describe',
params:{
id:id
}
})
// 子组件一样通过this.$route.params.id可以获取到参数。
// 3、使用path来匹配路由,并通过query来传递参数,query传递的参数会拼接在url后面?id=''
this.$router.push({
path:'describe',
query:{
id:id
}
})
// 子组件可以通过,this.$route.query.id可以获取参数。
题27
vue的生命周期。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 1、beforeCreate
组件的选项对象还没有创建,el和data并没有初始化,因此无法访问methods,data和computed等上的方法和数据。
2、create(创建后)
此时的data数据已经初始化成功,但是el尚未初始化。该方法无拦截过程,不适合在这个方法里发送请求,建议在组件路由钩子beforeRouterEnter中完成。
3、beforeMount(挂载前)
此时el和data均已初始化完成,编译已经完成生成html,但是数据还没挂载上去。
4、Mounted(已挂载)
挂载完成,也就是模板html数据渲染到html页面,此时一般可以做一些ajax操作,mounted只会执行一次。
5、beforeUpdate(更新前)
在数据更新之前调用,发生在虚拟dom重新渲染和打补丁之前,可以在该钩子中进一步的更改状态,不会触发附加的重渲染过程
6、updated(更新后)
组件dom已经更新完成,可以执行依赖于dom的操作。
7、beforeDestroy(销毁前)
实例销毁之前调用
8、destroyed(销毁后)
实例销毁后调用。
与路由有关的生命周期
route:{
//waitForData: true, // 数据加载完毕后再切换试图,也就是 点击之后先没反应,然后数据加载完,再出发过渡效果
canActivate:function(transition){
// canActivate阶段,可以做一些用户验证的事情(是否可以被激活)
// 在验证阶段,当一个组件将要被切入的时候被调用。
},
activate:function(transition){
// 在激活阶段被调用,在 activate 被断定( resolved ,指该函数返回的 promise 被 resolve )。
//用于加载和设置当前组件的数据。(激活)
//this.$root.$set('header',this.title);
transition.next();
//此方法结束后,api会调用afterActivate 方法
//在aftefActivate中 会给组件添加 $loadingRouteData 属性 并设置为true
},
data: function(transition) {
var _this = this;
// 在激活阶段被调用,在 activate 被断定( resolved ,指该函数返回的 promise 被 resolve )。用于加载和设置当前组件的数据
// 说明之前请求过 则不用再请求了
if(this.$root.myViewsData){
this.$data = this.$root.myViewsData;
transition.next();
console.log('已经请求过了不再请求数据');
return;
}
//将数据同步到根节点
this.$root.myViewsData = this.$data;
setTimeout(function(){
//这里 _this.$loadingRouteData 是 true
transition.next({msg:'加载后的数据'});
//在调用完transition.next 后,_this.$loadingRouteData 为 false
}.bind(this),4000);
},
canDeactivate:function(transition){
// 在验证阶段,当一个组件将要被切出的时候被调用。(是否可以被禁用)
},
deactivate: function (transition) {
// 在激活阶段,当一个组件将要被禁用和移除之时被调用。(禁用)
}
}
题28
子组件如何改变父组件的值。
1
2
3
4
5
6
7
8
9
10
11
12
13 // 父组件中引子组件.使用v-bind绑定要监听的数据,子组件通过props进行接受,然后定义子组件改变父组件定义的方法,并通过$emit发射出来。
// 然后父组件通过v-on 定义方法监听子组件要更改的数据,并进行改变。
// 父组件中:
<child v-bind:mydata="mydata" v-on:clifn="clifn"><child>
clifn(mydata){
this.mydata = mydata;
}
// 子组件中:
props:[mydata]
clifn(){
this.$emit(clifn,mydata);
}
题29
数组去重,ES6中set方法解析一下
1
2
3 function unSame(arr){
var set = new Set(arr);
}
题30
vue和jquery最大的区别是什么。
题31
去重
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 function unSame(arr){
var set = new Set(arr);
return set;
}
// console.log(unSame(arr));
function unSame2(arr){
var temp = {};
var brr = [];
arr.forEach(function(item,index){
temp[item]?temp[item]++:temp[item] = 1;
if(temp[item] == 1){
brr.push(item);
}
});
return brr;
}
console.log(unSame2(arr));
题31
讲一讲你知道的web前端攻击方式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 1、XSS:跨站脚本攻击。
恶意攻击者通过往web页面里插入恶意的Script代码,当用户浏览该页时,嵌入其中的Script代码会执行,从而达到恶意攻击的目的。
防御手法:
使用https手法,使用后台输入校验。
对用户提交的内容进行校验。
实现session标记。
2、CSRF:站点伪造请求
站点伪造请求通过访问用户被认为已经通过身份验证的web页面程序中包含恶意代码和链接来工作。如果该web应用程序的会话没有超时,攻击者可能会执行未授权的操作。
防御措施:
验证HTTP Referer字段
在请求中添加token并验证
在HTTP头部自定义属性并验证
正确使用post,get和cookie
在非get请求中增加伪随机数。
3、SQL注入
4、cookie劫持和session劫持
5、钓鱼攻击(重定向攻击)
题32
讲一讲跨域是怎么处理的,都有哪些方式
1
2
3
4
5
6
7
8
9
10 ajax基于安全的考虑只能访问本地的资源,而不能跨域访问。
1、代理。
2、jsonp.
创建一个script标签,并添加src属性,引入跨域访问的url.
Jsonp只支持get请求,不支持post请求。
3、XHR2
XMLHttpRequest level2
在服务器头部添加2句代码
header("Access-Control-Allow-Origin:*");
header("Acces-Control-Allow-Methods:Post,Get")
- jsonp有什么局限性?
题33
图片加载优化,各种格式的图片有什么区别。
1
2
3
4 1、使用base64编码代替图片
2、合并图片sprite
3、使用svg,css,canvas或iconfont代替图片。
4、图片压缩。
题34
各类手机操作系统兼容性的问题有没有遇到过,怎么解决的。
题35
你们的页面需要兼容ie吗,怎么做的处理。有哪些css属性需要注意。
题36
深拷贝和浅拷贝的区别,使用JSON.parse(JSON.stringify())有什么缺点?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 // 1、递归实现深拷贝:
function deepClone(obj){
let objClone = Array.isArray();
if(obj && typeof obj==="object"){
for(key in obj){
if(obj.hasOwnProperty(key)){
if(obj[key] && typeof obj[key] ==="object"){
objClone[key] = deepClone(obj[key]);
}else{
objClone[key] = obj[k];
}
}
}
}
return objClone;
}
// 2、借用JSON对象的parse和stringify()
JSON.parse(JSON.stringify(obj));
// function 不起作用,解决方法递归。。
// 深拷贝,指向的不是同一个内存地址。
// 浅拷贝,相当于指针,指向同一个内存地址。
题37
假如有一个a文件,有function a, b,c,d,其中,只有a函数是export default的,如何在一个b文件中引用a,b,c,d方法,如何导出。
1
2
3
4
5
6 export
可以:
import {b,c,d} from '';
export default
可以通过:
import a from '';
题38
vue如何配置生产环境和开发环境,其和webpack相关的配置怎么设置。
题39
使用正则匹配,前面不为空格后面不为空格的字符串。
1
2
3
4 function trim(str){
return str.replace(/(^\s*)|(\s*)$/g,"");
}
console.log(trim(" ds "));
题40
如果也要发送多个请求,如何确保页面渲染的数据的是最后一个请求的数据
题41
解释一下 setTimeOut 机制。
题42
export和export default的区别
1
2
3
4
5
6 共同点:
均可以导出常量,文件,函数,模块等
可以通过import进行导入并对其进行引用
不同点:
一个文件或者模块中,export、import可以有多个,export default 仅有一个。
通过export方式导出,import时要加{},export则不需要
题43
vuex的模式
1
2
3 开启严格模式,只需要创建store的时候传入 strict:true
严格模式下只要不是mutation函数引起的状态变更,都会报错。
应该避免发布环境开启严格。
题44
使用input时用v-model.如果这个状态是在vuex中管理的状态。怎么处理?
例子:1
<input v-model="obj.message">
用户输入时,v-model会视图直接修改obj.message。在vuex严格模式下,由于这个修改不是mutation函数中执行的
,会抛出错误。
用vuex的思维去解决的话:给input中绑定value,然后监听input或者change事件,在事件回调中调用action1
<input :value="message" @input="updateMessage">
解决方法:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31//...
computed:{
...mapState({
message: state =>state.obj.message
})
},
methods:{
updataMessage(e){
this.$store.commit('updataMessage',e.target.value);
}
}
//...
mutations:{
updataMessage(state,message){
state.obj.message = message;
}
}
//方法二
使用带有setter的双向绑定计算属性:
computed:{
message: {
get(){
return this.$store.state.obj.message;
},
set(value){
this.$store.commit("updateMessage",value);
}
}
}
}