阅读 42668

jsliang 的 2019 面试准备

Create by jsliang on 2019-2-11 15:30:34
Recently revised in 2019-3-17 21:30:36

Hello 小伙伴们,如果觉得本文还不错,记得给个 star , 小伙伴们的 star 是我持续更新的动力!GitHub 地址

并不是只有特定的季节才能跑路,只因为人跑得多了,这条路就定下来了。

金三银四跳槽季,jsliang2019年2月11日 写下了这篇文章,开始准备自己的面试之旅。

2019年3月17日 为止,jsliang 搭建出个人的面试知识体系,海量地翻阅了一些前辈留下的资料,结合个人需求进行了几场面试,从而进一步完善该文章并进行了发表,希望对准备跳槽或者正在跳槽中的小伙伴有所帮助。

一 目录

不折腾的前端,和咸鱼有什么区别

目录
一 目录
二 前言
2.1 自我介绍
2.2 跳槽原委
2.3 进击目标
2.4 开篇点题
三 HTML
3.1 HTML 学习推荐
3.2 HTML 语义化
3.3 HTML5 新标签
3.4 常见浏览器及其内核
3.5 cookies、session、sessionStorage、localStorage
四 CSS
4.1 CSS 学习推荐
4.2 CSS reset
4.3 CSS 盒模型
4.4 CSS 单位
4.5 CSS 选择器
4.6 CSS 常见布局
4.7 CSS3 新特性
4.8 BFC
4.9 行内元素和块级元素
4.10 行内样式、内嵌式、链接式以及导入式
4.11 水平垂直居中
五 JavaScript
5.1 JS 学习推荐
5.2 JS 引用方式
5.3 原型与原型链
5.4 作用域与闭包
5.5 浅拷贝与深拷贝
5.6 模块化与组件化
5.7 面向对象与面向过程
5.8 防抖与节流
5.9 ES6
5.10 数组操作
六 Vue
6.1 MVVM
6.2 生命周期
6.3 双向数据绑定
6.4 Virtual DOM
6.5 template 编译
6.6 key
6.7 nextTick
6.8 父子组件通讯
七 微信小程序
7.1 文件主要目录及文件作用
7.2 微信小程序生命周期
7.3 如何封装数据请求
7.4 页面数据传递
7.5 加载性能优化的方法
7.6 微信小程序与原生 APP、Vue、H5 差异
7.7 微信小程序原理
八 浏览器
8.1 浏览器解析 URL
8.2 重绘与回流
8.3 数据存储
8.4 内存管理与垃圾回收
8.5 内存泄漏
九 网络协议
9.1 网络分层
9.2 HTTP/HTTPS
9.3 HTTP 状态码
9.4 TCP 三次握手与四次挥手
十 性能优化
10.1 HTML 优化
10.2 CSS 优化
10.3 JavaScript 优化
十一 算法
十二 其他
十三 总结
十四 参考文献
14.1 关于面试
14.2 关于 HTML
14.3 关于 CSS
14.4 关于 JS
14.5 关于其他
十五 网友反馈

二 前言

返回目录

请时刻准备好自己的简历,不管是互联网经济不佳面临裁员,还是因为公司内部斗争严重心乱如麻,还是因为厌倦了目前的一切……只有随时更新自己,把自己的简历准备好,你才知道哪一刻跑路是最佳选择。

2.1 自我介绍

返回目录

Hello 小伙伴们好,我叫梁峻荣,网名叫 jsliang,由于崇拜前端大佬 技术胖jspang)的原因,又因为自己学的是前端(JavaScript),所以给自己取了个 jsliangJavaScriptLiang) 的网名,希望自己能通过建立自己的前端知识体系,从而在前端路上走得更远。并将自己的经验分享给小伙伴,携手小伙伴们一起前行。

下面是讲讲个人故事:

首先jsliang 高考后的暑期就听大学师兄的建议,开始学习编程,那时候学习了 C 语言,觉得世界上最神奇的事情不过如此,敲两下键盘,按下回车,电脑就会一闪一闪地响应我们!于是在大学的时候,陆陆续续学过 C、C#、.Net 等……。

-_-|| 由于学得都是基础,又都还给老师了,在这里就不多累述了。

然后,在大二就开始接触 HTML,那时候选修了个《网页设计基础》,跟着老师做了个只有几个页面的静态网站。在大三的时候,参加了学校的特训班,分角色按流程从头到尾做了个包含角色管理、购物等功能的网站。同时,由于在特训班的时候,看到后端使用 ThinkPHP(简称 TP),觉得蛮不错的,于是自己捣鼓,使用 TP 3.2.3 + Bootstrap 3 + MySQL 打造了自己的博客(已下线)。

接着,由于选修了门 Node.js 的课,所以也跟着大佬的步伐接触了下 Vue、Koa 这些,那时候对 npm 等诸多不懂,为了折腾这个,我的前端世界自此打开了个大门。

最后,我在自己的毕业设计中使用 Node.js + Vue + ElementUI + MongoDB 打造了个校园外卖、快递代拿等功能的社区单页应用。

在 2018 年 5 月的时候,家里催促,于是直接出来面试。不像其他大佬的毕业等于失业,很幸运地 jsliang 面试第一家就给了 offer,于是就进了这家公司,那时候感觉自己前面的大学生活白过了,只懂 ES5、jQuery、HTML/HTML5、CSS/CSS3 的皮毛。

在熟悉了三个月的业务,公司给的任务能顺利完成后,我觉得自己不够努力:外面的前端翻天覆地,我的技术却只是 jQuery is all!

于是 2018 年 8 月,jsliang 开始写 Markdown,将 5 月份到 8 月份记录到 Word 文档上的笔记整理成了 jsliang 的文档库,并在 jsliang 的掘金 上发表了第一篇文章。

18 年 8 月至今,jsliang 大致经历了以下这些:

  1. 学 Webpack,并用 Webpack 构建一个多页面配置。然后幸运的是,刚好碰到公司的一个仿站任务,于是整个前端小组直接用了我的 Webpack + jQuery + VS Code 的 Live Share 套路进行协同开发!
  2. 学 微信小程序,并将它应用到电信开发的微信小程序项目翼小微中。
  3. 学 ECharts 报表,并用它做了个 Vue + ECharts 的报表,来展示爱音乐公司的运营数据。
  4. 学 Node,然后搭了个企业网站(company.jsliang.top),并写了篇小文章(目前最高成就,获得了 1100 多赞)。
  5. 学 Vue,由于之前学的 Vue,在工作上有好多没有,逐渐淡忘了,所以从基础开始,准备写一套《Vue 从 0 到 1》。

以上,就是 jsliang 的编程生涯。

今儿,在这里写写 jsliang 为了跳槽,根据个人想法进行的一些前端面试资料整理,小伙伴们觉得不错的点个赞或者去 GitHub 点个 star,觉得有误请指出,谢谢~

2.2 跳槽原委

返回目录

马老板曾经说过,跳槽有两个原因:

  1. 钱没给到位。
  2. 心被委屈了。

首先,如果非要给 jsliang 我自己的跳槽定个位,那肯定是钱没给到位,劳动与产出不成正比。在我 2018 年 5 月入职前,与人事的交谈中了解到每年的 8 月和 2 月可以提薪,当初的技术栈是:HTML、CSS、ES5。

然后,2018 年 6 月到 2019 年 1 月,学习并应用到工作中的技术有:

  1. jQuery
  2. Webpack
  3. JSP
  4. 微信小程序
  5. Vue
  6. ECharts

其中 2018 年 8 月刚转正,也不敢说自己技术进步很大,也不敢说自己项目贡献很大,为公司谋了多大利益,所以没有提薪想法。

2019 年 1 月底感觉自己项目也做了,凌晨 4/5/6 点的体育西路也看过了,技术也提升了,于是跟人事交谈,期望 2 月能加薪,人事表示年终述职演讲得好的给提薪,2 月开工的时候表示提薪名单没我份……

你没看错,提薪全靠 PPT。PPT 里提高了不给,没提就是没有。
当初想法很简单,你随便加个 5/600 我也满足了。

最后jsliang 曾跟项目总监私下谈话,建议可以发展一些新产品,这样公司或许能获取一些新收入,我也可以进一步挑战我的技术。但是,由于我司是个老牌子公司,并且大部分依赖于接手电信项目进行扩张……

enm...所以心也委屈了。

在 2018 的努力下,GitHub 破 600 近 700 star,掘金破 10 万阅读量,3000 粉丝:
GitHub 见证:点击查看
掘金见证:点击查看

2.3 进击目标

返回目录

  • 目标城市:广州
  • 目标薪资:10K - 15K
  • 目标技术:
