你盼世界,我盼望你无bug。Hello 大家好!我是霖呆呆!
呆呆每周都会分享七道前端题给大家,系列名称就是「DD每周七题」。
系列的形式主要是:3道JavaScript + 2道HTML + 2道CSS,帮助我们大家一起巩固前端基础。
所有题目也都会整合至 LinDaiDai/niubility-coding-js 的issues中,欢迎大家提供更好的解题思路,谢谢大家????。
https://github.com/LinDaiDai/niubility-coding-js/issues
一起来看看本周的七道题吧。
(题目来源:https://github.com/CavsZhouyou/Front-End-Interview-Notebook)
咋了小伙伴们,感觉这道题目很简单是吗?哈哈,数一数逗号的间隙好像就能得出答案了,比如这样:
但是这道题的答案并不是4哟,而是3。
console.log([,,,].length) // 3所以最终我们是需要把它想象成这样的:
也就是最后一个逗号的后面是不算一项的。
这里其实涉及到了一个名为:尾后逗号的概念,或者说是叫做终止逗号。上面????这道题好像看不出它有什么作用,让我来看看实际上为什么会有这个用法。
比如现在你的项目中这么一个文件:
config.js:
const types = [ { name: '帅' }, { name: '阳光' }, ] export { types };大家可以看到,我在阳光这一项的的后面是多加了一个","的,此时我将这个代码提交到git上并标记为版本1。
如果这时候types中又要添加一项名为"可爱"的配置项,我只需要在它下面再加上就行了,不需要去改动到原来代码,此时你提交的代码的diff是长这样的:
const types = [ { name: '帅' }, { name: '阳光' }, + { + name: '可爱' + }, ] export { types };大家可以看到,只有简单的三行增量代码,如果你没有使用尾后逗号的话,你提交的代码的diff会是这样:
const types = [ { name: '帅' }, { name: '阳光' - } + }, + { + name: '可爱' + } ] export { types };因此我们可以得出尾后逗号它的作用:
「使得版本控制更加清晰,以及代码维护麻烦更少。」
(当然,这种用法在.json后缀的文件中是不能用的哈,因为JSON它严格遵循它自己的语法要求)
所以回归到这道题中来,像这种使用了多于一个尾后逗号的数组,我们就称之为稀疏数组,稀疏数组它的长度是等于逗号的数量的。
因此:
console.log([,,,].length) // 3https://github.com/LinDaiDai/niubility-coding-js/issues/37
这道题呆呆其实在很多地方都看到了,但是有的回答好像并不那么靠谱。
回答这道题首先我们需要知道一个概念:
浏览器环境:全局对象为window;而在node环境下,是有一个名为global的对象,它的内部Class属性是为"global"。
内部Class属性也就是我们通过Object.prototype.call(obj)这种方式来获取到的内容,比如:
console.log(Object.prototype.toString.call([1, 2, 3])); // "[object Array]"(关于它的用法呆呆在《【精】从206个console.log()完全弄懂数据类型转换的前世今生(上)》中的toString用法时说的也很详细咯)
因此我们可以得出这种判断方式:
var isBrowser = typeof window !== 'undefined' && ({}).toString.call(window) === '[object Window]'; var isNode = typeof global !== "undefined" && ({}).toString.call(global) == '[object global]';({}).toString.call()和Object.prototype.toString.call()用法一致,只不过在{}的外面最好加上一个(),也是为了预防JS将大括号{}认为是一个空的代码块(额,呆呆试了一下貌似也没有这方面的问题)。
https://github.com/LinDaiDai/niubility-coding-js/issues/38
reduce函数的第一个参数是一个回调函数,第二个参数为可选的初始值。
如果有初始值的话,回调函数就会从数组的第0项开始执行,也就是会执行arr.length次;
但是如果没有初始值的话,会默认取数组的第0项为初始值,回调函数会从数组的第1项开始执行,也就是会执行arr.length - 1次。
这点从我们手写一个reduce的实现就可以看出来,代码如下:
Array.prototype.MyReduce = function (fn, initialValue) { var arr = Array.prototype.slice.call(this); var pre, startIndex; pre = initialValue ? initialValue : arr[0]; startIndex = initialValue ? 0 : 1; for (var i = startIndex; i < arr.length; i++) { pre = fn.call(null, pre, arr[i], i, this) } return pre }过程分析:
首先,map、reduce这种方法都是数组原型对象上的方法,所以我将MyReduce定义在Array.prototype 上,这样你就可以直接使用ary.MyReduce()这样的方式调用它了(ary是一个类似于这样的数组[1, 2, 3])。
对于参数,我们参考原生reduce,它接收的第一个参数是一个回调函数,第二个是初始值
而var arr = ...的作用是获取调用MyReduce函数的那个变量,也就是说this会指向那个变量,例如ary.MyReduce(),那么此时this就为ary。
至于为什么不使用var arr = this;的方式而是使用Array.prototype.slice.call(this),算是实现一个浅拷贝吧,因为reduce是不会改变原数组的。
然后就是定义传入reduce中的回调函数的第一个参数pre,也就是上一次运行结果的返回值,可以看到这里就用到了初始值initialValue,如果存在初始值就取初始值,不存在则默认取数组第0项。(当然这里直接用initialValue ?来判断存不存在并不准确,因为我们知道0也会被判断为false)
接着是定义循环开始的下标startIndex,若是不存在初始值,则初始值是会取数组中的第0项的,相当于第0项并不需要运行,所以startIndex会是1,而如果有初始值的话则需要将数组的每一项都经过fn运行一下。
最后,for循环中使用fn.call()来调用fn函数,并且最后一个参数是要把原来的数组传递到回调函数中,也就是这里的this。
https://github.com/LinDaiDai/niubility-coding-js/issues/39
label标签不会向用户呈现任何特殊效果,它的作用是为鼠标用户改进了可用性。
也就是说当你使用了一个label标签和一个input绑定起来之后,点击label标签上的文字就会自动聚焦到input上。
如下:
绑定的方式:
label标签上设置for属性
input标签上设置和for属性一样的id
例如:
<label for="username">username:</label> <input type="text" name="username" id="username"/>这里有两点需要注意的:
这两个标签不一定非要在form标签内才会生效
for是和id对应的,并不是和name
https://github.com/LinDaiDai/niubility-coding-js/issues/40
大家在听到自动完成这个词,会有一点迷糊,自动完成什么?
其实这个功能的作用是这样的:
首先,autocomplete是一个属性,这个属性可以设置在form标签上,也可以设置在其它的input标签上。
被设置了自动完成的标签,会允许浏览器预测对字段的输入。也就是说浏览器会根据你在这个输入框中已经输入过的值,留有一个"历史记录",方便我们下次还想要输入同样的值。
例如下面这段代码:
<form autocomplete="on"> testaccount: <input type="text" name="testaccount" /><br /> testpassword: <input type="text" name="testpassword" autocomplete="off" /><br /> <input type="submit" /> </form>我把form标签的autocomplete打开,那么这个表单下的所有元素都开启了autocomplete
接着我把testpassword这一项的autocomplete关闭。
此时testaccout是有自动完成功能的,而testpassword没有。那么当我们第一次在这两个输入框中输入了内容并提交后。再次点击testaccout输入框,就会出现我们上一次输入并提交的那个值,而点击testpassword时却没有。
效果如下:
所以我们来做下总结吧????:
autocomplete属性规定输入字段是否应该启用自动完成功能;
它的默认值是启用,也就是"on",另一个值是"off"关闭;
作用是:允许浏览器预测对字段的输入。当用户在字段开始键入时,浏览器基于之前键入过的值,应该显示出在字段中填写的选项。
autocomplete 属性适用于<form>,以及下面的 <input> 类型:text, search, url, telephone, email, password, datepickers, range , color。
https://github.com/LinDaiDai/niubility-coding-js/issues/41
visibility会有这么几个个属性值:
visible
hidden
collapse
inherit
比较常用的可能是前面两个,用于控制元素的显示隐藏。且我们知道,设置为hidden是会隐藏元素,但是其他元素的布局不改变,相当于此元素变成透明。
inherit则是从父元素继承visibility属性的值。
而对于collapse,可能用的不是特别多,我们先来看下它的介绍:
对于一般的元素,它的表现跟hidden是一样的;
如果这个元素是table相关的元素,例如table行,table group,table列,table column group,它的表现却跟display: none一样,也就是说,它们占用的空间也会释放。
下面一起来看看这个案例????:
html代码:
<table> <tr class="tr1"> <td> tr1 </td> <td> tr1 </td> </tr> <tr> <td> tr2 </td> <td> tr2 </td> </tr> </table>css代码:
table { border: 1px solid red; } td { border: 1px solid blue; } .tr1 { }我在没给.tr1设置任何属性的时候,页面呈现的效果是这样的,很正常:
如果设置了visibility: hidden:
.tr1 { visibility: hidden; }效果如下:
虽然第一行被隐藏了,但是它的空间还是在的,就像是"隐身"了一样。
而如果设置了visibility: collapse:
.tr1 { visibility: collapse; }效果如下:
最终的效果会和display: none;一样。
如果你问呆呆这属性有什么实际的用处没有...咳咳,抱歉,好像还真没有????。也可能是呆呆不知道,知道的小伙伴还请提出哟,一起学习一哈。
https://github.com/LinDaiDai/niubility-coding-js/issues/42
这两个属性值相信大家都不陌生了,先让我们来看个案例理解一下:
html代码:
<div class="super"> <div class="sub1"> 我是呆呆的第一个崽 </div> <div class="sub2"> 我是呆呆的第二个崽 </div> <div class="sub3"> 我是呆呆的第三个崽 </div> </div>css代码:
.super { width: 200px; height: 100px; background: skyblue; } .sub1 { background: #d0e4a9; } .sub2 { width: 100%; background: #c077af; } .sub3 { width: auto; background: #f8d29d; }最开始时,三个崽表现的效果是一样的,并无很大差别:
此时如果我们对后面两个崽做一下改动:
.sub2 { width: 100%; padding-left: 10px; margin-left: 10px; background: #c077af; } .sub3 { width: auto; padding-left: 10px; margin-left: 10px; background: #f8d29d; }给他们都加上左内边距和左外边距,此时的效果就变成了这样:
大家会发现,设置了width: 100%的崽,它的宽度会和父级的一样,此时如果再给他设置了额外的padding,那它就会比父级还要宽了,也就是会超出父级容器。而因为还设置了margin-left,所以左边也会有一段距离。
但是设置了width: auto的崽就比较乖了,无论怎样它都不会超出父级,而是选择压缩自己的宽度。
因此我们可以得出结论:
两者的计算方式不同(这里的计算规则都是基于box-sizing: content-box;的情况):
对于width: auto;它的总宽度是等于父宽度的(这里的父宽度是指父级内容的宽度不包括padding、border、margin),即使给元素设置了padding、border、margin等属性,它也会自动分配水平空间。
对于width: 100%;它表示的是元素内容的宽度等于父宽度,所以它的总宽度是有可能超过父级的,因为如果设置了额外的padding、border,就可能比父级宽了。
无论是width:100%还是auto,其计算的参照都是父级内容区width值,而非总宽度值,也就是不包括padding、border、margin。
一般width:auto使用的多一些,因为这样灵活;而width:100%使用比较少,因为在增加padding或者margin的时候,容易使其突破父级框,破坏布局。
https://github.com/LinDaiDai/niubility-coding-js/issues/43
知识无价,支持原创。
参考文章:
《CSS里的visibility属性有个鲜为人知的属性值:collapse》https://www.webhek.com/post/visibility-collapse.html
《width:auto和width:100%的区别》https://blog.csdn.net/whaxrl/article/details/47166365
你盼世界,我盼望你无bug。这篇文章就介绍到这里。
您每周也许会花48小时的时间在工作????上,会花49小时的时间在睡觉????上,也许还可以再花20分钟的时间在呆呆的7道题上,日积月累,我相信我们都能见证彼此的成长????。
什么?你问我为什么系列的名字叫DD?因为呆呆呀,哈哈????。
喜欢「霖呆呆」的小伙还希望可以关注霖呆呆的公众号 LinDaiDai 或者扫一扫下面的二维码????????????。
img我会不定时的更新一些前端方面的知识内容以及自己的原创文章????
你的鼓励就是我持续创作的主要动力 ????。
往期题目可以戳下面????:
DD每周前端七题详解-第一期https://juejin.im/post/5ece0955e51d45784960ae58
DD每周前端七题详解-第二期
DD每周前端七题详解-第三期
DD每周前端七题详解-第四期
DD每周前端七题详解-第五期
或者你也可以查看github上的issues:https://github.com/LinDaiDai/niubility-coding-js/issues