DD每周前端七题详解-第五期

DD每周前端七题详解-第五期

系列介绍

你盼世界,我盼望你无bug。Hello 你们好!我是霖呆呆!javascript

呆呆每周都会分享七道前端题给你们,系列名称就是「DD每周七题」。css

系列的形式主要是:3道JavaScript + 2道HTML + 2道CSS,帮助咱们你们一块儿巩固前端基础。前端

全部题目也都会整合至 LinDaiDai/niubility-coding-jsissues中,欢迎你们提供更好的解题思路,谢谢你们😁。java

一块儿来看看本周的七道题吧。node

正题

1、实现mask函数将"123456"转为"##3456",只保留最后四个字符

(题目来源:github.com/30-seconds/…)css3

首先介绍一下题目的意思吧😄,案例🌰以下:git

const mask = (str, maskChar = '#') => {
 // 代码 } console.log(mask('123456')); // '##3456' console.log(mask('lindaidai')); // '#####idai' 复制代码

这道题的难度应该没有那么大,处理方式也有不少。呆呆这边主要是讲解一下如何使用padStart来实现的。github

简单介绍一下padStart方法吧,它是ES8新增的实例函数,与它做用差很少的还有一个叫padEnd的函数:web

  • String.prototype.padStart
  • String.prototype.padEnd

做用:容许将空字符串或其余字符串添加到原始字符串的开头或结尾。浏览器

语法

padStart(targetLength, [padString])
复制代码
  • targetLength: 必填,当前字符串须要填充到的目标长度。若是这个数值小于当前字符串的长度,则返回当前字符串自己。
  • padString: 可选,填充字符串。若是字符串太长,使填充后的字符串长度超过了目标长度,则只保留最左侧的部分,其余部分会被截断,此参数的缺省值为 " "

例如:

'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab' 复制代码

哈哈,另外想要了解如何实现一个padStart的小伙伴能够看呆呆以前一篇文章哟:DD每周前端七题详解-第二期

言归正传,让咱们回到这道题目哈,首先让咱们来处理一下输入参数边界的状况,例如输入的str不存在或者长度小于4的时候:

const mask = (str, maskChar = '#') => {
 if (!str || str.length <= 4) return str; } 复制代码

其次,咱们能够只保留住str的末尾四个字符,而后使用padStart将这四个字符填充至str.length便可,以下:

const mask = (str, maskChar = '#') => {
 if (!str || str.length <= 4) return str;  return str.slice(-4).padStart(str.length, maskChar); } 复制代码
  • slice不会影响本来的字符串
  • 使用 padStart填充便可

github.com/LinDaiDai/n…

2、介绍一下NaN并实现一个isNaN

介绍一下NaN

  • NaN属性是表明非数字值的特殊值,该属性用于指示某个值不是数字;
  • NaN是不等于 NaN的,即 NaN === NaN的结果是 false
  • 使用 Object.is()来比较两个 NaN结果是 true,即 Object.is(NaN, NaN)的结果是 true
  • typeof NaN"number"
  • 方法 parseInt()parseFloat()在不能解析指定的字符串时就返回这个值;
  • 可使用 isNaN来判断一个变量是否是 NaN,它是 JS内置对象 Number上的静态方法。

(关于第三点,你们能够看一下我以前的一篇文章哟,里面的「第二补:JS类型检测-Object.is()和===的区别」有提到:读《三元-JS灵魂之问》总结,给本身的一份原生JS补给(上))

实现一个isNaN:

对于isNaNpolyfill实现起来就比较简单了,只须要利用NaN不等于它自身的这一点便可:

const isNaN = v => v !== v;
复制代码

github.com/LinDaiDai/n…

3、按位取反,为何~2 = -3?

接下来,分享一道与JavaScript原生无关的题目吧,主要也是看到群里有小伙伴问了关于按位取反~的用法,这边统一科普一下,😁。

正常一个数字,例如12,或者-1-2

若是咱们对它们进行按位取反的话,结果会是这样:

  • ~1 = -2
  • ~2 = -3
  • ~-1 = 0
  • ~-2 = 1

看不懂不要紧,让咱们来一步步看看实现的过程哈。

在这里实际上是分了正数和负数的,由于符号不一样取反的过程也会不一样。

1.1 正数按位取反

先让咱们来看看正数的按位取反。

好比先看看~1 = -2,过程以下:

1. 十进制转为二进制原码

首先将十进制的1转化为二进制原码为:0000 0001

2. 二进制原码按位取反

以后将原码按位取反:

也就是将0000 0001 => 1111 1110

(取反应该知道啥意思吧?就是0换成11换成0)

3. 取反后的二进制转为原码

再将取反后的二进制码转为原码二进制:

也就是将1111 1110 => 1000 0010

这里你估计看着都点懵了,当咱们将取反后的二进制转为原码二进制的时候,实际上是有如下两步的:

  1. 须要判断取反后的二进制的第一个位是否是 1,这个第一位咱们称之为 符号位,若是是 1的话就表示即将要转成的数是一个负数,若是是 0的话表示即将要转的数是一个正数,这个符号位是不能动的;在这里咱们能够看到 1111 1110的第一位是 1,因此表示即将要转的数是一个负数,同时咱们不动它。
  2. 而后将除了第一位之外其它位数取反并 +1。因此会有这么两个过程:
    • 1111 1110 => 1000 0001
    • 1000 0001 => 1000 0010 (这步是对上一步的结果 +1,由于上一步的最后一个数是 1,因此它再加上 1就须要向前进一位了,所以变成了 1000 0010)

4. 将原码二进制转为十进制

最后一步就是将咱们前面获得的1000 0010这个二进制转化为十进制了。

第一位符号位,是1,则表示是个负数,因此结果为-2

OK👌,搞懂了这个步骤以后再让咱们本身来转换一下~2 = -3吧:

1. 0000 0010
2. 1111 1101 3. 1000 0011 4. -3 复制代码

正数按位取反总结

  1. 十进制转为二进制原码
  2. 二进制原码按位取反
  3. 符号位保留,其他位取反+1
  4. 二进制原码转为十进制

1.2 负数按位取反

负数的按位取反和上面就有些不同了,主要是第二步和第三步调换一下顺序:

  1. 十进制转为二进制原码
  2. 符号位保留,其他位取反+1
  3. 二进制原码按位取反
  4. 二进制原码转为十进制

例如:~-1 =0的转换过程:

1. 十进制转为二进制原码

这步和正数按位取反是同样的:

-1 => 1000 0001

2. 符号位保留,其他位取反+1

转换过程:

  • 1000 0001 => 1111 1110 (取反)
  • 1111 1110 => 1111 1111 (取反后 + 1)

3. 二进制原码按位取反

将刚刚获得的再进行按位取反:

1111 1111 => 0000 0000

4. 二进制原码转为十进制

0000 0000 => 0

OK👌,如今本身来转换一下~-2 = 1吧:

1. 1000 0010
2. 1111 1110 3. 0000 0001 4. 1 复制代码

这里没啥诀窍,关键就是要记住转换的过程而后不断的练习吧 😂。

另外关于~~的用法还能够看呆呆的另外一篇文章哟《JS中按位取反运算符~及其它运算符》

github.com/LinDaiDai/n…

4、知道insertAdjacentHTML方法吗?

这个方法是呆呆最近在看公司项目代码时了解到的,以前一直没有注意它。

首先对于它的用法:

insertAdjacentHTML() 方法将指定的文本解析为 Element 元素,并将结果节点插入到DOM树中的指定位置。它不会从新解析它正在使用的元素,所以它不会破坏元素内的现有元素。这避免了额外的序列化步骤,使其比直接使用innerHTML操做更快。

其次它的做用对象是一个元素element,例如const container = document.getElementById('container')

语法上呢:

element.insertAdjacentHTML(position, text);
复制代码
  • position:一个 DOMString,也就是表示插入内容相对元素的位置,且必须是下面的字符串之一:
    • 'beforebegin':元素自身的前面。
    • 'afterbegin':插入元素内部的第一个子节点以前。
    • 'beforeend':插入元素内部的最后一个子节点以后。
    • 'afterend':元素自身的后面。
  • text:是要被解析为HTML或XML元素,并插入到DOM树中的 DOMString

案例

让咱们来看看它的用法,例如🌰如今有一个HTML的结构为:

<div id="one">我是one</div>
复制代码

JavaScript代码中加上这段话:

const one = document.getElementById('one');
one.insertAdjacentHTML('afterend', '<div id="two">我是two</div>'); 复制代码

如今最终的渲染结果就变成了这样:

<div id="one">我是one</div><div id="two">我是two</div>
复制代码

工做上的用法

在项目中,主要能够应用于这样的场景:一个空的容器(你能够理解为一个div),开始须要一个loading的效果,在数据加载完毕以后,须要把loading取掉且清空容器内的元素并以其它方式从新渲染出容器的内容。

这里呆呆就以定时器来模拟一下数据加载的过程,实现代码以下:

<body>
 <div id="container"></div> </body> <script>  const container = document.getElementById('container');  const loading = '<div id="loading">loading</div>'; // loading多是一个组件  container.insertAdjacentHTML('beforeend', loading);  setTimeout(() => {  container.innerHTML = ''  }, 2000) </script> 复制代码

(固然,咱们不要为了刻意用而去用,适合本身的才是最好的)

安全问题

  • 使用 insertAdjacentHTML 插入用户输入的HTML内容的时候,须要转义以后才能使用。

    例如:

    const one = document.getElementById('one');
    // 因为 encodeURI('<div id="two">我是two</div>')会被转译为: // %3Cdiv%20id=%22two%22%3E%E6%88%91%E6%98%AFtwo%3C/div%3E // 所以最终会被当成 "%3Cdiv%20id=%22two%22%3E%E6%88%91%E6%98%AFtwo%3C/div%3E"字符串渲染 one.insertAdjacentHTML('afterend', encodeURI('<div id="two">我是two</div>')); 复制代码
  • 若是只是为了插入文本内容(而不是HTML节点),不建议使用这个方法,建议使用node.textContent 或者 node.insertAdjacentText()。由于这样不须要通过HTML解释器的转换,性能会好一点。(这里是引用的MDN-insertAdjacentHTML上的内容)

github.com/LinDaiDai/n…

5、insertAdjacentHTMLinsertAdjacentElement的区别

第二个参数的类型不一样, 前者接收的是是要被解析为HTML或XML元素的字符串,然后者接收的是一个element元素。

const one = document.getElementById('one');
one.insertAdjacentHTML('afterend', '<div id="two">我是two</div>');  const one = document.getElementById('one'); const two = document.createElement('div') two.innerHTML = '我是two'; one.insertAdjacentElement('afterend', two); 复制代码

github.com/LinDaiDai/n…

6、实现九宫格布局

实现效果以下:

先来看一下HTML方面的代码:

<div id="container">
 <div class="item item-1">1</div>  <div class="item item-2">2</div>  <div class="item item-3">3</div>  <div class="item item-4">4</div>  <div class="item item-5">5</div>  <div class="item item-6">6</div>  <div class="item item-7">7</div>  <div class="item item-8">8</div>  <div class="item item-9">9</div> </div> 复制代码

还有一些item上的基础css代码:

#container {
 /* css代码 */ }  .item {  font-size: 2em;  text-align: center;  border: 1px solid #e5e4e9; }  .item-1 {  background-color: #ef342a; }  .item-2 {  background-color: #f68f26; }  .item-3 {  background-color: #4ba946; }  .item-4 {  background-color: #0376c2; }  .item-5 {  background-color: #c077af; }  .item-6 {  background-color: #f8d29d; }  .item-7 {  background-color: #b5a87f; }  .item-8 {  background-color: #d0e4a9; }  .item-9 {  background-color: #4dc7ec; } 复制代码

方案一

第一种方案可使用浮动+百分比:

#container {
 width: 150px;  height: 150px; } .item {  float: left;  width: 33.33%;  height: 33.33%;  box-sizing: border-box;  font-size: 2em;  text-align: center;  border: 1px solid #e5e4e9; } 复制代码

方案二

还可使用flex布局的方式:

#container {
 width: 150px;  height: 150px;  display: flex;  flex-wrap: wrap; } .item {  width: 33.33%;  height: 33.33%;  box-sizing: border-box;  font-size: 2em;  text-align: center;  border: 1px solid #e5e4e9; } 复制代码

方案三

另外的话,也许还能够试试grid

#container {
 display: grid;  grid-template-columns: 50px 50px 50px;  grid-template-rows: 50px 50px 50px; } .item {  font-size: 2em;  text-align: center;  border: 1px solid #e5e4e9; } 复制代码

答案参考:github.com/haizlin/fe-…

github.com/LinDaiDai/n…

7、说说will-change

will-changeCSS3新增的标准属性,它的做用很单纯,就是"加强页面渲染性能",当咱们在经过某些行为触发页面进行大面积绘制的时候,浏览器每每是没有准备,只能被动的使用CPU去计算和重绘,因为事先没有准备,对于一些复杂的渲染可能会出现掉帧、卡顿等状况。

will-change则是在真正的行为触发以前告诉浏览器可能要进行重绘了,至关于浏览器把CPU拉上了,能从容的面对接下来的变形。

经常使用的语法主要有:

  • whil-change: scroll-position; 即将开始滚动
  • will-change: contents; 内容要动画或者变化了
  • will-transform; transform相关的属性要变化了(经常使用)

注意:

  • will-change虽然能够开启加速,可是必定要适度使用
  • 开启加速的代价为手机的耗电量会增长
  • 使用时遵循最小化影响原则,能够对伪元素开启加速,独立渲染
  • 能够写在伪类中,例如 hover中,这样移出元素的时候就会自动 removewill-change
  • 若是使用 JS添加了 will-change,注意要及时 remove掉,方式就是 style.willChange = 'auto'

github.com/LinDaiDai/n…

参考文章

知识无价,支持原创。

参考文章:

后语

你盼世界,我盼望你无bug。这篇文章就介绍到这里。

您每周也许会花48小时的时间在工做💻上,会花49小时的时间在睡觉😴上,也许还能够再花20分钟的时间在呆呆的7道题上,日积月累,我相信咱们都能见证彼此的成长😊。

什么?你问我为何系列的名字叫DD?由于呆呆呀,哈哈😄。

喜欢霖呆呆的小伙还但愿能够关注霖呆呆的公众号 LinDaiDai 或者扫一扫下面的二维码👇👇👇。

img
img

我会不定时的更新一些前端方面的知识内容以及本身的原创文章🎉

你的鼓励就是我持续创做的主要动力 😊。

本文使用 mdnice 排版

相关文章
相关标签/搜索