# 2019年05月刊
# 2019/05/27 - 2019/06/02 ⌚️
几种进制的相互转换计算方法,在 JavaScript 中如何表示和转换
点击
parseInt(str, radix)
将一个 radix 进制的 str 转化为十进制,parseInt('23',8) // 19
,将八进制的‘23’转化为10进制的‘19’number.toString(radix)
将一个数字转化为 radix 进制的数字字符串(0x11).toString(8); // 21 (0x11).toString(10); // 17 (0x11).toString(2); // 10001
1
2
3BFC 实现原理,可以解决的问题,如何创建 BFC
点击
BFC(Block formatting context)
直译为"块级格式化上下文"。它是一个独立的渲染区域,只有块级元素参与, 它规定了内部的块级元素如何布局,并且与这个区域外部毫不相干。BCF 可以解决的问题:浮动定位,消除外边距折叠,清除浮动,自适应多栏布局
BFC 的创建:根元素或包含根元素的元素,浮动元素(
float
不为none
),绝对定位元素(position
为absolute
或者fixed
),display
为inline-block,table-cell,table-caption,overflow
值不为visible
,弹性元素(flex
布局),网格元素(grid
布局)理解 JavaScript 的执行上下文栈,可以应用堆栈信息快速定位问题
点击
执行上下文 就是当前
JavaScript
代码被解析和执行时所在环境的抽象概念,JavaScript
中运行任何的代码都是在执行上下文中运行。执行上下文总共有三种类型:全局执行上下文, 函数执行上下文,
Eval
函数执行上下文执行栈,在其他编程语言中也被叫做调用栈,具有 LIFO(后进先出)结构,用于存储在代码执行期间创建的所有执行上下文。
null 和 undefined 的区别
点击
Number
转换的值不同,Number(null)
输出为0
,Number(undefined)
输出为NaN
null
表示一个值被定义了,但是这个值是空值undefined
表示缺少值,即此处应该有值,但是还没有定义
理解值类型和引用类型
点击
JavaScript 中的变量分为基本类型和引用类型:
基本类型: 保存在栈内存中的简单数据段,它们的值都有固定的大小,保存在栈空间,通过按值访问
引用类型: 保存在堆内存中的对象,值大小不固定,栈内存中存放的该对象的访问地址指向堆内存中的对象,
JavaScript
不允许直接访问堆内存中的位置,因此操作对象时,实际操作对象的引用基本类型对应的内置对象,以及他们之间的装箱拆箱操作
点击
String(), Number(), Boolean()
装箱:就是把基本类型转变为对应的对象。装箱分为隐式和显示
// 隐式装箱: 每当读取一个基本类型的值时,后台会创建一个该基本类型所对应的对象。 // 在这个基本类型上调用方法,其实是在这个基本类型对象上调用方法。 // 这个基本类型的对象是临时的,它只存在于方法调用那一行代码执行的瞬间,执行方法后立刻被销毁。 let num = 123; num.toFixed(2); // '123.00'//上方代码在后台的真正步骤为 var c = new Number(123); c.toFixed(2); c = null; // 显式装箱: 通过内置对象 Boolean、Object、String 等可以对基本类型进行显示装箱。 var obj = new String('123');
1
2
3
4
5
6
7
8
9
10拆箱: 拆箱与装箱相反,把对象转变为基本类型的值。
Number([1]); //1 // 转换演变: [1].valueOf(); // [1]; [1].toString(); // '1';Number('1'); //1
1
2
3
4
# 2019/05/20 - 2019/05/26 ⌚️
null 是一种数据类型,可为什么
typeof null === 'object'
?点击
虽然
typeof null
会输出object
,但是这只是JS
存在的一个悠久Bug
。在JS
的最初版本中使用的是32
位系统,为了性能考虑使用低位存储变量的类型信息,000
开头代表是对象然而null
表示为全零,所以将它错误的判断为object
。介绍下 Set、Map、WeakSet 和 WeakMap 的区别?
点击
- Set
- 成员唯一、无序且不重复[value, value],键值与键名是一致的(或者说只有键值,没有键名)
- 可以遍历,方法有:add、delete、has
- WeakSet
- 成员都是对象
- 成员都是弱引用,可以被垃圾回收机制回收,可以用来保存 DOM 节点,不容易造成内存泄漏
- 不能遍历,方法有 add、delete、has
- Map
- 本质上是键值对的集合,类似集合
- 可以遍历,方法很多可以跟各种数据格式转换
- WeakMap
- 只接受对象作为键名(null 除外),不接受其他类型的值作为键名
- 键名是弱引用,键值可以是任意的,键名所指向的对象可以被垃圾回收,此时键名是无效的
- 不能遍历,方法有 get、set、has、delete
- Set
实现一个方法取多个数组的并集
点击
function merge(...args) { let arr = []; for (let i = 0; i < args.length; i++) { arr = arr.concat(args[i]); console.log(args[i]); } return [...new Set(arr)]; } console.log(merge([0, 1, 2, 3], [1, 2, 3, 8], [1, 10])); // [ 0, 1, 2, 3, 8, 10 ]
1
2
3
4
5
6
7
8
9
10实现一个方法取多个数组的交集
点击
function intersect(...args) { if (args.length === 0) { return []; } if (args.length === 1) { return args[0]; } return args.reduce((result, arg) => { return result.filter(item => arg.includes(item)); }); } console.log(intersect([0, 1, 2, 3], [1, 2, 3], [1])); // [1]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
let arr = [2, 2, 1, 4, 4, 5, 5, 1, 8]; // 实现一个singleNumber找出不重复的8
1
2点击
这道题第一眼看过去,思路挺简单的,我们只需要维护一个对象来记录每一个元素出现的次数,使用元素的值作为 key,元素出现的次数作为 value。之后再遍历这个对象,找到 value 为 1 的 key。对应的 key 就是那个元素。
function singleNumber(nums) { const obj = {}; for (let i = 0; i < nums.length; i++) { obj[nums[i]] = obj[nums[i]] ? obj[nums[i]] + 1 : 1; } for (let key in obj) { if (obj[key] === 1) { return Number(key); // 由于 key 是 string ,因此我们这里需要转化下 } } } console.log(singleNumber([2, 2, 1, 4, 4, 5, 5, 1, 8])); // 8
1
2
3
4
5
6
7
8
9
10
11
12
13当然,更好的解法是用异或解决,两个相同数异或得 0,因此不断异或,最后剩下得就是不重复的数字,当然这只是在这种特殊情况下才使用,应用场景不大
function singleNumber(nums) { for (let i = 1; i < nums.length; i++) { nums[0] ^= nums[i]; } return nums[0]; } console.log(singleNumber([2, 2, 1, 4, 4, 5, 5, 1, 8]));
1
2
3
4
5
6
7
8hash
路由和history
路由的区别?点击
路由的哈希模式其实是利用了
window
可以监听onhashchange
事件,也就是说你的url
中的哈希值(#后面的值)如果有变化,前端是可以做到监听并做一些响应(搞点事情),这么一来,即使前端并没有发起http
请求他也能够找到对应页面的代码块进行按需加载。路由的
history
模式其实是利用了pushState
与replaceState
这两个神器,其作用就是可以将url
替换并且不刷新页面,好比挂羊头卖狗肉,http
并没有去请求服务器该路径下的资源,一旦刷新就会暴露这个实际不存在的“羊头”,显示404
。HTML
和XHTML
有什么区别?点击
XHTML
语法严格,主要不同包括:XHTML
元素必须被正确地嵌套。XHTML
元素必须被关闭。- 标签名必须用小写字母。
XHTML
文档必须拥有根元素。
# 2019/05/13 - 2019/05/19 ⌚️
请解释
<script>
、<script async>
和<script defer>
的区别点击
<script src="script.js"></script>
没有
defer
或async
,浏览器会立即加载并执行指定的脚本,“立即”指的是在渲染该script
标签之下的文档元素之前,也就是说不等待后续载入的文档元素,读到就加载并执行。<script async src="script.js"></script>
有
async
,加载和渲染后续文档元素的过程将和script.js
的加载与执行并行进行(异步)。<script defer src="myscript.js"></script>
有
defer
,加载后续文档元素的过程将和script.js
的加载并行进行(异步),但是script.js
的执行要在所有元素解析完成之后,DOMContentLoaded
事件触发之前完成。html5
新标签有哪些?点击
<article> 标签定义外部的内容。比如来自一个外部的新闻提供者的一篇新的文章,或者来自 blog 的文本,或者是来自论坛的文本。亦或是来自其他外部源内容。 <aside> 标签定义 article 以外的内容。aside 的内容应该与 article 的内容相关。 <audio> 标签定义声音,比如音乐或其他音频流。 <canvas> 标签定义图形,比如图表和其他图像。这个 HTML 元素是为了客户端矢量图形而设计的。它自己没有行为,但却把一个绘图 API 展现给客户端 JavaScript 以使脚本能够把想绘制的东西都绘制到一块画布上。 <command> 标签定义命令按钮,比如单选按钮、复选框或按钮。 <datalist> 标签定义可选数据的列表。与 input 元素配合使用,就可以制作出输入值的下拉列表。 <details> 标签定义元素的细节,用户可进行查看,或通过点击进行隐藏。与 <legend> 一起使用,来制作 detail 的标题。该标题对用户是可见的,当在其上点击时可打开或关闭 detail。 <figcaption> 标签定义 figure 元素的标题。”figcaption” 元素应该被置于 “figure” 元素的第一个或最后一个子元素的位置。 HTML5: <figure><figcaption>PRC</figcaption></figure> <figure> 标签用于对元素进行组合。使用 <figcaption> 元素为元素组添加标题。 HTML5: <figure> <figcaption>PRC</figcaption> <p> The People's Republic of China was born in 1949... </p> </figure> <footer> 标签定义 section 或 document 的页脚。典型地,它会包含创作者的姓名、文档的创作日期以及/或者联系信息。 <header> 标签定义 section 或 document 的页眉。 <hgroup> 标签用于对网页或区段(section)的标题进行组合。 <nav> 标签定义导航链接的部分。 <section> 标签定义文档中的节(section、区段)。比如章节、页眉、页脚或文档中的其他部分。 <source /> 标签为媒介元素(比如 <video> 和 <audio> )定义媒介资源。 <video> 标签定义视频,比如电影片段或其他视频流。 HTML5: <video src="movie.ogg" controls="controls" > 您的浏览器不支持 video 标签。 </video> </video> </audio> </video> </section> </nav> </hgroup> </header> </footer> </figcaption> </figure> </figcaption> </legend></details > </datalist></command ></canvas > </audio> </aside> </article>
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96<a>
标签中href="javascript:;"
表示什么意思??点击
这里的
href="javascript:;"
,其中javascript:
是伪协议,它可以让我们通过一个链接来调用javascript
函数.而采用这个方式javascript:;
可以实现A
标签的点击事件运行时,如果页面内容很多,有滚动条时,页面不会乱跳,用户体验更好。实现数组扁平化的方法?
Git
和SVN
的区别?点击
Git 和 SVN 孰优孰好,每个人有不同的体验。
Git 是分布式的,SVN 是集中式的
这是 Git 和 SVN 最大的区别。若能掌握这个概念,两者区别基本搞懂大半。因为 Git 是分布式的,所以 Git 支持离线工作,在本地可以进行很多操作,包括接下来将要重磅推出的分支功能。而 SVN 必须联网才能正常工作。
Git 复杂概念多,SVN 简单易上手
所有同时掌握 Git 和 SVN 的开发者都必须承认,Git 的命令实在太多了,日常工作需要掌握 add,commit,status,fetch,push,rebase 等,若要熟练掌握,还必须掌握 rebase 和 merge 的区别,fetch 和 pull 的区别等,除此之外,还有 cherry-pick,submodule,stash 等功能,仅是这些名词听着都很绕。
在易用性这方面,SVN 会好得多,简单易上手,对新手很友好。但是从另外一方面看,Git 命令多意味着功能多,若我们能掌握大部分 Git 的功能,体会到其中的奥妙,会发现再也回不去 SVN 的时代了。
Git 分支廉价,SVN 分支昂贵
在版本管理里,分支是很常使用的功能。在发布版本前,需要发布分支,进行大需求开发,需要 feature 分支,大团队还会有开发分支,稳定分支等。在大团队开发过程中,常常存在创建分支,切换分支的需求。
Git 分支是指针指向某次提交,而 SVN 分支是拷贝的目录。这个特性使 Git 的分支切换非常迅速,且创建成本非常低。
而且 Git 有本地分支,SVN 无本地分支。在实际开发过程中,经常会遇到有些代码没写完,但是需紧急处理其他问题,若我们使用 Git,便可以创建本地分支存储没写完的代码,待问题处理完后,再回到本地分支继续完成代码。
前端日志埋点方案?
npm、yarn
依赖包管理的原理,两者的区别 ?点击
首先,这两个都属于 js 包管理工具,都可以安装包或者模块, 两者命令有所不同yarn 是由 facebook、google 等联合开发推出的,具有速度快,离线工作, 从多个源安装,安装版本统一,更简洁的输出,多注册来源处理, 更好的语义化的优点
# 2019/05/06 - 2019/05/12 ⌚️
如何有效避免回流与重绘 ?
点击
Display 的值会影响布局,从而影响页面元素位置变化,所以会更改渲染树的结构,慎用
使用 DocumentFragment 进行缓存操作,引发一次回流和重绘
使用 cloneNode (true or false) 和 replaceChild 技术,引发一次回流和重绘。
不要对元素进行 JS 动画流操作,尽量使用 CSS 动画属性,以减少回流的 Render Tree 的规模
从输入 URL 到页面展现的详细过程 ?
浏览器跨标签通信 ?
localstorage 或者 cookie 或者 url 传递参数
浏览器海量数据存储 ?
点击
cookie 用于短期存储用户身份,登录状态等较小的信息;localStorage/sessionStorage 用于长期存储数据,浏览器关闭不影响它们的内存,相比于 cookie,storage 能存储较多;IndexedDB 是浏览器提供的接近于 NoSQL 的数据库,允许存储大量数据。
域名解析的过程?
点击
1、在浏览器中输入
www.qq.com
域名,操作系统会先检查自己本地的hosts
文件是否有这个网址映射关系,如果有,就先调用这个IP
地址映射,完成域名解析。2、如果
hosts
里没有这个域名的映射,则查找本地DNS解析器缓存
,是否有这个网址映射关系,如果有,直接返回,完成域名解析。3、如果
hosts
与本地DNS解析器缓存
都没有相应的网址映射关系,首先会找TCP/ip
参数中设置的首选DNS服务器
,在此我们叫它本地DNS服务器
,此服务器收到查询时,如果要查询的域名,包含在本地配置区域资源中,则返回解析结果给客户机,完成域名解析,此解析具有权威性。4、如果要查询的域名,不由
本地DNS服务器区域解析
,但该服务器已缓存了此网址映射关系,则调用这个IP
地址映射,完成域名解析,此解析不具有权威性。5、如果
本地DNS服务器
本地区域文件与缓存解析都失效,则根据本地DNS服务器
的设置(是否设置转发器)进行查询,如果未用转发模式,本地DNS
就把请求发至13
台根DNS
,根DNS
服务器收到请求后会判断这个域名(.com)
是谁来授权管理,并会返回一个负责该顶级域名服务器的一个IP
。本地DNS服务器
收到IP
信息后,将会联系负责.com
域的这台服务器。这台负责.com
域的服务器收到请求后,如果自己无法解析,它就会找一个管理.com
域的下一级DNS
服务器地址(http://qq.com)
给本地DNS服务器
。当本地DNS服务器
收到这个地址后,就会找http://qq.com
域服务器,重复上面的动作,进行查询,直至找到www.qq .com
主机。6、如果用的是转发模式,此
DNS
服务器就会把请求转发至上一级DNS
服务器,由上一级服务器进行解析,上一级服务器如果不能解析,或找根DNS
或把转请求转至上上级,以此循环。不管是本地DNS服务器
用是是转发,还是根提示,最后都是把结果返回给本地DNS服务器
,由此DNS
服务器再返回给客户机。JavaScript
异常处理的方式,统一的异常处理方案如何解决页面加载海量数据而不冻结前端 UI ?
点击
题目:10w 条记录的数组,一次性渲染到页面上,如何处理可以不冻结UI?
1分治思想,在一定的时间内多次加载数据,直至渲染完成,使用
window.requestAnimationFrame
和document.createDocumentFragment()
实现<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>页面加载海量数据</title> </head> <body> <ul id="list-with-big-data"> 100000 数据 </ul> <script> // 此处添加你的代码逻辑 (function() { const ulContainer = document.getElementById('list-with-big-data'); // 防御性编程 if (!ulContainer) { return; } const total = 100000; // 插入数据的总数 const batchSize = 4; // 每次批量插入的节点个数,个数越多,界面越卡顿 const batchCount = total / batchSize; // 批处理的次数 let batchDone = 0; // 已完成的批处理个数 function appendItems() { // 使用 DocumentFragment 减少 DOM 操作次数,对已有元素不进行回流 const fragment = document.createDocumentFragment(); for (let i = 0; i < batchSize; i++) { const liItem = document.createElement('li'); liItem.innerText = batchDone * batchSize + i + 1; fragment.appendChild(liItem); } // 每次批处理只修改 1 次 DOM ulContainer.appendChild(fragment); batchDone++; doAppendBatch(); } function doAppendBatch() { if (batchDone < batchCount) { // 在重绘之前,分批插入新节点 window.requestAnimationFrame(appendItems); } } // kickoff doAppendBatch(); // 使用 事件委托 ,利用 JavaScript 的事件机制,实现对海量元素的监听,有效减少事件注册的数量 ulContainer.addEventListener('click', function(e) { const target = e.target; if (target.tagName === 'LI') { alert(target.innerText); } }); })(); </script> </body> </html>
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
61
62
63
64
65
66
# 2019/04/29 - 2019/05/05 ⌚️
ES6 class
构造以及继承的底层实现原理手动实现一个
new
?点击
function myNew(Obj, ...args) { var obj = Object.create(Obj.prototype); //使用指定的原型对象及其属性去创建一个新的对象 Obj.apply(obj, args); // 绑定 this 到obj, 设置 obj 的属性 return obj; // 返回实例 }
1
2
3
4
5手动实现一个 instanceof?
点击
instanceof
其原理就是判断实例对象的__proto__
是不是强等于对象的prototype
属性,如果不是继续往原型链上找,直到__proto__
为null
为止。function instanceOf(obj, object) { //obj 表示实例对象,object 表示对象 var O = object.prototype; obj = obj.__proto__; while (true) { if (obj === null) return false; if (O === obj) // 这里重点:当 O 严格等于 obj 时,返回 true return true; obj = obj.__proto__; } }
1
2
3
4
5
6
7
8
9
10
11
12==
的类型转化规则点击
[] == false // true {} == false // false
1
2
31,null 和 undefined,相等。
2,数字和字符串,转化为数字再比较。
3,如果有 true 或 false,转换为 1 或 0,再比较。
4,如果有引用类型,优先调用 valueOf。
5,其余都不相等。
DOM
和BOM
有什么区别 ?点击
- DOM Document Object Model,文档对象模型
DOM 是为了操作文档出现的 API,document 是其的一个对象
DOM 和文档有关,这里的文档指的是网页,也就是 html 文档。DOM 和浏览器无关,他关注的是网页本身的内容。
- BOM Browser Object Model,浏览器对象模型
BOM 是为了操作浏览器出现的 API,window 是其的一个对象
window 对象既为 javascript 访问浏览器提供 API,同时在 ECMAScript 中充当 Global 对象
doctype
有什么用?点击
doctype 是一种标准通用标记语言的文档类型声明,目的是告诉标准通用标记语言解析器要使用什么样的文档类型定义(DTD)来解析文档。
声明是用来指示 web 浏览器关于页面使用哪个 HTML 版本进行编写的指令。 声明必须是 HTML 文档的第一行,位于 html 标签之前。
浏览器本身分为两种模式,一种是标准模式,一种是怪异模式,浏览器通过 doctype 来区分这两种模式,doctype 在 html 中的作用就是触发浏览器的标准模式,如果 html 中省略了 doctype,浏览器就会进入到 Quirks 模式的怪异状态,在这种模式下,有些样式会和标准模式存在差异,而 html 标准和 dom 标准值规定了标准模式下的行为,没有对怪异模式做出规定,因此不同浏览器在怪异模式下的处理也是不同的,所以一定要在 html 开头使用 doctype。
箭头函数和普通函数有什么区别?
点击
- 函数体内的
this
对象,就是定义时所在的对象,而不是使用时所在的对象,用call apply bind
也不能改变this
指向 - 不可以当作构造函数,也就是说,不可以使用
new
命令,否则会抛出一个错误。 - 不可以使用
arguments
对象,该对象在函数体内不存在。如果要用,可以用rest
参数代替。 - 不可以使用
yield
命令,因此箭头函数不能用作Generator
函数。 - 箭头函数没有原型对象
prototype
- 函数体内的