浏览器眼中的0

0作为一个特殊的符号,经常会跟浏览器打交道,在不同的场景下,0代表的意思不尽相同,因此浏览器眼中的0不一定就是符合人们感官上的认识,那究竟浏览器会怎么对待它呢,今天我们就来探究一下各种场景中0的含义及浏览器的处理方式。

1.setTimeout

setTimeout在js中常用来推迟任务的执行,可以通过第二个参数设置延迟的毫秒数(如果不设置,默认为0),在一些代码中,可以看到delay=0的情况,如下:

window.setTimeout(() => { ...... }, 0);

了解js的同学应该知道,setTimeout的回调函数不会在定时器超时后立即执行,如果delay大于0,比较好理解,但delay是0的时候呢,浏览器会怎么对待呢,这里要分两种情况:
1.)timer嵌套
'Timers can be nested; after five such nested timers, however, the interval is forced to be at least four milliseconds.'也就是setTimeout嵌套超过5层的,并且延迟不到4ms,才会变成4ms,同样适用于setInterval,因此在这种情况下,delay=0其实会被设置成4;
2.)timer没有嵌套
在没有嵌套情况下,对于chrome来说,delay=0也会设置成1;
说完浏览器的处理方式之后,我们来看看网上搬过来的一个例子吧:

setTimeout(()=>{console.log(5)},5)setTimeout(()=>{console.log(4)},4)setTimeout(()=>{console.log(3)},3)setTimeout(()=>{console.log(2)},2)setTimeout(()=>{console.log(1)},1)setTimeout(()=>{console.log(0)},0)

chrome打印结果:1 0 2 3 4 5;
firefox打印结果:0 1 2 3 4 5;
edge打印结果:1 2 0 3 4 5;
qq浏览器打印结果:1 0 2 3 4 5;
360浏览器打印结果:1 0 2 3 4 5;
从上面的打印结果来看,firefox是符合代码预期的,edge打印与chrome稍有不同,应该是edge处理delay=0情况稍有不同(设置成了2),qq和360浏览器跟chrome保持一致。
0ms定时器
在MDN文档上,还说到一种实现0ms延时的定时器的实现方案,大体思路是自定义一个setZeroTimeout 方法,通过 postMessage 来触发定时回调的执行,具体可看 https://dbaron.org/log/20100309-faster-timeouts ;
node的setTimeout
说完浏览器中的setTimeout,我们再来看看nodejs中的是否一样呢,可以通过nodejs的源代码窥探一二:

// https://github.com/nodejs/node/blob/master/lib/internal/timers.jsfunction Timeout(callback, after, args, isRepeat, isRefed) {after *= 1; // Coalesce to number or NaNif (!(after >= 1 && after <= TIMEOUT_MAX)) { // const TIMEOUT_MAX = 2 ** 31 - 1;if (after > TIMEOUT_MAX) {process.emitWarning(`${after} does not fit into` +' a 32-bit signed integer.' + '\nTimeout duration was set t 1.', 'TimeoutOverflowWarning');}after = 1; // Schedule on next tick, follows browser behavior}

看过源代码后,就知道node的处理策略了:如果delay=0,会设置为1,注释也说得很清楚了,是为了遵循浏览器的行为。

2.+0&-0

虽然很少用到,但是js中确是存在+0和-0的,那么有什么区别呢:

+0 === -0; // true+0 === 0; // true-0 === 0; // true

可以看到,通过全等比较,+0,-0和0都是相等的,那是否就可以认为这三者就是一样的呢,还不能这么轻易下结论,有时候很有必要区分三者,那么如何判断呢,es6新增了一个方法Object.is(value1, value2),可以用来判断,具体效果如下:

Object.is(0, -0); // falseObject.is(+0, -0); // falseObject.is(+0, 0); // true

这里还需要说明的一点就是+0和0其实就是一样的,因为+0等效Number(0),因此Object.is(+0, 0)是符合预期的,这里顺带说一下Object.is的比较逻辑,根据MDN文档描述,
Object.is() 方法判断两个值是否为同一个值。如果满足以下条件则两个值相等:

  • 都是 undefined

  • 都是 null

  • 都是 true 或 false

  • 都是相同长度的字符串且相同字符按相同顺序排列

  • 都是相同对象(意味着每个对象有同一个引用)

  • 都是数字且

    • 都是 +0

    • 都是 -0

    • 都是 NaN

    • 或都是非零而且非 NaN 且为同一个值

== 运算不同。 == 运算符在判断相等前对两边的变量(如果它们不是同一类型) 进行强制转换 (这种行为的结果会将 "" == false 判断为 true ), 而 Object.is 不会强制转换两边的值。
=== 运算也不相同。 === 运算符 (也包括 == 运算符) 将数字 -0 和 +0 视为相等 ,而将Number.NaN 与NaN视为不相等.

