前端面经总结(八)

前端面经总结(六)

Vue中computed和watch区别

  1. computed是计算属性,只有依赖数据发生改变才会重新计算。watch是监听属性,数据遍直接会触发相应的操作

  2. computed不支持异步。watch支持异步

  3. computed多用于多对一或一对一,即属性由其他属性计算而来时的情况。watch多用于一对多的情况,即当一个属性变化时,需要执行对应的操作

  4. computed属性在getter执行后默认走缓存,它基于响应式依赖进行缓存,即基于data声明或父组件传递的props中的数据通过计算后得到的值。只有当它依赖的属性值改变后,下一次获取computed的值时才会重新调用getter计算。

  5. watch监听的函数接收两个参数,最新的值newVal和输入之前的值oldVal。在每次监听的值变化时,都会执行回调。当数据变化时,触发的函数有两个参数,immediate表示组件加载立即触发回调函数执行,deep为深度监听,为了发现对象内部值的变化,为复杂类型的数据时使用。如数组中对象内容的改变,但deep无法监听数组变动。

cors后端如何实现,能否传递cookie

Java实现

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
58
59
60
import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;

/**
* 允许跨域过滤器(Cross-Origin Resource Sharing)
* @author user
*
*/
@Component
public class CorsFilter implements Filter {

private final Logger logger = Logger.getLogger(this.getClass().getPackage().getName());

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;

response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "*");
response.setHeader("Access-Control-Max-Age", "3600");
// response.setHeader("Access-Control-Allow-Headers", "*");
response.setHeader("Access-Control-Allow-Headers", "Authorization,Origin,X-Requested-With,Content-Type,Accept,"
+ "content-Type,origin,x-requested-with,content-type,accept,authorization,token,id,X-Custom-Header,X-Cookie,Connection,User-Agent,Cookie,*");
response.setHeader("Access-Control-Request-Headers", "Authorization,Origin, X-Requested-With,content-Type,Accept");
response.setHeader("Access-Control-Expose-Headers", "*");

chain.doFilter(req, response);
}

public void init(FilterConfig filterConfig) {}

public void destroy() {}

}