1. 熟悉 HTML/HTML5、CSS/CSS3、ES5/ES6。
2. 了解 OOP 概念,并尝试在工作中使用过 OOP 技巧。
3. 对 MVC/MVVM 架构有一定了解,如有 Vue/React/Angular 或者 微信小程序开发经验更佳。
4. 使用过 Bootstrap 或者 ElementUI 等 UI 库,并对前端 UI 库有一定的个人理解。
5. 了解 Git、Webpack 等工具。
6. 对 Java、Node.js 等后端编程有一定了解。
7. 一年及以上工作经验。
复制代码
  • 广州前端分析:
  1. 广州 13K 薪资要求:
    1. 2/3 年工作经验。
    2. 熟悉 OOP,并能在工作中使用,且能独立开发插件等……
    3. 你可以不懂 Vue,但 React 你必须得会!
  2. 广州 15k+ 薪资要求:
    1. 5 年+ 工作经验。
    2. 全能,懂前端,熟悉后端,能写文档……
    3. 带领过小队进行开发。
  3. 广州异常偏科公司:
    1. 要求必须懂后端。
    2. 要求必须懂安卓或者 IOS 开发。
    3. 要求必须精通 jQuery 全家桶(jQuery UI、jQuery Mobile 等……)。

该分析数据来自 Boss 直聘

2.4 开篇点题

返回目录

本文的知识点将涉及 HTML、CSS、JS、HTTP、Vue、Webpack、打包工具、性能优化等,没有前置条件,看得懂可以瞅瞅复习下,看不懂可以瞅瞅学习下。

关于面试,在这记下慕课网视频看到的,个人非常认同的三个问答:

  • 问:拿到一个面试题,第一时间看到什么? 答:考点
  • 问:如何看待网上搜出来的永远看不完的题海? 答:不变应万变
  • 问:如何对待面试题? 答:题目到知识再到题目

然后在复习面试题的过程中,个人有些小看法:

  • 个人感言一:为什么我总是比不上别人优秀?

当编写业务代码中,碰到某个业务 bug 时,我会习惯性地百度这个业务 bug,看看网友是怎么解决的。但是,学霸级的程序猿,会多走一步,他们会思考产生这个业务 bug 的底层原因是什么,下次碰到类似的是如何应用该技术解决。所以,日积月累,我的确比不上人家了。

  • 个人感言二:辞职并不是件便捷的事。

way 1:面试成功,跟自己公司递辞呈,走流程,同时跟对面 hr 申请一个月后入职。

way 2:面试成功,跟自己公司递辞呈,询问能不能快速离职,收到回复跟对面 hr 确认时间。【推荐】

way 3:先递辞呈,同时面试,面试成功的,一律申请走完原公司一个月的流程之后的日子入职。

jsliang 于 2 月底拿到 offer 并递交辞呈,3 月 - 4 月进入一个月倒计时,4 月第一周才能拿到离职证明。

最后在这里祝各位小伙伴能找到称心如意的工作~

三 HTML

返回目录

HTML 属于结构层,负责描绘出内容的结构。

CSS 属于表示层,负责如何显示有关内容。

JavaScript 属于行为层,负责内容应如何对事件做出反应。

3.1 HTML 学习推荐

返回目录

3.2 HTML 语义化

返回目录

语义化的含义就是用正确的标签做正确的事情,HTML 语义化就是让页面的内容结构化,它有如下优点:

  1. 便于对浏览器、搜索引擎解析;
  2. 便于盲人浏览网页;
  3. 便于阅读源代码的人对网站进行分开,维护和理解;

简单来说,能用 <header><footer> 等 H5 新标签的就不用 <div class="header">,不要使用 <div> 来存放段落等……

3.3 HTML5 新标签

返回目录

HTML5 中新增标签大致有:<header><footer><aside><nav><video><audio><canvas>等等。

3.4 常见浏览器及其内核

返回目录

Chrome Firefox Safari IE Opera
排版引擎 Blink Gecko Webkit Trident Blink
JS 引擎 V8 SpiderMonkey Nitro Chakra V8

国内一些浏览器使用较多的是 Webkit 内核。

  • 针对不同浏览器内核,HTML 辨别:
  1. IE 内核浏览器识别:<!--[if IE]><![endif]-->
  2. 非 IE 内核浏览器识别:<!--[if !IE]><![endif]-->
  • 针对不同浏览器内核,CSS 辨别:
/* 设置文字不可选取 */
* {
  -moz-user-select: none; /* 火狐 浏览器 */
  -webkit-user-select: none; /* Webkit 浏览器 */
  -o-user-select: none; /* Opera 浏览器 */
  -ms-user-select: none; /* IE10 浏览器 */
  -khtml-user-select: none; /* 早期浏览器 */
  user-select: none; /* 默认 */
}
复制代码

3.5 cookies、session、sessionStorage、localStorage

返回目录

  • cookies:存储于浏览器端的数据。可以设置 cookies 的到期时间,如果不设置时间,则在浏览器关闭窗口的时候会消失。

  • session:存储于服务器端的数据。session 存储特定用户会话所需的属性和配置信息。

  • cookiessession 的区别在于:

  1. cookies 数据存放在客户的浏览器上,session 数据存放在服务器上。
  2. 前端都是裸君子,没有安全可言,cookies 可能会被黑客利用作数据欺骗。所以重要信息记得存 session。
  3. session 如果在生效期内量过大,会占用服务器性能。
  4. 单个 cookies 保存的数据不能超过 4 K,很多浏览器限制一个站点保存最多 20 个 cookies。

  • sessionStorage:生命周期存在于标签页或窗口,用于本地存储一个会话(session)中的数据,这些数据会随着窗口或者标签页的关闭而被清空。

  • localStorage:生命周期是永久的,除非用户主动清除浏览器上存储的 localStorage 信息,否则它将会永久存在。

  • sessionStoragelocalStorage 操作方法:setItemgetItem 以及 removeItem

以 localStorage 为例:

localStorage.getItem('name'); // 获取 name 的值
localStorage.setItem('name', 'jsliang'); // 设置 name 的值为 jsliang
localStorage.removeItem('name'); // 删除 name 的值
复制代码

参考 1:《前端分享之cookie的使用及单点登录》
参考 2:《Cookie、session和localStorage、以及sessionStorage之间的区别》

四 CSS

返回目录

HTML 属于结构层,负责描绘出内容的结构。

CSS 属于表示层,负责如何显示有关内容。

JavaScript 属于行为层,负责内容应如何对事件做出反应。

4.1 CSS 学习推荐

返回目录

4.2 CSS reset

返回目录

在工作的过程中,会发现各式各样的浏览器对某个标签有自己独特的样式。

但是在前端开发中,如果不采用统一标准,那么会产生千奇百怪的 bug。所以为了减少后期 bug 的出现,前端开发人员会重置一遍 CSS 样式,尽可能地使开发的网页在各个浏览器相差不大。

下面是 jsliang 在使用的样式重置,当然如果小伙伴有不同的想法,可以去 百度/必应/google 搜索并使用其他版本的样式重置:

4.3 CSS 盒模型

返回目录

在工作的过程中,也许小伙伴需要 div 块的总宽度为 100px,然后发现总是被 margin 撑高,这是因为盒模型定义的问题:

CSS 中有个属性叫 box-sizing

box-sizing: border-box
box-sizing: content-box
复制代码
  1. border-box 中,整个 div 的宽、高,包括 marginpaddingborder
  2. content-box 中,整个 div 的宽、高,则不包括上面元素。

如上图,如果一个 div ,你的代码如下:

div {
  box-sizing: border-box;
  margin: 10px;
  width: 100px;
  height: 100px;
  padding: 10px;
}
复制代码

那么,你的整个宽高还是 100px

但是,如果你的代码如下:

div {
  box-sizing: content-box;
  margin: 10px;
  width: 100px;
  height: 100px;
  padding: 10px;
}
复制代码

那么,你的整个盒子宽高是 120px

如果你在设计页面中,发现内容区被撑爆了,那么,请检查下现在的 border-box 是什么,最好在引用 reset.css 的时候,就对 border-box 进行统一设置,方便管理。

4.4 CSS 单位

返回目录

在 CSS 中,除了我们常用的 px,还有其他单位小伙伴们可以了解一下:

单位 描述
% 百分比
px 像素。计算机屏幕上的一个点为 1px
em 相对单位。相对于父元素计算,假如某个 p 元素为 font-size: 12px,在它内部有个 span 标签,设置 font-size: 2em,那么,这时候的 span 字体大小为:12 * 2 = 24px
rem 相对单位。相对于根元素 html 的 font-size,假如 html 为 font-size: 12px,那么,在其当中的 div 设置为 font-size: 2rem,就是当中的 div 为 24px
rpx 微信小程序相对单位。1rpx = 屏幕宽度 / 750 px。在 750px 的设计稿上,1rpx = 1px。

除此之外还有 pt、ex 等单位,但由于不太好换算,故在此不提。

4.5 CSS 选择器

返回目录

选择器是匹配元素的一种模式。

  • 关于 CSS 解析器:

HTML 经过解析生成 DOM Tree;而在 CSS 解析完毕后,需要将解析的结果与 DOM Tree 的内容一起进行分析建立一棵 Render Tree,最终用来进行绘图。

Render Tree 中的元素与 DOM 元素相对应,但非一一对应:一个 DOM 元素可能会对应多个 renderer,如文本折行后,不同的「行」会成为 render tree 种不同的 renderer。也有的 DOM 元素被 Render Tree 完全无视,比如 display:none 的元素。