最后来看下如何生成-0和+0吧:

1/-Infinity; // -00*-1;// -01/+Infinity;// +00*+1;// +0

3. +[]

由于存在类型转换,因此在判断相等时,会有这样的情况:

'' == 0; // true[] == 0; // true+[] == 0; // true

这里我们说一下+[]的情况,很容易理解,+相当于Number([]),最终会转换成0,这没什么大不了,如果是下面这段代码呢:

(![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[+!+[]+[!+[]+!+[]+!+[]]]+[+!+[]]+([+[]]+![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[!+[]+!+[]+[+[]]]

其实代表的就是alert(1), http://www.jsfuck.com/ 这个奇葩网站专门干这事的,原理就是使用的类型转换,把我们熟悉的代码变成了这样,真是骚操作。

4.font-size

font-size在css中使用频繁,浏览器通常会默认设置成14px或者16px。如果设置成0呢?

.foo {font-size: 0;}<span class="foo">foo</span>

文字真的就没有了,这符合预期,但如果设置的值小于12(非负),各浏览器处理稍有不同,chrome/edge浏览器会设置最小字体为12px,firefox严格按照给定的值来显示。
font-size:0的用处
在布局过程中,经常会生成空白字符,例如:

<div class="box1"><span>a</span><span>b</span></div><div class="box2"><img src="xxx.jpg"></div>

box1和box2高度其实是略高于实际的内容的,而且box1的两个span中间有间隙,没有紧挨着,因为空白字符的原因,引用css规范说明:On a block container element whose content is composed of inline-level elements, ‘line-height’ specifies the minimal height of line boxes within the element. The minimum height consists of a minimum height above the baseline and a minimum depth below it, exactly as if each line box starts with a zero-width inline box with the element’s font and line height properties. We call that imaginary box a “strut.”,大意就是一个块级容器元素内容区域由inline-level元素组成的;而这些linline-level元素被放在每一行的line-box里面,line-box高度是由它所有子元素的高度计算得出的。浏览器会计算这一行里每个子元素的高度,再得出 line-box 的高度(具体来说就是从子元素的最高点到最低点的高度)。默认情况下,一个 line-box 总是有足够的高度来容纳它的子元素,而每一个行框可以想象为默认会有一个宽度为0的空白节点,字体大小和行高会影响该节点,具体规范可查看 https://www.w3.org/TR/CSS2/visudet.html#line-height。
说完规范后,再来分析一下box1和box2的效果,为了便于理解,下面的代码手动加入了一个[x]符号,代表strut:

<div class="box1"><span>a</span> <span>b</span>[x]</div><div class="box2"><img src="xxx.jpg">[x]</div>

box1的两个span发生了换行,相当于中间有个空格,因此会有间隙,如果span不换行,那么中间的空隙也就没有了。由于存在[x],而且vertical-align:baseline的缘故,span/img和[x]的baseline对齐之后,[x]处于baseline以下的部分会撑开整个line-box的高度,因此会外部块级容器的高度会略高一些,说得不清楚,我们还是上一张图来说明吧:


粉色的线是图片的baseline,红色的线是strut的baseline,对齐之后strut的baseline下面还有一部分高度,box的最终高度就是img的顶部到strut底部之间的距离。分析完成因后,终于可以使用font-size:0来解决问题了,在box上设置font-size:0后,strut就相当于没有了,因此就不存在高度撑开的问题了,当然这里还可以改变img的vertical-align属性来修复这个问题,比如img{ vertical-align:bottom; }那么img的粉色线就跟strut的底部对齐了,也就不会撑开容器高度了,这里说了box2,box1原理差不多,这里涉及到vertical-align的知识了,可查阅https://www.w3.org/TR/CSS2/visudet.html#vertical-align 进行了解。

5.width&height

width和height也是可以设置成0的,效果也是符合我们预期的,但如果我们的意图是想通过设置0把元素隐藏的话,一般情况下会采用如下方案:

.visually-hidden {clip: rect(0 0 0 0);clip-path: inset(50%);height: 1px;width: 1px;overflow: hidden;position: absolute;white-space: nowrap;}

有些屏幕阅读器会忽略width和height等于0的元素,因此这里特意设置成1px,当然关于元素的隐藏还有很多实现方案,有兴趣可参考【1】;

6.line-height

line-height及行高,原意是baseline之间的高度,在css中就是一行的高度。默认情况下,line-height是跟具体字体定义相关联的,一般都是font-size的1.x倍,如果设置成0,在不同类型元素上的情况是不一样的,可分为如下三种情况:
1.)非置换行类元素
line-height定义的是最终参与计算line-box(行盒)的高度的值,而不会影响non-replaced inline element(非置换行类元素)的实际高度;

<style>.foo {line-height:0;}</style><div><span class="foo">a</span> // class为foo的span高度不会受样式影响</div>

2.)行类块级元素
会影响元素高度,如果line-height设置为0,那么该元素高度就变成了0,如果设置了height,那么height将会起作用;
3.)块级元素
当块级元素包含inline-level(display:inline|inline-block)元素时, 行高定义的每一个line-box(行盒)的最小高度,此外height也能影响块级元素的最终高度,height比line-height有更高优先级,当没有height情况下,line-height起作用;
上面提到了line-box,如果有不了解的同学,可以看一下文末的链接【2】;

7.transform

transform常用来做样式变化和动画,在有时候,会设置成如下形式:

transform: translateZ(0);

这其实是为了启用GPU加速渲染,元素会单独在一个绘制层(Layer)里进行绘制,而不会对其他层产生影响,因此也就少了很多计算和合成的功能,而且不会阻塞主线程,动画会更加流畅,当然元素设置太多会导致性能降低,因为需要内存的维护。

参考资料:

【1】https://css-tricks.com/comparing-various-ways-to-hide-things-in-css/
【2】https://www.w3.org/TR/CSS2/visuren.html#line-box

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/306526.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

剑指offer——01二维数组中的查找.

class Solution { public:bool Find(int target, vector<vector<int> > array) {int m array.size();//得到该二维数组的行数if(m0) return false;//如果行数为0则直接退出int n array[0].size();//得到该二维数组的列数if(n0) return false;//如果列数为0则直接退…

GraphQL:验证与授权

GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述&#xff0c;使得客户端能够准确地获得它需要的数据&#xff0c;而且没有任何冗余&#xff0c;也让 API 更容易地随着时间推移而演进&#xff0c…

python 创建目录_第二天:Python中目录及文件操作

Python创建目录使用os模块mkdir创建一级目录&#xff0c;但不会创建父级目录#创建test目录&#xff0c;成功 import os os.mkdir(E:test)##若无父级目录python,则创建test目录失败 import os os.mkdir(E:pythontest)makedirs可创建父级目录import os os.makedirs(E:pythontest)…

计算机科普小知识——U盘格式化

在格式化U盘的时候我们需要选择文件系统类型&#xff0c;分别有FAT32&#xff08;默认&#xff09;&#xff0c;NTFS和exFAT这三种格式 常见格式一&#xff1a;FAT32 FAT32是windows传统的文件格式&#xff0c;对每个分区只有4GB的容量&#xff0c;是任何一种usb存储设备都会预…

.NET 5干货来袭 嘉宾李杨桂素伟

Azure Show大家好&#xff0c;欢迎来到Azure Show第八期&#xff0c;好久不见&#xff01;因为工作的原因有两个月没和大家见面&#xff0c;但12月Azure Show回归&#xff0c;会有更多大家感兴趣的话题&#xff0c;也有更多嘉宾与大家见面。除了这一期&#xff0c;在12月我们还…

setnx和expire合成一条指令_Python 为什么只需一条语句“a,b=b,a”,就能直接交换两个变量?...

从接触 Python 时起&#xff0c;我就觉得 Python 的元组解包&#xff08;unpacking&#xff09;挺有意思&#xff0c;非常简洁好用。最显而易见的例子就是多重赋值&#xff0c;即在一条语句中同时给多个变量赋值&#xff1a;>>> x, y 1, 2 >>> print(x, y) …

计算机科普小知识——Win7系统32位与64位的区别,该如何选择?

Win7系统32位与64位的区别 首先我们要知道32位和64位指的是什么。其实这是根据CPU内的寄存器字长来确定的&#xff0c;计算机内部数据都是二进制来呈现的&#xff0c;32位的计算机CPU一次最多能处理32位的二进制数据&#xff0c;而64位的计算机CPU一次最多能处理64位的二进制数…

你知道这个C#开发跨平台APP的样例介绍开源项目吗?

站长英文太差就不翻译了&#xff0c;大家看效果图&#xff0c;都是使用Xamarin.Forms开发的开源移动App介绍&#xff0c;感兴趣的可以访问Github和Gitee仓库看看&#xff0c;下载对应的App项目研究。Github&#xff1a;https://github.com/jsuarezruiz/xamarin-forms-goodlooki…

mybatis plus 批量保存_mybatis源码分析

原理图&#xff1a;Configuration解析&#xff1a;Configuration表示配置&#xff0c;该对象中维护了很多mybatis的配置参数&#xff1b;大致可分为四部分&#xff1a;1.环境变量Environment 2.配置参数&#xff1b;3.缓存集合&#xff1b;4.插件及其他1.1环境变量EnvironmentE…

判断领导是在压榨你,还是在培养你?就看这5点!别被骗了!

职场&认知洞察 丨 作者 / findyi这是findyi公众号分享的第102篇原创文章前文写了职场PUA的文章&#xff0c;有读者问洋哥&#xff1a;我的领导有点像PUA&#xff0c;但又总是说要培养我&#xff0c;怎么破&#xff1f;读者问的问题并不是个案&#xff0c;前不久一个哥们挺郁…

java使用教程——组件及事件处理——窗口(设置窗口的颜色和背景)

用JFrame时&#xff0c;设置背景颜色需使用JFrame.getContentPane().setBackground(Color.red) Container conthis.getContentPane();//得到内容窗格 con.setBackground(Color.blue); 而使用Frame时则可以直接使用setBackground(Color.red)&#xff0c;且需要设置窗体默认关闭事…

揭秘软件开发的达摩克利斯之剑

↑ ???? 万字长文不想看&#xff0c;那就听一听叭 ↑为什么你的程序总是出现 bug&#xff1f;凭什么让改 bug 占据了你大部分的时间&#xff1f;看完本文&#xff0c;保证你能设计出更稳定的程序&#xff0c;摆脱 bug 的缠绕&#xff0c;做项目更安心&#xff01;记得我在学…

java使用教程——组件及事件处理——菜单(添加图标)

菜单条JMenuBar 菜单JMenu 菜单项JMenuItem menuFruit.addSeparator(); //在菜单添加分隔线 public class Example9_2 {public static void main(String args[]) {WindowMenu winnew WindowMenu("带菜单的窗口",20,30,600,290);} }C:/Users/86156/OneDrive/图片/水…

java使用教程——组件及事件处理——常用组件与布局

常用组件&#xff1a; 1.JTextField(文本框) 允许用户在文本框中输入单行文本 2.JTextArea(文本区) 允许用户文本区中输入多行文本 3.JLabel(标签) 标签为用户提供信息 4.JButton(按钮) 允许用户单击按钮 5.JCheckBox(复选框) 为用户提供多种选择 6.JComboBox(下拉列表&#xf…

数据库大战,AWS又将目标瞄准了微软SQL Server

喜欢就关注我们吧&#xff01;文|白开水AWS 宣布了一种新的数据库产品 — 用于 Aurora PostgreSQL 的 Babelfish。该产品旨在效仿 Microsoft 的 SQL Server&#xff0c;并吸引 SQL Server 用户迁移到 AWS 云平台。图片来源&#xff1a;techcrunchAWS 首席执行官 Andy Jassy 在 …

惊!Kubernetes 将弃用 Docker,开发者们怎么办?

喜欢就关注我们吧&#xff01;文|大东BE近日&#xff0c;Kubernetes 官方发布公告&#xff0c;宣布自 v1.20 起放弃对 Docker 的支持&#xff0c;届时用户将收到 Docker 弃用警告&#xff0c;并需要改用其他容器运行时。但 Docker 作为容器镜像构建工具的作用将不受影响&#x…

sql计算留存_SQL基础第七讲:关于用户留存率的计算

最近&#xff0c;好几个小伙伴都拿着关于用户留存的面试题来问我&#xff0c;所以今天单独开一篇文章讲一下留存问题。首先看一下留存是什么&#xff0c;简单来说&#xff0c;我和你今天在一家超市购物了&#xff0c;明天我来购物了&#xff0c;你没来&#xff0c;那么我就是这…

java实用教程——组件及事件处理——ActionEvent事件

事件源&#xff1a; 文本框&#xff0c;按钮&#xff0c;菜单项&#xff0c;密码框&#xff0c;单选按钮 注册监视器&#xff1a; 能够触发ActionEvent事件的组件使用方法 addActionListener(ActionListener listener) 处理事件接口&#xff1a; ActionListener接口中只有一个方…

【Azure Show】|第七期 特别版线上沙龙直播回顾. 嘉宾张坤段清华谭国欣柯克黄炜锵...

我是MVP 继与广州图书馆合作推出【搭上AI快车】在线公益课堂和大家分享了基于移动应用的人工智能开发经验后&#xff0c;本期继续与广州图书馆合作&#xff0c;邀请更多的微软技术专家&#xff0c;推出我们Azure Show节目的特别版&#xff0c;为大家带来各IT技术领域的经验分享…

java实用教程——组件及事件处理——ItemEvent事件(设置字体类型)

ItemEvent事件源&#xff1a; 选择框&#xff0c;下拉列表都可以触发ItemEvent事件 注册监视器&#xff1a; 能够触发ItemEvent事件的组件使用addItemListener(ItemListener listen) 将实现ItemListener的接口的类的实例注册为事件源的监视器 ItemListener接口&#xff1a; 接口…