阅读 497

2020-今年的裸辞暂告一个段落 | 掘金征文

5月20日从上家公司拿到离职证明,到7月20日拿到了一个自认为还算满意的 offer,这个为期2个月、从杭州到成都裸辞之旅暂告一个段落。

本文首发在我的个人博客上:www.brandhuang.com/article/159…

本文主要分三个话题:

  1. 自我介绍
  2. 最后总结
  3. 一些面试题

自我介绍

2016年某大学电子信息科学与技术专业毕业,自学踏入了前端这个行业,到2020年的7月,算是整整4年的前端经验了,一直混迹在各种不知名的小厂,基本是自己一个人在前端这块单打独斗,本来是加一些「技术群」去向大佬取经的,结果都变成了闲扯吹水的群。自己也一天天从前端小白,变成了前端老白。

前两年 JQuery 一把梭,后两年 Vue 全家桶熟练工,新工作大部分时间要搞 React Hooks了

工作第二年开始了解到 Vue,由于工作中没有用武之地,只好自己折腾,于是 2017 年自己开始用 Vue + Koa2 + Mysql 折腾上线了自己的博客:

18年准备换工作的时候,群里已经有朋友开始用 React 了,于是自己又开始学习 React ,想着有人一起学习,有问题方便找人请教,朋友推荐了《React小书》,照着撸了一遍了,又开始拿自己博客开始练手,尝试写写 demo:

谁料到,18年换了这份工作开始,至今,经历的公司都是用的 VueReact 就这样被我放弃了,18年可以说是我 React 技术最牛逼的时候!

最近一年开始接触数据结构与算法设计模式性能优化等等...

由于在工作中都没有机会大量的实战(或者说没有大佬带,自己一个人不敢大量实战),所以大多数都是浅尝辄止,学习也是属于两天打鱼,三天晒网,还有两天在想到底要不要学这个,学了到底有不有用

我这四年经验换算成其他同行的,可能就3个月的经验吧

我发现 「工作中没有用到」 成了我学习技术路上最大的绊脚石

新工作,新开始,立个 Flag:从现在开始打磨这块绊脚石,争取早日碾碎它

这次裸辞虽然内心慌的一批,但是表面还是要装出一副很镇定的样子,毕竟是男人,决不允许让别人说自己不行,即使真不行,也能让别人知道!

今年的面试除了和项目强相关的外,其他基础题基本都能在掘金别的大佬的面经上刷到

自己今年的面试总结起来大概就是:「js基础 30%」、「框架原理 30%」、「简历上写的内容 30%」、「性能优化 4%」、「计算机网络 4%」、「数据结构与算法 1%」、「其他 1%」

总结

不知道自己这篇文章到底要表达个什么意思,就当作自己的一个年中总结吧。

今年概况:

  • 2020年2月份复工,上家公司薪资微调,不符预期
  • 3月底公司调整,换项目组,
  • 4月下旬提离职裸辞
  • 5月底离开杭州回到成都
  • 7月下旬入职新公司,薪资涨幅还算满意(比上家公司好吧)
  • 下半年新环境,事太多,好好学习,奥利给!

以个人这四年混过来的经验来说,为了混口好饭吃,这几点真的很重要:

  • 制定目标:方向错了,可能怎么做都是错的;
  • 做好计划:规划时间,摆脱拖延症;画好图(脑图、UML类图、流程图等等),按部就班;
  • 自学能力:找到适合自己的学习方式和内容;
  • 动手实战:实践出真知,是骡子是马拉出来遛遛;
  • 做好记录:好记性不如烂笔头,随时翻看,减缓记忆衰减;
  • 持之以恒:三分钟热度最终都会凉凉,除了浪费时间什么也得不到

学习的路还很长,虽然苦,但值得咬牙坚持。

每天有一点收获也是一种进步

我相信和我一样 间歇性踌躇满志,持续性混吃等死 的人应该不在少数

只希望你回顾过去的时候,不会后悔

一些面试题目

题目并不是所有都给出了答案,请自行总结~;另,感谢各位大佬的面经收获颇多;题目可能出现记忆偏差,答案如有错误或者描述不准确,欢迎指正

js是单线程语言,所有任务只能在一个线程上完成,一次只能做一件事。js通过eventLoop来实现异步。

为什么js设计成单线程?

JavaScript 的主要用途是与用户互动,以及操作 DOM。多线程操作DOM的话容易造成混乱(比如一个线程要修改这个DOM,而另一个线程则要删除这个DOM...)。

js 中的 EventLoop

主要需要理解任务(task)微任务(micro task)

常见的任务(task): setTimeout、setInterval、 setImmediate、script(整体代码)、 I/O 操作、UI 渲染等

常见的微任务(micro task): process.nextTick、new Promise().then(回调)、MutationObserver(html5 新特性) 等

Node 中的 EventLoop

Node.js 采用 V8 作为 js 的解析引擎,而 I/O 处理方面使用了自己设计的 libuv,事件循环在其中实现。与浏览器中的事件循环是不同的

在 libuv 中,将事件循环分为六个阶段:

  1. timers 阶段:这个阶段执行 timer(setTimeout、setInterval)的回调
  2. pending callbacks 阶段:该阶段对某些系统操作(如TCP错误类型)执行回调。处理一些上一轮循环中的少数未执行的 I/O 回调
  3. idle, prepare 阶段:仅 node 内部使用
  4. poll 阶段:获取新的 I/O 事件,执行与 I/O 相关的回调,适当的条件下 node 将阻塞在这里
  5. check 阶段:执行 setImmediate() 的回调
  6. close callbacks 阶段:执行 socket 的 close 事件回调

Node 事件循环执行顺序:外部输入 -> poll -> check -> close callbacks -> timers -> I/O callbacks -> idle,prepare -> poll -> ...(循环)

重点阶段详解:

  1. timers:Node 会检查有无过期的timer,如果有,则把他的回调加入到timer的任务队列中等待执行「这个过期检测不一定靠谱,受机器上其它运行程序影响,或者那个时间点主线程不空闲」。
// 下列代码中 settimeout和setimmediate的执行顺序不确定
// 但是如果将他们放入到I/O回调中
// 则 setImmediate会先执行
// 请参看前面Node中事件循环执行顺序
setTimeout(() => {
  console.log('timeout')
}, 0)

setImmediate(() => {
  console.log('immediate')
})
复制代码
  1. poll:该阶段系统会做两件事:

    1. 计算应该阻塞和轮询 I/O 的时间(控制timer阶段的执行)
    2. 处理 poll 队列里的事件

    进入本阶段,同时未设定 timer 时,会发生以下两种情况:

    • 如果 poll 队列不为空,会遍历回调队列并同步执行,直到队列为空或达到系统限制。
    • 如果 poll 队列为空
      • 如果有预设的 setimmediate() ,则poll阶段会结束并进入执行 check 阶段任务队列
      • 如果没有预设的 setimmediate() ,则EventLoop会被阻塞在该阶段。为防止一直阻塞,该阶段event loop会有一个检查机制,检查timer队列是否为空,如果timer队列非空,event loop就开始下一轮事件循环,即重新进入到timer阶段。
  2. check:setImmediate()的回调会被加入 check 队列中。check 阶段的执行顺序在 poll 阶段之后。

process.nextTick

这个函数其实是独立于 Event Loop 之外的,它有一个自己的队列,当每个阶段完成后,如果存在 nextTick 队列,就会清空队列中的所有回调函数,并且优先于其他 microtask 执行。递归的调用process.nextTick()会导致I/O starving,官方推荐使用setImmediate()

参考文章

Node中和浏览器中EventLoop的差异:

区别:microtask 队列的执行时机不同

  • Node.js 中 EventLoop 分为六个阶段
  • 浏览器环境下:microtask 队列是在每个 macrotask 队列执行之后执行。
  • Node.js 中:一个阶段执行完毕就会去执行 microtask 队列的任务。

Vue3.0 中的 Proxy 和 Vue2.x 中的 defineProperty 的优劣对比

结论:

  • Proxy 监听是的对象,而不是对象上的属性(defineProperty 监听的是对象上的属性)
  • Proxy 除了拦截 set 和 get 还能拦截 apply、ownKeys、deleteProperty、has等等是Object.defineProperty不具备的。
  • Proxy返回的是一个新对象,可以只操作新的对象达到目的,而Object.defineProperty只能遍历对象属性直接修改
  • Object.defineProperty 支持 IE9,Proxy的存在浏览器兼容性问题,而且无法用polyfill磨平。

Vue2.x 的核心函数是 Object.defineProperty,通过给对象属性添加一些配置,拦截属性的 getset 方法来实现数据的响应式绑定,但是对对象新增的属性无能为力,对数组也需要拦截它的原型方法来实现响应式,不能通过 arr[1]=xx 方式来修改数组。此时,vue 提供了一个api:this.$set 使新增属性也能实现响应式。

// vue2中是根据具体的 key 去进行拦截的,需要知道拦截的 key 是什么,
// 所以对新增的key 无能为力。
// 数组不能通过 arr[1]=xx 来修改
let data = {}
Object.defineProperty(data, key, {
    get: function() {

    },
    set: function() {

    }
})
复制代码

Vue3 中使用 Proxy 代替了 Object.defineProperty

// 这种拦截方式不需要知道具体的 key
// 可拦截任意的 key
// 不管新增的还是已有的
// 数组可以通过 arr[1]=xx 来修改
new Proxy(data, {
    get() {},
    set(){}
})
复制代码

参考文章

TCP三次握手以及HTTP位于那一层?(计算机网络)

TCP/IP 协议族分为 4 层:

  1. 应用层
  2. 传输层
  3. 网络层
  4. 数据链路层

三次握手:

  1. 第一次握手:发送端将 SYN=1 同步序列号和初始化序列号 seq=x 发送给接收端
  2. 第二次握手:接收端收到 SYN 请求报文之后,如果同意连接,会以自己的同步序列号SYN(服务端) = 1、初始化序列号 seq = y和确认序列号(期望下次收到的数据包)ack = x+ 1 以及确认号ACK = 1报文作为应答
  3. 第三次握手:接收端接收到服务端的 SYN + ACK 之后,发送同步序列号 ack = y + 1和数据包的序列号 seq = x + 1以及确认号ACK = 1,握手结束。

四次挥手:

  1. 第一次挥手:客户端发送一个FIN=M,用来关闭客户端到服务器端的数据传送,客户端进入FIN_WAIT_1状态
  2. 第二次挥手:服务器端收到FIN后,发送ack=M+1,服务端进入CLOSE-WAIT(关闭等待)状态,客户端进入FIN_WAIT_2 状态
  3. 第三次挥手:服务器端确定数据已发送完成,则向客户端发送FIN=N报文,服务器端进入LAST_ACK状态
  4. 第四次挥手:客户端收到FIN=N报文后,发送ack=N+1后进入TIME_WAIT状态,服务器端收到ACK后断开连接,客户端2SML(最长报文段寿命)后未收到回复则关闭连接,完成四次挥手

为什么是4次挥手?

服务端是分开发送 ack 和 FIN 信息的,所以会多一次。

HTTP 协议属于应用层

HTTPWebsoket 联系与区别

HTTP 与 Websocket 的相同点

  • 位于应用层,基于TCP,需要三次握手四次挥手
  • 使用Request/Response模型进行连接的建立
  • 在连接的建立过程中对错误的处理方式相同(可能返回相同的错误码)

HTTP 与 Websocket 的不同点

  • HTTP 是单向的(客户端发送请求,服务端发送响应);Websocket 是双向的(服务端客户端都可以主动发起请求);
  • HTTP 是无状态协议(每次请求都会新建与服务器的连接,获得响应后自动终止);Websocket 是有状态协议(客户端和服务器之间的连接将保持活动状态,直到被任何一方(客户端或服务器)终止);

webpack 的 loader 和 plugin 的区别

  • Loader:加载器、转换器。因为 webpack 只能解析 js 文件,loader 能让webpack 拥有加载和解析非 js 资源的能力。
  • Plugin:插件、扩展器。扩展 webpack 功能,Plugin 可以监听 webpack 运行期间广播出的一些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。

websoket 同时接入的数据量大时性能问题

这个还真不清楚,公司这个项目用户数不多,所以根本就不存在高并发的情况。。个人觉得,这种并发问题和前端关系应该不大,是需要后端处理的。唯一可能与性能有关的前端问题应该是大量、频繁更新前端界面的时候引起的。

这个问题感觉可以和性能优化放在一起

性能优化

HTTP 优化

两个大方向,就是我们通常所说的资源的压缩与合并。这里就需要知道webpack了。

  • 减少请求次数
  • 减少每次请求花费的时间

webpack性能优化:主要两个方面:

  1. webpack 构建过程时间过长
  2. webpack 打包结果体积过大

针对构建时间过长:

  • 不要让loader做太多事
    • 使用 include 或者 exclude 来避免不必要的转译
    • 开启缓存,将转译结果缓存至文件系统
    // 以babel-loader为例
    loader: 'babel-loader?cacheDirectory=true'
    复制代码
  • 第三方库单独打包
    • 处理第三方库的包有:ExternalsCommonsChunkPluginDllPlugin等(详细情况自己再下去研究),这样的第三方库就不会随业务代码被重新打包,只有第三方库自身版本发生变化时才会重新打包

针对打包结果体积过大:

  • 拆分资源。使用 DllPlugin
  • 删除冗余代码
    • Tree-Shaking:是基于 import/export 语法,没有被真正使用的模块在打包的时候会被删除。
    • UglifyJsPlugin:在压缩过程中对碎片化的冗余代码(如 console 语句、注释等)进行自动化删除
  • 按需加载

图片优化

JPEG/JPG

特点:有损压缩、体积小、加载快、不支持透明,24位的JPG可存储1600万种颜色

使用场景:适用于呈现色彩丰富的图片。常见的大背景图、轮播图、banner图等

PNG-8 与 PNG-24

PNG 图片具有比 JPG 更强的色彩表现力,弥补了 JPG 的不足,但是体积较大

特点:无损压缩、质量高、体积大、支持透明,8位支持256中颜色,24位支持1600万中颜色

使用场景:Logo、背景简单且对比强烈的图片或背景

SVG

SVG 对图像的处理不是基于像素点,而是是基于对图像的形状描述,与其他图片有本质的不同。可以被非常多的工具读取和修改,具有较强的灵活性。

特点:文本文件、体积小、不失真、兼容性好

Base64

作为小图标解决方案而存在的,作用和雪碧图类似

特点: 文本文件、依赖编码、小图标解决方案

存储优化

浏览器缓存机制:

  1. Memory Cache
  2. Service Woker Cache
  3. HTTP Cache
  4. Push Cache
HTTP Cache

分为强缓存协商缓存强缓存优先级较高,强缓存命中失败才会走协商缓存

强缓存:由 HTTP 请求头中的 ExpireCache-Control 两个字段控制。浏览器根据这两个字段判断是否命中强缓存,若命中,则直接从缓存中获取,不与服务器发生请求

  • Expire 是一个时间戳,浏览器会对比本地时间和 Expire 时间戳(如果改掉客户端本地时间, expire 将不能达到预期,这是 expire 的局限性)
expires: Wed, 11 Sep 2019 16:12:18 GMT
复制代码
  • HTTP1.1新增了 Cache-Control 来替代 Expire 。(该字段是一个时间长度,避免了时间戳带来的问题。相比 expire,更准确,优先级更高,两个字段同时存在时,以 Cache-Control 为准)
cache-control: max-age=31536000
复制代码

协商缓存由 Last-Modified 和 Etag 实现,两个同时存在时以 Etag 为准, 需要浏览器向服务器询问缓存信息,来决定是发起请求还是从本地缓存获取。

响应会返回 Last-Modified,请求会携带 If-Modified-Since

Last-Modified: Mon, 01 Jun 2020 06:34:26 GMT

If-Modified-Since: Mon, 01 Jun 2020 06:34:26 GMT
复制代码

Last-Modified 常见问题:

  • If-Modified-Since 只能检查以秒为单位的时间差,修改时间过短会出问题
  • 如果修改了文件但是没改文件内容,会被当作新资源请求,所以出现了 Etag

Etag:基于文件内容,编码生成唯一标志字符串,避免了 Last-Modified 的两个问题。响应会返回 ETag,请求会携带 If-None-Match

ETag: W/"2a3b-1602480f459"

If-None-Match: W/"2a3b-1602480f459"
复制代码
Memory Cache

内存缓存,优先级最高,速度快,进程结束后即被清空。常缓存 base64 格式的图片、体积较小的 js 和 css 文件,体积较大的会被存进磁盘。

Service Woker Cache

独立于主线程之外的 Javascript 线程。脱离于浏览器窗体,因此无法直接访问 DOM。用来实现离线缓存、消息推送和网络代理等功能仅支持 HTTPS 协议

Push Cache

HTTP2 中的新知识

特点:

  • 在其他缓存均未命中的情况下,才会查找该缓存
  • 是一种存在于会话阶段的缓存,当 session 终止时,缓存也随之释放
  • 不同的页面只要共享了同一个 HTTP2 连接,那么它们就可以共享同一个 Push Cache。

渲染优化

参考文章

推荐一本掘金小册:

前端性能优化原理与实践

常用的设计模式(然后说话你的项目中用到过的)

推荐一本掘金小册和一篇文章,然后结合自己的项目总结下:

Vuex的原理,怎么实现状态管理的

Vue双向绑定如何实现的,get和set进行了哪些操作

Vue生命周期

this.$nexttick原理

说下你了解的async和await?await的使用条件是什么?

前端请求的封装是如何做的?

遍历数组你常用的方法,有何区别

watch和computed相关用法以及区别

组件传参

深拷贝浅拷贝

做过公共组件抽离吗?

vue权限路由实现?如果后续路由层级加深,该如如何处理?

mixin在项目中有用到嘛?

你所做项目中觉得哪个是比较有的亮点的?是什么?

vue-router原理(怎么根据url找到我们对应的组件的)

数组去重

写一个数组排序方法(数组可能是简单数组,也可能是复杂数组)

项目打包后文件过大你是怎么优化的

页面加载时间过长你是怎么优化的

vue双向绑定原理

vue中computed与watch

介绍下协商缓存与强制缓存

项目中,关闭页面(或者浏览器后)未提交的数据如何保存与回填。你怎么确定存储的数据是这个页面的

js数据类型转换

js中类型转换有3种:

  • 转换为布尔型(调用 boolean()方法)
  • 转换为数字(调用Number()、parseInt()和parseFloat()方法)
  • 转换为字符串(调用.toString()或者String()方法)

除以上三种外,还有一些操作符会存在隐式转换

  • 对象和布尔值比较:对象先转换成字符串然后转成数值,布尔值转成数值,然后两者进行比较
  • 对象和字符串比较:对象转成字符串,然后和字符串进行比较
  • 对象和数字比较:对象先转换成字符串然后转成数值,然后进行比较
  • 字符串和布尔值比较:两者先转成数值进行比较
  • 布尔值和数字比较:布尔值先转成数值进行比较

Number方法的参数是对象时

第一步,调用对象自身的valueOf方法。如果返回原始类型的值,则直接对该值使用 Number函数,不再进行后续步骤。(默认情况下,对象的valueOf方法返回对象本身)

第二步,如果valueOf方法返回的还是对象,则改为调用对象自身的toString方法。如果toString方法返回原始类型的值,则对该值使用Number函数,不再进行后续步骤。

第三步,如果toString方法返回的是对象,就报错。

var obj = {x: 1};
Number(obj) // NaN

// 等同于
if (typeof obj.valueOf() === 'object') {
  Number(obj.toString());
} else {
  Number(obj.valueOf());
}
复制代码

js隐式转换原理

Vue 父子组件生命周期执行顺序

  1. 加载渲染过程
  • 父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
  1. 子组件更新过程
  • 父beforeUpdate->子beforeUpdate->子updated->父updated
  1. 父组件更新过程
  • 父beforeUpdate->父updated
  1. 销毁过程
  • 父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

三栏布局

bfc

清除浮动

声明一个变量实现:a===1&&a===2&&a===3

方法一:

let val = 1
Object.defineProperty(this, 'a', {
  get(){
    return val++
  }
})
复制代码

方法二:利用 toString 方法

class A {
    constructor(value) {
        this.value = value;
    }
    toString() {
        return this.value++;
    }
}
const a = new A(1);
if (a == 1 && a == 2 && a == 3) {
    console.log("success");
}
复制代码

拓展:

// 设置一个函数输出以下的值
f(1) = 1;
f(1)(2) = 3;
f(1)(2)(3) = 6;

function f() {
  let args = [...arguments];
  let add = function() {
    args.push(...arguments);
    return add;
  };
  add.toString = function() {
    return args.reduce((a, b) => {
      return a + b;
    });
  };
  return add;
}
console.log(f(1)(2)(3)); // 6

复制代码

事件触发顺序

  • NetSpace:事件捕获先触发
  • MicroSoft: 事件冒泡先触发
  • W3C模型中:事件先捕获,在冒泡

js 基础数据类型与复杂数据类型的区别

7种基础数据类型:undefinednullnumberbooleanstringSymbol(ES6新增,表示独一无二的值)BigInt(ES10)

1种引用数据类型(复杂数据类型):Object,包含function、Array、Date等

  • 基本数据类型把数据名和值直接存储在栈当中占据空间小、大小固定,属于被频繁使用数据
  • 复杂数据类型在栈中存储数据名和一个在堆(占据空间大、大小不固定)中的地址在堆中存储属性及值,访问时先从栈中获取地址,再到堆中拿出相应的值

vue页面级的拆包

闭包及其作用

闭包就是能够读取其他函数内部变量的函数。闭包是将函数内部和函数外部连接起来的桥梁

如何从外部读取函数内部的局部变量?可通过闭包实现

  • 作用
      1. 封装私有变量
      1. 读取函数内部变量
      1. 变量始终保存在内存中(滥用闭包会造成内存泄漏)

原型、原型链

每个对象都有 __proto__ 属性,但只有函数对象才有 prototype 属性

所有的普通的原型链最终都会指向Object.Prototype

箭头函数与普通函数的区别

  • 箭头函数是匿名函数,不能作为构造函数,不能使用new
  • 箭头函数不能绑定arguments,取而代之用rest参数...解决
      function A(a){
        console.log(arguments);
      }
      A(1,2,3,4,5,8);
      // [1, 2, 3, 4, 5, 8, callee: ƒ, Symbol(Symbol.iterator): ƒ]
      let C = (...c) => {
        console.log(c);
      }
      C(3,82,32,11323);
    复制代码
  • 箭头函数没有原型属性
      let arrow = () => {}
      arrow.prototype // undefined
    复制代码
  • 箭头函数的this永远指向其上下文的this,没有办改变其指向, 普通函数的this指向调用它的对象

vue中 v-if 和 v-for 同时出现,那个优先级高,同时存在时怎么优化性能?

  • v-for优先于v-if被解析
  • 如果同时出现,每次渲染都会先执行循环再判断条件,无论如何循环都不可避免,浪费了性能
  • 优化一:要避免出现这种情况,则在外层嵌套template,在这一层进行v-if判断,然后在内部进行v-for循环
<template v-if="...">
  <p v-for="item in itemArrValid" :key="item.id">{{item}}</p>
</template>
复制代码
  • 优化二:如果在循环内部进行if判断,我们可以先用computed过滤出有效的展示数据,再进行渲染
<p v-for="item in itemArrValid" :key="item.id">{{item}}</p>
复制代码
computed:{
  itemArrValid(){
    // return ...
    // 处理 itemArr 重的数据 
  }
}
复制代码

v-for 绑定 key 的作用

v-for 的默认行为会尝试原地修改元素而不是移动它们。要强制其重新排序元素,你需要用特殊 attribute key 来提供一个排序提示。———— 来源:Vue官网

key 的特殊属性主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes。如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试修复/再利用相同类型元素的算法。使用 key,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。

key是给每一个vnode的唯一id,可以依靠key,更准确, 更快的拿到oldVnode中对应的vnode节点。

  1. 更准确

    因为带key就不是就地复用了,在sameNode函数 a.key === b.key对比中可以避免就地复用的情况。所以会更加准确。

  2. 更快

    利用key的唯一性生成map对象来获取对应节点,比遍历方式更快。(这个观点,就是我最初的那个观点。从这个角度看,map会比遍历更快。)

vue中的data

官方文档:cn.vuejs.org/v2/api/#dat…

data可以是一个 Object,也可以是一个 Function。但是组件的定义只接收 function(因为组件可能被用来创建多个实例。如果 data 仍然是一个纯粹的对象,则所有的实例将共享引用同一个数据对象!通过提供 data 函数,每次创建一个新实例后,我们能够调用 data 函数,从而返回初始数据的一个全新副本数据对象)

var data = { a: 1 }

// 直接创建一个实例
var vm = new Vue({
  data: data
})
vm.a // => 1
vm.$data === data // => true

// Vue.extend() 中 data 必须是函数
var Component = Vue.extend({
  data: function () { 
    return { a: 1 }
  }
})
复制代码

Vue 组件间传值

一、父子组件传值

  1. 父组件 传给 子组件
    • 父组件 通过 v-bind 绑定动态数据传给子组件
    • 子组件 通过 props 接收
    • 使用$ref获取指定的子组件
    • 使用$children
  2. 子组件 传给 父组件
    • 子组件 用 this.$emit('fnName', data) 触发 ``
    • 父组件 用 @fnName="fn" 接收,注意,@的名称 和子组件this.$emit名称相同
    • 使用 $parent

二、组件传值

  1. eventBus,利用 bus.$emit(‘eventName', sendData)触发,通过 bus.$on(‘eventName', (getData) => {})监听接收
  2. 使用Vuex
  3. $sttrs/listeners 用于多级组件间传值的问题
// 一般在 main.js中引入
Vue.prototype.bus=new Vue()
// 或者
window.bus = new Vue()
复制代码

webpack 热更新原理

推荐文章:zhuanlan.zhihu.com/p/30669007

vue 组件封装

全局主题切换思路

vue 中怎么定义一个全局方法

方法一:

// 在 main.js 中
Vue.prototype.Fn = function () {
  console.log(‘这是一个全局方法’)
}
复制代码

方法二:

// 一个单独的js文件
// globalFn.js
const data = {
  hello(param){
      return param
  }
}

const install = (vm, option) => {
  vm.prototype.gFn = data
}
export default { install }

// main.js中引入

import gFn from './globalFn.js'
Vue.use(gFn)

// 使用

this.gFn.hello('hello')
复制代码

如何保证API调用时数据的安全性?

  1. 通信使用https
  2. 请求签名,防止参数被篡改
  3. 身份确认机制,每次请求都要验证是否合法
  4. 对所有请求和响应都进行加解密操作

V8垃圾回收机制

下列代码输出什么

滑慢点,下面挨着的就是答案

var a = 1;
let b = 2
let obj = {
    a:11,
    b:22,
    fn: function(){
        console.log(this.a, this.b)
    },
    fn1: () => {
        console.log(this.a, this.b)
    }
}
obj.fn()
obj.fn1()

复制代码

解析:

本题个人看到有两个知识点:

1、this指向问题

2、let 声明的变量不会挂在window上,var 声明的会挂在 window 上

obj.fn() 输出: 1122

objfn1() 输出:1undefined
复制代码

掘金征文 | 2020 与我的年中总结 征文活动正在进行中......