在建立 Render Tree 时,浏览器就要为每个 DOM Tree 中的元素根据 CSS 的解析结果来确定生成怎样的 renderer。对于每个 DOM 元素,必须在所有 Style Rules 中找到符合的 selector 并将对应的规则进行合并。选择器的「解析」实际是在这里执行的,在遍历 DOM Tree 时,从 Style Rules 中去寻找对应的 selector。

  • CSS 解析顺序

在 CSS 的选择器中,它会按照优先级 从右向左解析,因为这样匹配元素的时候,能尽量少地查找,所以选择器最好写地简洁一点。

  • CSS 常用选择器
  1. 通配符:*
  2. ID 选择器:#ID
  3. 类选择器:.class
  4. 元素选择器:pa 等……
  5. 后代选择器:p spandiv a 等……
  6. 伪类选择器:a:hover 等……
  7. 属性选择器:input[type="text"] 等……
  8. 子元素选择器:li:firth-childp:nth-child(1) 等……
  • CSS 选择器权重

!important -> 行内样式 -> #id -> .class -> 元素和伪元素 -> * -> 继承 -> 默认

4.6 CSS 常见布局

返回目录

  1. 水平垂直居中。这种布局老生常谈,jsliang 在本文也有提到,详解请 点击链接
  2. 两列布局。一侧固定,另一侧自适应。
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Two Column Layout</title>
  <style>
    .container {
      display: flex;
    }
    .child-one {
      width: 300px;
      height: 300px;
      background: red;
    }
    .child-two {
      width: 100%;
      height: 300px;
      background: deepskyblue;
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="child-one"></div>
    <div class="child-two"></div>
  </div>
</body>
</html>
复制代码
  1. 三列布局。类似于两列布局,新增多一个固定宽的 <div> 块而已。当然,小伙伴们可能会说:jsliang 你要考虑 flex 的兼容性啊!enm...支持所有最新版本的浏览器!请更新你的浏览器哦亲~

避免被寄刀片,附上 float 布局:《css常见布局》

4.7 CSS3 新特性

返回目录

经典:CSS3 相关属性你了解吗,说说都有哪些?能说说你工作中常用的一些 CSS3 属性吗?

那么,CSS3 新特性都有哪些呢?

  • transition:过渡
  • transform:旋转、缩放、移动或者倾斜
  • animation:动画
  • gradient:渐变
  • shadow:阴影
  • border-radius:圆角

为了方便记忆,咱将它们扔到同一个 HTML 文件上,小伙伴拷贝到本地上打开,可以看到一个拥有渐变的小球,做着横向运动,如果你鼠标移动到它上面,它的宽度会放大,并且进行倾斜。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"> 
<title>CSS3 新特性</title>
<style> 
  div {
    width: 100px;
    height: 100px;
    border-radius: 50px;
    background: linear-gradient(red, orange);
    box-shadow: 10px 10px 5px #888888;
    position: relative;
    transition: width 2s;
    animation: mymove 5s infinite;
  }
  div:hover {
    width:300px;
    transform: rotate(7deg);
  }
  @keyframes mymove {
    from { left: 0px; }
    to { left: 200px; }
  }
</style>
</head>
<body>
  <div></div>
</body>
</html>
复制代码

参考 1:《CSS3 圆角》
参考 2:《CSS3 渐变(Gradients)》
参考 3:《CSS3 transition 属性》
参考 4:《CSS3 transform 属性》
参考 5:《CSS3 animation(动画) 属性》
参考 6:《CSS3 box-shadow 属性》
参考 7:《个人总结(css3新特性)》

4.8 BFC

返回目录

  • 什么是 BFC?

BFC 就是 块级格式上下文,它是一个独立的渲染区域,让处于 BFC 内部的元素和外部的元素相互隔离,使内外元素的定位不会相互影响。

一定的 CSS 声明可以生成 BFC,浏览器对生成的 BFC 有一系列的渲染规则,利用这些渲染规则可以达到一定的布局效果。

  • 为什么需要 BFC 呢?
  1. 它可以防止 margin 元素重叠(div 中包含 ul,而 div 与 ul 之间的垂直距离,取决于 div、ul、li 三者之间的最大外边距,这时候给 ul 一个 display:inline-block 即可解决这个问题)
  2. 清除内部浮动(div 中包含 ul,而 ul 采用 float:left,那么 div 将变成一长条,这时候给 div 加上规则使其变成 BFC 即可)
  • 如何产生 BFC?
  1. display: inline-block
  2. position: absolute/fixed
  • 工作中一般可能不会顾及这个:
  1. float 很少使用了,尽可能使用 flex
  2. css reset 一般会清除掉一些问题,减少 BFC 的使用。

参考文献:《我对BFC的理解》

返回目录

4.9 行内元素和块级元素

返回目录

行内元素:宽度和高度由内容决定,与其他元素共占一行的元素,我们将其叫行内元素。例如:<span><i><a> 等……

块级元素:默认宽度由父容器决定,默认高度由内容决定,独占一行并且可以设置宽高的元素,我们将其叫做块级元素。例如:<p><div><ul> 等……

在日常开发中,我们经常使用 CSS 的 display 属性来打破两者的壁垒:display: inline-block,使它们拥有更多的状态。

4.10 行内样式、内嵌式、链接式以及导入式

返回目录

在引用 CSS 上,分为四种形式:行内样式内嵌式链接式以及导入式,下面介绍这四种模式。

  • 行内样式

直接对 HTML 的标记使用 style 属性,然后将 CSS 代码直接写进去:

<p style="color: #fff; backgournd: deepskyblue;"></p>
复制代码
  • 内嵌式

将 CSS 写 <head></head> 之间,并且用 <style></style> 标记进行声明:

<head>
  <style>
    p {
      color: #fff;
      background: deepskyblue;
    }
  </style>
</head>
复制代码
  • 链接式

通过将 <style> 上的 CSS 提起到指定的 CSS 文件上,然后通过 <link> 的方式在 HTML 上链接起来。

<head>
  <link href="reset.css" type="text/css" rel="stylesheet">
</head>
复制代码
  • 导入样式
<head>
  <style>
    @import url(reset.css);
  </style>
</head>
复制代码
  • 各种方式的优先级

在优先级上,行内样式 > 链接式 > 内嵌式 > @import 导入式

4.11 水平垂直居中

返回目录

  • 什么是 Flex 布局?

Flex 是 Flexible Box 的缩写,意为”弹性布局”,用来为盒状模型提供最大的灵活性。

  • Flex 布局有哪些便利
/* 设置 Flex 模式 */
display: flex;

/* 决定元素是横排还是竖着排,要不要倒序 */
flex-direction: column;

/* 决定元素换行格式,一行排不下的时候如何排 */
flex-wrap: wrap;

/* flex-flow = flex-direction + flex-wrap */
flex-flow: column wrap;

/* 同一排下对齐方式,空格如何隔开各个元素 */
justify-content: space-between;

/* 同一排下元素如何对齐,顶部对齐、中部对齐还是其他 */
align-items: center;

/* 多行对齐方式 */
align-content: space-between;
复制代码
  • 如何通过 Flex 实现元素水平垂直居中?

HTML

<div class="container">
  <div class="child"></div>
</div>
复制代码

CSS

.container {
  margin: 0 auto;
  width: 300px;
  height: 200px;
  background: deepskyblue;
  display: flex;
  /* 实现元素水平居中 */
  justify-content: center;
  /* 实现元素垂直居中 */
  align-items: center;
}
.child {
  width: 100px;
  height: 100px;
  background: #fff;
}
复制代码
  • 除了 Flex,还能使用其他形式进行水平垂直居中吗?

HTML

<div class="container">
  <div class="child"></div>
</div>
复制代码

CSS

.container {
  position: relative;
  width: 300px;
  height: 200px;
  background: pink;
  margin: 0 auto;
}
.child {
  position: absolute;
  width: 100px;
  height: 100px;
  top: 50%;
  left: 50%;
  /* 下面两种方式均可 */
  /* margin-top: -50px;
  margin-left: -50px; */
  transform: translate(-50%, -50%);
  background: #fff;
}
复制代码
  • 除此之外再谈谈 CSS 水平居中或者垂直居中?

水平居中:

  1. 行内元素:display: inline-block; text-align: center;
  2. 块级元素:margin: 0 auto;
  3. Flex:display: flex; justify-content: center;

垂直居中:

  1. 行高 = 元素高:line-height: height
  2. Flex:display: flex; align-items: center;

参考文献:
《CSS实现垂直居中的常用方法》
《CSS 用 position: absolute 与 transform 来居中块级元素的问题》

五 JavaScript

返回目录

HTML 属于结构层,负责描绘出内容的结构。

CSS 属于表示层,负责如何显示有关内容。

JavaScript 属于行为层,负责内容应如何对事件做出反应。

5.1 JS 学习推荐

返回目录

  • 《JavaScript 高级程序(第三版)》
  • 《你不知道的 JavaScript》
  • 《JavaScript 忍者秘籍》
  • 《ES6 标准入门》—— 阮一峰
  • 《JavaScript 设计模式》—— 张容铭
  • 《JavaScript 设计模式与开发实践》—— 曾探

5.2 JS 引用方式

返回目录

  • 行内引入
<body>
  <input type="button" onclick="alert('行内引入')" value="按钮"/>
  <button onclick="alert(123)">点击我</button>
</body>
复制代码
  • 内部引入
<script>
  window.onload = function() {
    alert("js 内部引入!");
  }
</script>
复制代码
  • 外部引入
<body>
  <div></div>

  <script type="text/javascript" src="./js/index.js"></script>
</body>
复制代码

注意

  1. 不推荐写行内或者在 HTML 中插入 <script>,因为浏览器解析顺序缘故,如果解析到死循环之类的 JS 代码,会卡住页面。
  2. 建议在 onload 事件之后,即等 HTML、CSS 渲染完毕再执行代码。

5.3 原型与原型链

返回目录

关于 prototype__proto__newcall()apply()bind()this 这些的知识点,由于篇幅太长,jsliang 已经抽离了出来,并做了简洁详细讲解,详见:

下面放出相关知识点:

  • 实例的 __proto__ 属性(原型)等于其构造函数的 prototype 属性。
  • Object.proto === Function.prototype
  • Function.prototype.proto === Object.prototype
  • Object.prototype.proto === null

5.4 作用域与闭包

返回目录

在 JS 中,最容易混淆的就是作用域的情况。

在传统的后端语言(例如 C 语言)中,一对花括号 {} 就是一个块级作用域,作用域内变量不会相互影响,但是在 JS 中,像 if 条件语句的 {} 就不算一个独立的作用域:

var x = 1;
console.log(x); // 1
if(true) {
  var x = 2;
  console.log(x); // 2
}
console.log(x); // 2
复制代码

所以有时候我们就需要变通,通过自执行函数创建临时作用域:

function foo() {
  var x = 1;
  console.log(x); // 1
  if(x) {
    (function(x) {
      console.log(x); // 1
      var x = 2;
      console.log(x); // 2
    })(x)
  }
  console.log(x); // 1
}
foo();
复制代码

说到创建临时作用域,我们就不得不谈一下闭包。

那么,什么是闭包呢?

闭包简单定义:函数 A 里面包含了 函数 B,而 函数 B 里面使用了 函数 A 的变量,那么 函数 B 被称为闭包。

又或者:闭包就是能够读取其他函数内部变量的函数

function A() {
  var a = 1;
  function B() {
    console.log(a);
  }
  return B();
}
复制代码
  • 闭包经典问题:现在我们有一段代码:
for(var i = 0; i < 3; i++) {
  setTimeout(function() {
    console.log(i);
  }, 1000);
}
复制代码

请问这段代码输出什么?

答案:3 个 3。
解析:首先,for 循环是同步代码,先执行三遍 for,i 变成了 3;然后,再执行异步代码 setTimeout,这时候输出的 i,只能是 3 个 3 了。

  • 那么,我们有什么办法依次输出 0 1 2 么?
  1. 使用 let:
for(let i = 0; i < 3; i++) {
  setTimeout(function() {
    console.log(i);
  }, 1000);
}
复制代码

在这里,每个 let 和代码块结合起来形成块级作用域,当 setTimeout() 打印时,会寻找最近的块级作用域中的 i,所以依次打印出 0 1 2。

如果这样讲不明白,我们可以执行下下面这段代码:

for(let i = 0; i < 3; i++) {
  console.log("定时器外部:" + i);
  setTimeout(function() {
    console.log(i);
  }, 1000);
}
复制代码

此时浏览器依次输出的是:

定时器外部:0
定时器外部:1
定时器外部:2
0
1
2
复制代码

即代码还是先执行 for 循环,但是当 for 结束执行到了 setTimeout 的时候,它会做个标记,这样到了 console.log(i) 中,i 就能找到这个块中最近的变量定义。

  1. 使用立即执行函数解决闭包问题
for(let i = 0; i < 3; i++) {
  (function(i){
    setTimeout(function() {
      console.log(i);
    }, 1000);
  })(i)
}
复制代码

以上,我们就讲解完了闭包及解决闭包的方式。

观点 1:有些资料表示闭包中产生的大量局部变量,会造成内存消耗过大,从而造成网页的性能问题。
观点 2:有些资料表示目前浏览器引擎都基于 V8,而 V8 引擎有个 gc 回收机制,不用太过担心变量不会被回收。
提示:所以,如果你觉得不够保险,那就在退出函数之前,将不使用的局部变量全部删除。

5.5 浅拷贝与深拷贝

返回目录

  • 什么是深拷贝?什么是浅拷贝?

简单来说,有两个对象 A 和 B,B = A,当你修改 A 时,B 的值也跟着发生了变化,这时候就叫浅拷贝。如果不发生变化,就叫深拷贝。

  • 为什么会出现深拷贝与浅拷贝?
  1. 首先我们需要知道基本数据类型(number、string、boolean、null、undefined)引用数据类型(无序对象,数据以及函数)
  2. 然后在基本数据类型中,例如:let a = 1; let b = a; a = 2; console.log(b)。当我们尝试这样子写时,b 在栈内存中开辟了一个新内存,所以 b 的值不会改变,仍是 1.
  3. 接着在引用数据类型中,例如 let a = [1, 2, 3], b = a; a[0] = 3; console.log(b)。当我们尝试这样子写时,b 会偷懒,引用跟 a 同一块的内存地址,从而 a 的修改会影响 b,使得 b 变成 [3, 1, 3]。
  4. 最后,我们可以知道在引用数据类型中,会产生浅拷贝的问题。
  • 如何实现深拷贝?
  1. 首先我们尝试使用递归去解决深拷贝:
function deepClone(obj) {
  let objClone = Array.isArray(obj) ? [] : {};
  if(obj && typeof obj === "object") {
    for(key in obj) {
      if(obj.hasOwnProperty(key)) {
        // 判断 obj 子元素是否为对象,如果是,递归复制
        if(obj[key] && typeof obj[key] === "object") {
          objClone[key] = deepClone(obj[key]);
        } else {
          // 如果不是,简单复制
          objClone[key] = obj[key];
        }
      }
    }
  }
  return objClone;
}

let a = [1, 2, 3, 4];
let b = deepClone(a);
a[0] = 2;
console.log(a, b);

// Console
// a = [2, 2, 3, 4];
// b = [1, 2, 3, 4];
复制代码
  1. 使用 JSON 对象的 parse 和 stringify

注意:采用 JSON 进行的深拷贝,无法拷贝到 undefined、function、symbol 这类数据,它是有小 bug 的深拷贝。

function deepClone(obj) {
 let _obj = JSON.stringify(obj);
 let objClone = JSON.parse(_obj);
 return objClone
}
let a = [0, 1, [2, 3], 4];
let b = deepClone(a);
a[0] = 1;
a[2][0] = 1;
console.log(a, b);

// Console
// a = [1, 1, [1, 3], 4];
// b = [0, 1, [2, 3], 4];
复制代码

5.6 模块化与组件化

返回目录

在前端发展中,随着前后端分离,前端社区的不断壮大,前端能做的事情越来越多,承受的任务越来越重,代码也就越来越长了。就好比 jsliang 个人使用 jQuery 开发的时候,动不动就上千行代码,这在一个编辑器上看起来就有点乱了。如果碰上没有代码折叠的编辑器,你就更加难受了。

有的小伙伴的编辑器不是 VS Code,也不能进行代码折叠

所以,面对越来越多的代码,我们就急需将这些代码分门别类,将代码按功能划分,将同一功能的代码整合在一起,于是就有了模块化开发:一个文件就是一个模块,当我们需要某个文件的时候,我们只需要引用这个模块即可……

首先,是 CommonJS 的提出,在 Node.js 以及 Webpack 都支持 CommonJS,它规定了一个文件就是一个模块,文件内部定义的变量属于这个模块,不会对外暴露从而污染全局变量的规则。在 CommonJS 中,通过 exports 或者 module.exports 进行导出,通过 require 进行 同步加载 所需要依赖的模块。由于它是同步加载模块的形式,所以比较通用于服务器端。

然后,根据 CommonJS 只能同步加载的问题,AMD 根据浏览器的特性,进行了非同步加载模块的提出。同时,AMD 有个问题,就是在使用 require.js 的时候,必须提前加载所有模块。

接着,根据 AMD 的问题,CMD 提出来了:通过按需加载的形式,哪里需要就调用哪里,而不用等到所有的模块都加载了再解析。

最后,ECMA 国际推出了 ES6 的 modules。在 ES6 中,通过 export 关键字导出模块,通过 import 关键字引用代码。当然,由于浏览器厂商诸多,ES6 在浏览器的尚不支持,目前主流做法是先将 ES6 通过 babel 编译成 require。

当然,JS 都进行模块化了,jsliang 想起自己项目中的那一坨 CSS,真心没有回顾的想法!所以我们还需要知道为了方便管理 CSS,大佬们还是有做事儿的:Less 以及 Sass,这两者使 CSS 的编写更有组织性和目的性了。

说起模块化,我们又可以顺带提及组件化了,一开始为了区分这两者,jsliang 也是百度了大量文章,最后成功把自己整蒙了,还是说说感觉可以的解释:

组件化更关注的是 UI 部分:弹出框、头部,内容区、按钮等,都可以编写成组件,然后在适用的地方进行引用。而模块化更侧重于功能或者数据的封装,比如全局的 JSON 配置文件,比如通用的验证方法,比如规范时间戳等。

所以,说到这里,我们就可以提到前端工程化:将整个开发流程就行工程规划,从而提高整个团队的开发效率。

在前端工程化中,最重要的就是提高整个团队在 编码 -> 测试 -> 维护 这三个阶段的生产效率。团队的协调至关重要,将每个任务细分给各个成员,从而获取极致的工作效率,是管理者最喜欢看到的。而在上面的模块化和组件化的应用,就属于前端工程化中的一部分,其目的就是在一些复杂的项目中,方便团队进行合作开发,提高生产效率。

参考文献:
《到底什么是前端工程化、模块化、组件化》
《【前端工程化系列】简谈前端模块化开发与开发规范》
《个人关于模块化的理解》
《组件化开发和模块化开发概念辨析》
《JavaScript模块化 --- Commonjs、AMD、CMD、es6 modules》
《浅谈什么是前端工程化》

5.7 面向对象与面向过程

返回目录

  1. 什么是面向过程与面向对象?
  • 面向过程就是做围墙的时候,由你本身操作,叠第一层的时候:放砖头,糊水泥,放砖头,糊水泥;然后第二层的时候,继续放砖头,糊水泥,放砖头,糊水泥……
  • 面向对象就是做围墙的时候,由他人帮你完成,将做第一层的做法抽取出来,就是放砖头是第一个动作,糊水泥是第二个动作,然后给这两个动作加上步数,最后告诉机器人有 n 层,交给机器人帮你工作就行了。
  1. 为什么需要面向对象写法?
  • 更方便
  • 可以复用,减少代码冗余度
  • 高内聚低耦合

简单来说,就是增加代码的可复用性,减少咱们的工作,使代码更加流畅。

  1. 手写个面向对象代码?
function Person(name, phone) {
  this.name = name;
  this.phone = phone;
  this.eat = function() {
    console.log(name + " 吃饭");
  }

  return this;
}

let p1 = new Person("jsliang", "18818881888");
console.log(p1.name); // jsliang
p1.eat(); // jsliang 吃饭
复制代码

当然,jsliang 只能写到这里了,再写下去就是设计模式等知识点了。

所以希望小伙伴们还是了解下面向对象思想,有助于进一步提升自己。

5.8 防抖与节流

返回目录

关于 防抖与节流jsliang 特意将资料结合起来:

  • 防抖与节流
  • 重绘与回流
  • 浏览器解析 URL
  • DNS 域名解析
  • TCP 三次握手与四次挥手
  • 浏览器渲染页面

小伙伴们可以前往 《面试知识点 - JS 防抖与节流》 查看。

5.9 ES6

返回目录

ES6 是个大知识点,如果你面试的公司不是 “饱经沧桑” 的那种,那么一定会出点 ES6 问题,例如:

  • 说说 let、var、const 区别
  • 讲讲 Promise 及其使用

因为 jsliang 感觉自己连 ES6 的门还没进,所以在这里就不 自作聪明,推荐下阮一峰大佬的教程:

希望小伙伴们看完能有所收获,并在工作中大量使用。

5.10 数组操作

返回目录

在 JavaScript 中,用得较多的之一无疑是数组操作,这里过一遍数组的一些用法:

  • map: 遍历数组,返回回调返回值组成的新数组
  • forEach: 无法break,可以用try/catch中throw new Error来停止
  • filter: 过滤
  • some: 有一项返回true,则整体为true
  • every: 有一项返回false,则整体为false
  • join: 通过指定连接符生成字符串
  • push / pop: 末尾推入和弹出,改变原数组, 返回推入/弹出项【有误】
  • unshift / shift: 头部推入和弹出,改变原数组,返回操作项【有误】
  • sort(fn) / reverse: 排序与反转,改变原数组
  • concat: 连接数组,不影响原数组, 浅拷贝
  • slice(start, end): 返回截断后的新数组,不改变原数组
  • splice(start, number, value...): 返回删除元素组成的数组,value 为插入项,改变原数组
  • indexOf / lastIndexOf(value, fromIndex): 查找数组项,返回对应的下标
  • reduce / reduceRight(fn(prev, cur), defaultPrev): 两两执行,prev 为上次化简函数的return值,cur 为当前值(从第二项开始)

相信小伙伴在工作中耍的已经是一套一套的了,或者像 jsliang 一样只会简单的使用 pushmap 这几个,感兴趣的小伙伴可以 百度/bing/google 找找一些 奇技淫巧,说不定对工作效率有很大提升~

六 Vue

返回目录

推荐:

  1. 技术胖
  2. 慕课网

6.1 MVVM

返回目录

在 MVVM 架构下,View 和 Model 之间并没有直接的联系,而是通过 ViewModel 进行交互,Model 和 ViewModel 之间的交互时双向的,因此 View 数据会同步到 Model 中,而 Model 数据的变化也会立即反应到 View 上。

ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而 View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需要关注业务逻辑,不需要手动操作 DOM,不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。

  1. M - Model。Model 代表数据模型,也可以在 Model 中定义数据修改和操作的业务逻辑。
  2. V - View。View 代表 UI 组件,它负责将数据模型转化为 UI 展现出来。
  3. VM - ViewModel。ViewModel 监听模型数据的改变和控制视图行为、处理用户交互,简单理解就是一个同步 View 和 Model 的对象,连接 Model 和 View。

6.2 生命周期

返回目录

  • 请大致讲下 Vue 的生命周期?
  1. 创建前/后:在 beforeCreated 阶段,Vue 实例的挂载元素 $el 和数据对象 data 以及事件还未初始化。在 created 阶段,Vue 实例的数据对象 data 以及方法的运算有了,$el 还没有。
  2. 载入前/后:在 beforeMount 阶段,render 函数首次被调用,Vue 实例的 $el 和 data 都初始化了,但还是挂载在虚拟的 DOM 节点上。在 mounted 阶段,Vue 实例挂载到实际的 DOM 操作完成,一般在该过程进行 Ajax 交互。
  3. 更新前/后:在数据更新之前调用,即发生在虚拟 DOM 重新渲染和打补丁之前,调用 beforeUpdate。在虚拟 DOM 重新渲染和打补丁之后,会触发 updated 方法。
  4. 销毁前/后:在执行实例销毁之前调用 beforeDestory,此时实例仍然可以调用。在执行 destroy 方法后,对 data 的改变不会再触发周期函数,说明此时 Vue 实例已经解除了事件监听以及和 DOM 的绑定,但是 DOM 结构依然存在。
  • 什么是 Vue 生命周期?

Vue 实例从创建到销毁的过程,就是生命周期。从开始创建、初始化数据、编译模板、挂载 DOM -> 渲染、更新 -> 渲染、销毁等一系列过程,称之为 Vue 的生命周期。

  • Vue 有几个生命周期,它们的作用主要是什么?

8 个,创建前/创建后、挂载前/挂载后、更新前/更新后、销毁前/销毁后。Vue 生命周期的作用是方便我们通过它的生命周期,在业务代码中更好地操作数据,实现相关功能。

  • 第一次页面加载会触发 Vue 哪几个钩子?

会触发 4 个生命钩子:创建前/创建后、挂载前/挂载后

  • DOM 渲染在哪个周期就已经完成?

beforeMounted 时它执行了 render 函数,对 $el 和 data 进行了初始化,但此时还是挂载到虚拟的 DOM 节点,然后它在 mounted 时就完成了 DOM 渲染,这时候我们一般还进行 Ajax 交互。

6.3 双向数据绑定

返回目录

Vue 采用 数据劫持 结合 发布者-订阅者 模式的方式,通过 Object.defineProperty() 来劫持各个属性的 setter 以及 getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

  1. 第一步:需要 Observe 的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter 和 getter。这样的话,给这个对象的某个值赋值,就会触发 setter,那么就能监听到了数据变化。
  2. 第二步:Compile 解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新数据。
  3. 第三步:Watcher 订阅者是 Observer 和 Compile 之间通信的桥梁,主要做的事情有:
    1. 在自身实例化时往属性订阅器(dep)里面添加自己。
    2. 自身必须有一个 update() 方法
    3. 待属性变动 dep.notice() 通知时,能调用自身的 update() 方法,并触发 Compile 中绑定的回调,则功成身退。
  4. 第四步:MVVM 作为数据绑定的入口,整合 Observer、Compile 和 Watcher 三者,通过 Observer 来监听自己的 model 数据变化,通过 Compile 来解析编译模板指令,最终利用 Watcher 搭起 Observer 和 Compile 之间的桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据 model 变更的双向绑定效果。

js 实现简单的双向绑定

<body>
  <div id="app">
    <input type="text" id="txt">
    <p id="show"></p>
  </div>
  
  <script>
    window.onload = function() {
      let obj = {};
      Object.defineProperty(obj, "txt", {
        get: function() {
          return obj;
        },
        set: function(newValue) {
          document.getElementById("txt").value = newValue;
          document.getElementById("show").innerHTML  = newValue;
        }
      })
      document.addEventListener("keyup", function(e) {
        obj.txt = e.target.value;
      })
    }
  </script>
</body>
复制代码

Object.defineProperty 接收三个参数:对象,属性名,配置对象
这里使用的是 Object.defineProperty,这是 Vue 2.0 进行双向数据绑定的写法。在 Vue 3.0 中,它使用 Proxy 进行数据劫持。

  • 为什么 Vue 3.0 中使用 Proxy 了?
  1. Vue 中使用 Object.defineProperty 进行双向数据绑定时,告知使用者是可以监听数组的,但是只是监听了数组的 push()、pop()、shift()、unshift()、splice()、sort()、reverse() 这八种方法,其他数组的属性检测不到。
  2. Object.defineProperty 只能劫持对象的属性,因此对每个对象的属性进行遍历时,如果属性值也是对象需要深度遍历,那么就比较麻烦了,所以在比较 Proxy 能完整劫持对象的对比下,选择 Proxy。
  3. 为什么 Proxy 在 Vue 2.0 编写的时候出来了,尤大却没有用上去?因为当时 es6 环境不够成熟,兼容性不好,尤其是这个属性无法用 polyfill 来兼容。(polyfill 是一个 js 库,专门用来处理 js 的兼容性问题-js 修补器)

参考自《实现双向绑定Proxy比defineproperty优劣如何》

6.4 Virtual DOM

返回目录

Vue 在 rendercreateElement 的时候,并不是产生真实的 DOM 元素,实际上 createElement 描述为 createNodeDescription,因为它所包含的信息会告诉 Vue 页面上需要渲染什么样的节点。

因此,我们将这样的节点描述为 “虚拟节点”(Virtual Node),简称 VNode。“虚拟 DOM” 是我们对由 Vue 组件树建立的整个 VNode 树的称呼。

作为一枚切图仔,很荣幸地跟小伙伴说:“其实我也不懂 Virtual DOM!”

但是,总会有些面试场合会提到的,所以这里找了几篇资料,小伙伴们可以进一步学习:

其他的就需要小伙伴自己寻找了,如果觉得有不错的解析 Virtual DOM 的文档/视频,小伙伴也可以推荐过来哈~

6.5 template 编译

返回目录

  • Vue template 编译的理解

Vue 中 template 就是先转化成 AST 树,再得到 render 函数返回 VNode(Vue 的虚拟 DOM 节点)。

  1. 通过 compile 编译器把 template 编译成 AST 语法树(abstract syntax tree - 源代码的抽象语法结构的树状表现形式),compile 是 createCompiler 的返回值,createCompiler 是用以创建编译器的。另外 compile 还负责合并 option。
  2. AST 会经过 generate(将 AST 语法树转换成 render function 字符串的过程)得到 render 函数,render 的返回值是 VNode,VNode 是 Vue 的虚拟 DOM 节点,里面有标签名、子节点、文本等待。

6.6 key

返回目录

key 的作用就是在更新组件时判断两个节点是否相同。相同就复用,不相同就删除旧的创建新的。

对于 diff 过程来说 key 是起不到提速作用的,详见:key 的作用

6.7 nextTick

返回目录

  • 用法:Vue.nextTick( [callback, context] )

  • 参数:

    • {Function} [callback]
    • {Object} [context]
  • 说明:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

  • 案例:

// 修改数据
vm.msg = 'Hello'
// DOM 还没有更新
Vue.nextTick(function () {
  // DOM 更新了
})

// 作为一个 Promise 使用 (2.1.0 起新增,详见接下来的提示)
Vue.nextTick().then(function () {
  // DOM 更新了
})
复制代码

关于 nextTick 的更多理解,jsliang 就不献丑了,需要学习的小伙伴可以查看:

或者自行查找更优秀的资源。

6.8 父子组件通讯

返回目录

关于 Vue 中的父子组件通讯,相信经常开发 Vue 的小伙伴比 jsliang 知道的多很多。

没怎么使用 Vue 的小伙伴可以看下下面的文章,并尝试自己写一写:

下面咱讲下使用 bus.js 实现非父子组件通讯:

假设在工作中,有三个 .vue 文件:A.vue、B.vue、C.vue。A.vue 是主页面,B.vue 和 C.vue 类似于头部导航条和底部导航栏。现在,B.vue 点击会切换路由,C.vue 需要获取 B.vue 传递的信息。

A.vue

<template>
  <div>
    <top-nav></top-nav>
    <div class="container">
      <router-view></router-view>
    </div>
    <bottom-nav></bottom-nav>
  </div>
</template>
复制代码

bus.js

import Vue from 'vue';

// 使用 Event Bus
const bus = new Vue();

export default bus;
复制代码

B.vue

<template>
  <div class="bottom-nav">
    <div class="nav-one" @click="goToPage({path: '/HomeIndex', meta:'首页'})">
      <i class="icon-home"></i>
      <span>首页</span>
    </div>
  </div>
</template>

<script>
  import bus from '../utils/bus'
  export default {
    methods: {
      goToPage(route) {
        this.$router.push(route.path);
        bus.$emit('meta', route.meta);
      }
    }
  }
</script>
复制代码

C.vue

<template>
  <div class="top-nav">
    <span class="title">{{title}}</span>
  </div>
</template>

<script>
  import bus from '../utils/bus'
  export default {
    data() {
      return {
        title: ''
      }
    },
    created() {
      bus.$on('meta', msg=> {
        this.title = msg;
      })
    }
  }
</script>
复制代码

七 微信小程序

返回目录

微信小程序,简称小程序,英文名 Mini Program,是一种不需要下载安装即可使用的应用,它实现了应用“触手可及”的梦想,用户扫一扫或搜一下即可打开应用。

7.1 文件主要目录及文件作用

返回目录

- component —————————————————— 组件文件夹
  - navBar                  —— 底部组件
    - navBar.js             —— 底部组件的 JS 代码
    - navBar.json           —— 底部组件的配置文件
    - navBar.wxml           —— 底部组件的 HTML 代码
    - navBar.wxss           —— 底部组件的 CSS 代码
- pages  ————————————————————— 页面文件夹
  - index                   —— 首页
    - index.js              —— 首页的 JS 代码
    - index.json            —— 首页的配置文件
    - index.wxml            —— 首页的 HTML 代码
    - index.wxss            —— 首页的 CSS 代码
- public ————————————————————— 图片文件夹
- utils —————————————————————— 工具文件夹
  - api.js                  —— 控制 API 的文件
  - md5.js                  —— 工具 - MD5 加密文件
  - timestamp.js            —— 工具 - 时间戳文件
- app.json ——————————————————— 设置全局的基础数据等
- app.wxss ——————————————————— 公共样式,可通过 import 导入更多
- project.config.json ———————— 项目配置文件
复制代码

7.2 微信小程序生命周期

返回目录

  • onLoad():页面加载时触发。
  • onShow():页面显示/切入前台时触发。
  • onReady():页面初次渲染完成时触发。
  • onHide():页面隐藏/切入后台时触发。
  • onUnload():页面卸载时触发。

7.3 如何封装数据请求

返回目录

  1. 封装接口:

项目/utils/api.js

// 将请求进行 Promise 封装
const fetch = ({url, data}) => {

  // 打印接口请求的信息
  console.log(`【step 1】API 接口:${url}`);
  console.log("【step 2】data 传参:");
  console.log(data);

  // 返回 Promise
  return new Promise((resolve, reject) => {
    wx.request({
      url: getApp().globalData.api + url,
      data: data,
      success: res => {
        
        // 成功时的处理 
        if (res.data.code == 0) {
          console.log("【step 3】请求成功:");
          console.log(res.data);
          return resolve(res.data);
        } else {
          wx.showModal({
            title: '请求失败',
            content: res.data.message,
            showCancel: false
          });
        }

      },
      fail: err => {
        // 失败时的处理
        console.log(err);
        return reject(err);
      }
    })
  })

}

/**
 * code 换取 openId
 * @data {
 *   jsCode - wx.login() 返回的 code
 * }
 */
export const wxLogin = data => {
  return fetch({
    url: "tbcUser/getWechatOpenId",
    data: data
  })
}
复制代码
  1. 调用接口:

项目/pages/login/login.js

import {
  wxLogin,
} from '../../utils/api.js'
复制代码
  1. 使用接口:

项目/pages/login/login.js

wxLogin({
  jsCode: this.data.code
}).then(
  res => {
    console.log("【step 4】返回成功处理:");
    console.log(res.data);
  },
  err => {
    console.log("【step 4】返回失败处理:");
    console.log(err);
  }
)
复制代码

7.4 页面数据传递

返回目录

  1. 通过 url 携带参数,在 onLoad() 中通过 options 获取 url 上的参数:

代码演示

<navigator url="../index/index?userId={{userId}}"></navigator>

<!-- 这两段是分别在 HTML 和 JS 中的代码 -->

onLoad: function(options) {
  console.log(options.userId);
}
复制代码
  1. 通过 Storage 来传递参数:
wx.setStorageSync('userId', 'jsliang');
wx.getStorageSync('userId');
复制代码
  1. WXML 传递数据到 JS

login.wxml

<text bindtap="clickText" data-labelId="{{userId}}">点击传递数据到 JS</text>
复制代码

login.js

clickText(e) {
  console.log(e.currentTarget.labelid)
}
复制代码
  1. 组件调用传参

组件接收数据:component-tag-name

Component({
  properties: {
    // 这里定义了innerText属性,属性值可以在组件使用时指定
    innerText: {
      type: String,
      value: 'default value',
    }
  }
})
复制代码

使用组件的页面定义 json

{
  "usingComponents": {
    "component-tag-name": "../component/component"
  }
}
复制代码

使用组件的页面 HTML 代码

<view>
  <!-- 以下是对一个自定义组件的引用 -->
  <component-tag-name inner-text="Some text"></component-tag-name>
</view>
复制代码
  1. 通过接口调用传递参数

7.5 加载性能优化的方法

返回目录

  1. 通过 this.$preload() 预加载用户可能点击的第二个页面。
  2. 组件化页面,出现两次以上的部分都进行封装成组件。
  3. 提取共用的 CSS 样式。
  4. 优化图片:TinyPNG

7.6 微信小程序与原生 APP、Vue、H5 差异

返回目录

  • 微信小程序优劣势:

优势

  1. 无需下载
  2. 打开速度较快
  3. 开发成本低于原生 APP

劣势

  1. 限制多。页面大小不能超过 1M,不能打开超过 5 个层级的页面。
  2. 样式单一。小程序内部组件已经成宿,样式不可以修改。
  3. 推广面窄。跑不出微信,还不能跑入朋友圈。
  • 微信小程序 VS 原生 APP

微信小程序有着低开发成本、低获客成本、无需下载的优势。

  • 微信小程序 VS H5
  1. 依赖环境不同。一个能在多种手机浏览器运行。一个只能在微信中的非完整的浏览器。
  2. 开发成本不同。一个可能在各种浏览器出问题。一个只能在微信中运行。
  • 微信小程序 VS Vue

微信小程序看似就是阉割版的 Vue。

7.7 微信小程序原理

返回目录

  1. 本质上就是一个单页面应用,所有的页面渲染和事件处理,都在一个页面中进行。
  2. 架构为数据驱动的模式,UI 和数据分离,所有页面的更新,都需要通过对数据的更改来实现。
  3. 微信小程序分为两个部分:webview 和 appService。其中 webview 主要用来展示 UI,appServer 用来处理业务逻辑、数据及接口调用。它们在两个进程中进行,通过系统层 JSBridge 实现通信,实现 UI 的渲染、事件的处理。

八 浏览器

返回目录

8.1 浏览器解析 URL

返回目录

关于 浏览器解析 URLjsliang 特意将资料结合起来:

  • 防抖与节流
  • 重绘与回流
  • 浏览器解析 URL
  • DNS 域名解析
  • TCP 三次握手与四次挥手
  • 浏览器渲染页面

小伙伴们可以前往 《面试知识点 - JS 防抖与节流》 查看。

8.2 重绘与回流

返回目录

关于 重绘与回流jsliang 特意将资料结合起来:

  • 防抖与节流
  • 重绘与回流
  • 浏览器解析 URL
  • DNS 域名解析
  • TCP 三次握手与四次挥手
  • 浏览器渲染页面

小伙伴们可以前往 《面试知识点 - JS 防抖与节流》 查看。

8.3 数据存储

返回目录

  1. 存储于代码中,代码执行完毕释放内存。
  2. 存储于浏览器中,cookie 用于短期存储用户身份,登录状态等较小的信息;localStorage/sessionStorage 用于长期存储数据,浏览器关闭不影响它们的内存,相比于 cookie,storage 能存储较多;IndexedDB 是浏览器提供的接近于 NoSQL 的数据库,允许存储大量数据。
  3. 存储于数据库中。

8.4 内存管理与垃圾回收

返回目录

V8 将内存分为两类:新生代内存空间和老生代内存空间。

  • 新生代内存空间:主要用来存放存活时间较短的对象。
  • 老生代内存空间:主要用来存放存活时间较长的对象。

这两者通过不同的算法,对内存进行管理操作。

8.5 内存泄漏

返回目录

  • 意外的全局变量:无法被回收。

  • 定时器:未被正确关闭,导致所引用的外部变量无法被释放。

  • 事件监听:没有正确销毁(低版本浏览器可能出现)。

  • 闭包:会导致父级中的变量无法被释放。

  • DOM 引用:DOM 被删除时,内存中的引用未被正确清空。

  • 如何查看内存变化情况?

使用 Chrome 的 Timeline(新版本 Performance)进行内存标记,可视化查看内存的变化情况,找出异常点。

九 网络协议

返回目录

9.1 网络分层

返回目录

目前网络分层可分为两种:OSI 模型和 TCP/IP 模型。

  • OSI 模型
  1. 应用层(Application)
  2. 表示层(Presentation)
  3. 会话层(Session)
  4. 传输层(Transport)
  5. 网络层(Network)
  6. 数据链路层(Data Link)
  7. 物理层(Physical)
  • TCP/IP 模型
  1. 应用层(Application)
  2. 传输层(Host-to-Host Transport)
  3. 互联网层(Internet)
  4. 网络接口层(Network Interface)

更多详情可以查看下面这篇文章,里面讲得非常详细:

9.2 HTTP/HTTPS

返回目录

  • HTTP:超文本传输协议(HTTP)是用于分布式,协作式和超媒体信息系统的应用协议。它是Web上数据交换的基础,是一种 client-server 协议,也就是说请求通常是由像浏览器这样的接受方发起的。
  • HTTPS:HTTPS(全称:Hypertext Transfer Protocol over Secure Socket Layer),是以安全为目标的 HTTP 通道,简单讲是 HTTP 的安全版。即 HTTP 下加入 SSL 层,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。 它是一个 URI scheme(抽象标识符体系),句法类同 http: 体系。用于安全的HTTP数据传输。https:URL 表明它使用了 HTTP,但 HTTPS 存在不同于 HTTP 的默认端口及一个加密/身份验证层(在 HTTP 与 TCP 之间)。这个系统的最初研发由网景公司进行,提供了身份验证与加密通讯方法,现在它被广泛用于万维网上安全敏感的通讯,例如交易支付方面。

9.3 HTTP 状态码

返回目录

首先,我们大致区分下状态码:

  1. 1**开头 - 信息提示
  2. 2**开头 - 请求成功
  3. 3**开头 - 请求被重定向
  4. 4**开头 - 请求错误
  5. 5**开头 - 服务器错误

然后,常见的状态码:

  1. 200 - 请求成功,Ajax 接受到信息了。
  2. 400 - 服务器不理解请求,工作中常见于跨域的时候后端给我报 400!
  3. 403 - 服务器拒绝请求。
  4. 404 - 请求页面错误。
  5. 500 - 服务器内部错误,无法完成请求。

最后,小伙伴们如果想要了解更多,还是需要自行查找资料的。

9.4 TCP 三次握手与四次挥手

返回目录

关于 TCP 三次握手与四次挥手jsliang 特意将资料结合起来:

  • 防抖与节流
  • 重绘与回流
  • 浏览器解析 URL
  • DNS 域名解析
  • TCP 三次握手与四次挥手
  • 浏览器渲染页面

小伙伴们可以前往 《面试知识点 - JS 防抖与节流》 查看。

十 性能优化

返回目录

通过优化从而提高页面的加载速度。

10.1 HTML 优化

返回目录

  1. 避免 HTML 中书写 CSS 代码,因为这样难以维护。
  2. 使用 Viewport 加速页面的渲染。
  3. 使用语义化标签,减少 CSS 代码,增加可读性和 SEO。
  4. 减少标签的使用,DOM 解析是一个大量遍历的过程,减少不必要的标签,能降低遍历的次数。
  5. 避免 src、href 等的值为空,因为即时它们为空,浏览器也会发起 HTTP 请求。
  6. 减少 DNS 查询的次数。

10.2 CSS 优化

返回目录

  1. 优化选择器路径:使用 .c {} 而不是 .a .b .c {}
  2. 选择器合并:共同的属性内容提起出来,压缩空间和资源开销。
  3. 精准样式:使用 padding-left: 10px 而不是 padding: 0 0 0 10px
  4. 雪碧图:将小的图标合并到一张图中,这样所有的图片只需要请求一次。
  5. 避免通配符:.a .b * {} 这样的选择器,根据从右到左的解析顺序在解析过程中遇到通配符 * {} 会遍历整个 DOM,性能大大损耗。
  6. 少用 float:float 在渲染时计算量比较大,可以使用 flex 布局。
  7. 为 0 值去单位:增加兼容性。
  8. 压缩文件大小,减少资源下载负担。

10.3 JavaScript 优化

返回目录

  1. 尽可能把 <script> 标签放在 body 之后,避免 JS 的执行卡住 DOM 的渲染,最大程度保证页面尽快地展示出来。
  2. 尽可能合并 JS 代码:提取公共方法,进行面向对象设计等……
  3. CSS 能做的事情,尽量不用 JS 来做,毕竟 JS 的解析执行比较粗暴,而 CSS 效率更高。
  4. 尽可能逐条操作 DOM,并预定好 CSs 样式,从而减少 reflow 或者 repaint 的次数。
  5. 尽可能少地创建 DOM,而是在 HTML 和 CSS 中使用 display: none 来隐藏,按需显示。
  6. 压缩文件大小,减少资源下载负担。

十一 算法

返回目录

在算法这块,jsliang 觉得自己还是比较薄弱的,如果小伙伴们跟 jsliang 一样,也想丰富下这方面知识,欢迎一起刷 LeetCode 共同进步:

十二 其他

返回目录

在 【其他】 这章,原本 jsliang 想谈谈面试中的一些小技巧,例如谈薪;或者讲讲 HR 面需要询问的问题,例如工作时长、加班机制、调薪机制等……

但是,最终看来,jsliang 的经历还是有所欠缺,所经历的面试不够 “盛大”,所以说出的话可能就是 “胡言乱语”、“误导观众”,故在此就不献丑了,如果小伙伴们想知道更多,可以通过 QQ 群:798961601 找到我。

☆ 目前 jsliang 通过 3 天的请假,去了 5 场面试,收获了 3 份 offer。
☆ 如果小伙伴不知道简历该怎么写、面试总是镇静不下来、总感觉面试没谱,可以先找 jsliang 聊聊,我会讲讲个人的面试经历,以及听到的其他小伙伴的经历~

十三 总结

返回目录

在观看这篇文章的过程中,小伙伴可能会有这些疑问:

  1. 看完觉得不过瘾啊!你怎么就这么 “短” 啊?

回答

系列套餐你值得拥有!

  1. 你这杂七杂八的都写了什么呀?看完我晕乎了!

回答

每个人的学习经历是不同的,所拥有的技术、知识点以及工作经验等都是不同的。

所以 jsliang 的目的是通过这篇文章充实自己的同时,顺带挖掘自己的不足,例如面向对象造轮子、算法问题等让 jsliang 想进一步折腾,并应用到工作中。

因此,小伙伴应该根据自己实际去扩展补充属于自己的知识点。

毕竟了解自己的,只有自己!

  1. 好像你这里写得也不是很全啊?看完我还是一知半解的!

回答

每个人的目的都是不同的,不可能一篇文章写完所有知识点,同时有些知识点可能 jsliang 也不感兴趣、或者 jsliang 的层次不够,接触不到。

并且每个面试官都可能有自己的一套面试题,如果 jsliang 能将所有的面试题都写出来,那还需要面试官做啥,大家都像考国家证书一样直接电脑考试吧~(我也期待!!!)

如果小伙伴对文章存有疑问,想快速得到回复。
或者小伙伴对 jsliang 个人的前端文档库感兴趣,也想将自己的前端知识整理出来。
或者小伙伴对文章后续的更新感兴趣,掌握更多的面试技巧。
欢迎加 QQ 群一起探讨:798961601

十四 参考文献

返回目录

本文中的许多内容,也许小伙伴看了会觉得眼熟,因为它们大部分是 jsliang 参考大量文献,再经过刷选整理,最后根据自己理解后的一些阐述。

下面是个人觉得非常优秀的文章。

14.1 关于面试

返回目录

  1. 《一位前端 2018 绝地求生记》
  2. 《中高级前端大厂面试秘籍,为你保驾护航金三银四,直通大厂(上)》
  3. 《InterviewMap》
  4. 《一篇文章搞定前端面试》
  5. 《微信小程序必知面试题》
  6. 《微信小程序面试题,附答案》
  7. 《小程序踩过的那些面试题坑,附答案解决方法》

14.2 关于 HTML

返回目录

  1. 《前端工程师手册》
  2. 《HTML 教程- (HTML5 标准) - 菜鸟教程》
  3. 《前端分享之cookie的使用及单点登录》
  4. 《Cookie、session和localStorage、以及sessionStorage之间的区别》

14.3 关于 CSS

返回目录

  1. 《前端工程师手册》
  2. 《CSS 权威指南》
  3. 《CSS 揭秘》
  4. 《CSS 世界》
  5. 《我对BFC的理解》
  6. 《CSS实现垂直居中的常用方法》
  7. 《CSS 用 position: absolute 与 transform 来居中块级元素的问题》
  8. 《css常见布局》
  9. 《CSS3 圆角》
  10. 《CSS3 渐变(Gradients)》
  11. 《CSS3 transition 属性》
  12. 《CSS3 transform 属性》
  13. 《CSS3 animation(动画) 属性》
  14. 《CSS3 box-shadow 属性》
  15. 《个人总结(css3新特性)》

14.4 关于 JS

返回目录

  1. 【推荐】《JavaScript - MDN》
  2. 《小邵教你玩转ES6》
  3. 《小邵教你玩转JS面向对象》
  4. 《实现双向绑定Proxy比defineproperty优劣如何》
  5. 《Vue 中关于 $emit 的用法》
  6. 《JavaScript 世界万物诞生记》
  7. 《js中的new()到底做了些什么??》
  8. 《MDN Function.prototype.call()》
  9. 《JavaScript中的call、apply、bind深入理解》
  10. 《箭头函数 - 廖雪峰》
  11. 《ECMAScript 6 入门 - 阮一峰》
  12. 《Vue原理解析之Virtual Dom》
  13. 《virtual-dom(Vue实现)简析》
  14. 《Vue.nextTick 的原理和用途》

14.5 关于其他

返回目录

  1. 《前端性能优化最佳实践》
  2. 《到底什么是前端工程化、模块化、组件化》
  3. 《【前端工程化系列】简谈前端模块化开发与开发规范》
  4. 《个人关于模块化的理解》
  5. 《组件化开发和模块化开发概念辨析》
  6. 《JavaScript模块化 --- Commonjs、AMD、CMD、es6 modules》
  7. 《浅谈什么是前端工程化》
  8. 《前端分享之cookie的使用及单点登录》
  9. 《Cookie、session和localStorage、以及sessionStorage之间的区别》
  10. 《网络分层TCP/IP 与HTTP》

十五 网友反馈

返回目录

查看了下掘金评论区,感谢各位大大的反馈,由于本人将于 2019年4月1日 入职,故将一些个人觉得不错的自己没有察觉的知识点记录下来,区分于原文,更为了猴年马月后的下一次跳槽进一步完善。

意思就是,jsliang 这货懒得改原文了,小伙伴们看着这里进行知识点补充

  • 闭包定义

函数 A 里面包含了 函数 B,而 函数 B 里面使用了 函数 A 的变量,函数 B 被 return 了出去,那么 函数 B 被称为闭包。

  • box-sizing 属性

当值为 border-box 时,宽度 width = content + padding + border,包含内边距与边框。

当值为 content-box 时,宽度 width = content,不包含内边距与边框。

  • em

em 是一个相对的大小,这里的相对于元素父元素的 font-size

  • Side Project

Side Project 对应的中文就是副业、业余项目或者小项目。

感兴趣的小伙伴可以去了解一下。

  • pushshift 系列

这里原文已备注是有误的,只是一时没空,没有修改。

  • CSS 选择器加载顺序

原文:!important -> 行内样式 -> #id -> .class -> 元素和伪元素 -> * -> 继承 -> 默认

网友:“应该是最后的优先级最高。”

这里最后的优先级最高应该是指同等级优先级覆盖。浏览器通过 CSSParser 将 CSS 解析成 CSS Rule Tree 的时候,没错的话应该是按照原文中的排序先加载,然后同等级的时候,后面的属性覆盖前面的属性。

  • ARIA

对于 HTML5 的语义化,ARIA 的意思是 Accessible Rich Internet Application,aria-* 的作用就是描述这个 Tag 在可视化的情境中的具体信息。例如:

  1. aria-label:为组件指定内置的文本标签,用来替代开发者没有使用 <label> 标签
  2. aria-labelledby:会读取与此具有相同的 id 名的值

详情可参考张鑫旭的 《WAI-ARIA无障碍网页应用属性完全展示》

  • sessionStorage 和 localStorage

文章描述不够详细。

  • 两列布局/三列布局
  1. child-tow 中设置 width: 100% 的时候 child-one 的宽度会随机而变,设置 flex: 1 就不会。所以看个人需求进行设置。
  2. 文章中没有讲到应对兼容性怎么设置,可以考虑使用 float 进行相关的布局。
  • 浅拷贝与深拷贝

可参考文章:《深拷贝的终极探索(90%的人不知道)》

  • Promiseasync/await

文章描述不够详细。

  • 跨域

本来打算写的,后面没时间,给我删了这块,评论区有篇文献参考:

《九种跨域方式实现原理(完整版)》

以上,即为目前评论区的补充,感谢各位小伙伴的点赞支持。


jsliang 广告推送:
也许小伙伴想了解下云服务器
或者小伙伴想买一台云服务器
或者小伙伴需要续费云服务器
欢迎点击 云服务器推广 查看!

知识共享许可协议
jsliang 的文档库梁峻荣 采用 知识共享 署名-非商业性使用-相同方式共享 4.0 国际 许可协议进行许可。
基于github.com/LiangJunron…上的作品创作。
本许可协议授权之外的使用权限可以从 creativecommons.org/licenses/by… 处获得。

关注下面的标签,发现更多相似文章
评论