//web.xml文件:用来初始化配置信息:比如Welcome页面、servlet、servlet-mapping、filter、listener、启动加载级别等
<!-- 跨域过滤器 -->
<filter>
<filter-name>corsFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>corsFilter</filter-name>
<url-pattern>/dental/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>corsFilter</filter-name>
<url-pattern>/toothCheck/*</url-pattern>
</filter-mapping>

cors传递cookie

  1. 没有跨域时,后端在response头部设置set-cookie,则会产生cookie并保存在客户端。等客户端再次向后端发送请求时,浏览器会自动携带cookie随请求一并发送到后端

  2. cors跨域时,浏览器默认无法主动跨域向后端发送cookie。故需要发送cookie

    • 浏览器设置withCredentialstrue

    • 后端设置Access-Control-Allow-Credentialstrue

此时可以发送cookie,但由于同源策略,仍然无法使用/修改cookie,仅能访问到。cookie的CRUD只能由server控制

tree-shaking

Tree Shaking 是一种通过消除最终文件中未使用的代码来优化体积的方法。

当引入一个模块时,不引入此模块的所有代码,只引入需要的代码,故可以借助webpack的tree shaking功能。

shaking```只支持```ES Module-import```,不支持```require```。```require```是动态加载模块的,故可以根据代码中的条件来导入。而```import```是静态加载的,故需要使用```tree shaking```。
1
2

在```mode: production```模式下,```tree shaking```会被自动配置,但```tree shaking```并不能自动判断副作用脚本,即在```import```时执行了一些行为,但此行为不一定和到处相关,如```polyfill```是全局引用的,不是在```index.js```中导入引用。故对于副作用脚本需要在```package.json```文件中添加```"sideEffect":["./src/polyfill.js"],

mode: development模式下,可以在webpack.config.js文件中,使用optimization:{ usedExports: true }来配置tree shaking

图片懒加载的实现和原理

原理

  1. 设置图片的data-set属性值为图片路径,而不是src,故不会发送http请求

  2. 计算页面scrollTop的高度和浏览器高度之和,若图片距离页面顶端(相对于整个页面,而不是浏览器窗口)坐标Y小于两者之和,则说明图片要显示出来了

  3. 替换data-set属性为src属性

实现

  1. 使用padding-toppadding-bottom实现固定宽高比
1
2
3
<div style="padding-top:75%">
<img data-src="" alt="" class="lazyload">
<div>
  1. Vue中使用开源vue-lazyload

    • 使用npm install vue-lazyload --save下载

    • 引入vue-lazyload到main.js

      1
      2
      3
      4
      5
      6
      import VueLazyload from 'vue-lazyload'
      Vue.use(VueLazyload, {
      preLoad: 1.3,//在屏幕多少倍的范围内开始加载
      loading: 'http://cdn.uehtml.com/201402/1392662591495_1140x0.gif',
      error: 'https://cdn.dribbble.com/users/195330/screenshots/1545094/attachments/235536/21_404-error.png'
      });
    • 在.vue中使用

      1
      <img id="errorImg" v-lazy="'http://bbg-seller.oss-cn-qingdao.aliyuncs.com/test/gp/p1/' + item.picture" error="this.src=null;" >

502产生的原因

连接超时,服务器当前链接太多,无法给予正常响应。通常可产生的原因有

  1. DNS缓冲,如未开启vpn访问外链,未访问到且在本机留下了缓冲,可通过等待几分钟再次访问或在cmd中运行ipconfig/flushdns解决

  2. 浏览器开了代理,关掉后可访问

  3. dns被劫持。

jquery如何获得兄弟节点

  • siblings():选取所有兄弟节点

  • next():选取后面的兄弟节点

  • nextAll():选取所有后面的兄弟节点

  • nextUntil():选取所有后面的兄弟节点,但不包括后面指定节点的弟弟。

  • prevAll():选取所有墙面的兄弟节点

  • prevUntil():选取所有的兄弟节点,但不包含后面指定的节点及指定节点的哥哥

如:

1
$("li.start").siblings().css({"color":"red","border":"2px solid red"});

echarts原理

echarts是轻量级的javascript图形库,纯js实现,MVC封装,数据驱动

echarts特点为重要性和优先级一次递减,可个性化定制。其总体结构基于MVC架构。

  • Storage(M):模型层,实现图形数据的增删改查管理
  • Painter(V):视图层,实现Canvas元素的生命周期管理。如视图渲染、更新控制、绘图等
  • Handler(C):控制层,事件交互处理,实现完整的dom事件模拟封装

其中,Painter持有Storage对象,即Painter读取Storage进行绘图。Handler持有StoragePainter对象,控制层对模型层有增删改查CURD关系,即Handler通过访问Storage对象提供的数据增删改查操作,实现事件交互处理所需的数据部分,控制层和视图层存在call关系,即Handler通过访问Painter对象提供的视图操作,实现事件交互处理的视图部分。

SVG和Canvas

SVG和Canvas是两个可选择的类库之一。SVG基于XML,即SVG DOM中每个怨毒都是可用的,且每个被绘制的图像均被视为对象。Canvas基于JavaScript绘制2D图形,且是逐像素渲染,一旦图形被绘制完成,则浏览器停止关注它,若其位置发生变化,则整个场景都需要重新绘制。

  1. Canvas依赖分辨率,SVG不依赖分辨率

  2. Canvas不支持事件处理器,SVG支持事件处理器

  3. Canvas文本渲染能力弱,SVG适合带有大型渲染区域的应用程序

  4. Canvas能以.png/.jpg格式保存结果图像

  5. Canvas适合图像密集型的游戏,其中许多对象会被频繁重绘。SVG不适合游戏应用,复杂度高会减慢渲染速度

echarts如何实现响应式变化

使用echarts里的resize函数,当页面发生resize事件时,触发echarts的resize事件,重绘canvas

  • 若页面只有一个echarts图表,可window.onresize = myChart.resize()

  • 若页面有多个echarts图表,使用事件绑定方法addEventListener()方法

  • 若在vue中使用响应式图标,直接对对象添加事件

1
2
myCharts.setOption(option);//使用指定的配置项和数据显示图表
window.addEventListener("resize", () => { myCharts.resize();});

作用域题

1
2
3
4
5
6
7
8
9
10
function foo() {
console.log( a );
}
function bar() {
var a = 3;
foo();
}
var a = 2;
bar();//输出2
bar.call({a:4})//输出2

调用方法bar()时,bar()方法在全局作用域创建,同时bar()方法调用foo()方法,foo()方法也在全局作用域创建,故foo()方法中,用到的a的值,要取全局作用域定义的a值,即var a = 2;。故bar()输出2。

以上bar()方法的输出用到了“静态作用域“的内容,即调用函数时,函数内用到的参数要到创建这个函数的那个作用域中取值

同样,bar.call({a:4})bar()this指向了{a:4}。但foo()方法输出的是console.log(a)a仍是自由变量,故还是在创建foo()方法的作用域找,故仍输出2。若想输出4,则需要修改foo()方法console.log(this.a)

算法:千分位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* @param {number} n
* @return {string}
*/
var thousandSeparator = function(n) {
let str = "";
let nstr = n.toString().split("").reverse();
for(let i = 0;i<nstr.length;i++){
if(i%3 == 2 && i != nstr.length - 1){
str+=nstr[i]+".";
}else{
str+=nstr[i]+ ""
}
}
return str.split("").reverse().join("");
};
//利用正则表达式
var thousandSeparator = function(n) {
let str = n.toString();
let reg = /(\d)(?=(?:(\d{3})+$))/g;
return str.replace(reg,'$1.')
};

算法:两数之和

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function(nums, target) {
let result = [];
for(let i = 0;i< nums.length;i++){
let num = target - nums[i];
let index = nums.lastIndexOf(num);
if(index && index !== i && index !== -1){
result.push(i);
result.push(index);
return result;
}
}
};

算法:多维数组转化为一维数组

  1. 利用str
1
2
3
4
function fn(arr){
let str = arr.join();
return str.split(",");
}
  1. 利用循环递归
1
2
3
4
5
6
7
8
9
10
11
function fn(arr){
let result = [];
for(let i = 0;i<arr.length;i++){
if(Array.isArray(arr[i])){
fn(arr[i]);
}else{
result.push(arr[i]);
}
}
}
fn(arr);

算法:珂里化

待改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let fn = function(n1,n2,n3){return n1*n2*n3}

function fun1(fn){
let len = fn.length;
let args = [];
return function(arg){
args.push(arg);
if(arg.length < len){
return arguments.callee;
}
else{
return fn.apply("",args);
}
}
}
  • 版权声明: 本博客所有文章除特别声明外,均采用 Apache License 2.0 许可协议。转载请注明出处!
  • © 2020-2024 Aweso Lynn
  • PV: UV: