为什么 0.1 + 0.2 != 0.3,请详述理由
因为 JS 采纳 IEEE 754 双精度版本(64位),并且只有采纳 IEEE 754 的语言都有该问题。
咱们都晓得计算机示意十进制是采纳二进制示意的,所以 0.1
在二进制示意为
// (0011) 示意循环0.1 = 2^-4 * 1.10011(0011)
那么如何失去这个二进制的呢,咱们能够来演算下
小数算二进制和整数不同。乘法计算时,只计算小数位,整数位用作每一位的二进制,并且失去的第一位为最高位。所以咱们得出 0.1 = 2^-4 * 1.10011(0011)
,那么 0.2
的演算也根本如上所示,只须要去掉第一步乘法,所以得出 0.2 = 2^-3 * 1.10011(0011)
。
回来持续说 IEEE 754 双精度。六十四位中符号位占一位,整数位占十一位,其余五十二位都为小数位。因为 0.1
和 0.2
都是有限循环的二进制了,所以在小数位开端处须要判断是否进位(就和十进制的四舍五入一样)。
所以 2^-4 * 1.10011...001
进位后就变成了 2^-4 * 1.10011(0011 * 12次)010
。那么把这两个二进制加起来会得出 2^-2 * 1.0011(0011 * 11次)0100
, 这个值算成十进制就是 0.30000000000000004
上面说一下原生解决办法,如下代码所示
parseFloat((0.1 + 0.2).toFixed(10))
常⽤的meta标签有哪些
meta
标签由 name
和 content
属性定义,用来形容网页文档的属性,比方网页的作者,网页形容,关键词等,除了HTTP规范固定了一些name
作为大家应用的共识,开发者还能够自定义name。
罕用的meta标签:
(1)charset
,用来形容HTML文档的编码类型:
<meta charset="UTF-8" >
(2) keywords
,页面关键词:
<meta name="keywords" content="关键词" />
(3)description
,页面形容:
<meta name="description" content="页面形容内容" />
(4)refresh
,页面重定向和刷新:
<meta http-equiv="refresh" content="0;url=" />
(5)viewport
,适配挪动端,能够管制视口的大小和比例:
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
其中,content
参数有以下几种:
width viewport
:宽度(数值/device-width)height viewport
:高度(数值/device-height)initial-scale
:初始缩放比例maximum-scale
:最大缩放比例minimum-scale
:最小缩放比例user-scalable
:是否容许用户缩放(yes/no)
(6)搜索引擎索引形式:
<meta name="robots" content="index,follow" />
其中,content
参数有以下几种:
all
:文件将被检索,且页面上的链接能够被查问;none
:文件将不被检索,且页面上的链接不能够被查问;index
:文件将被检索;follow
:页面上的链接能够被查问;noindex
:文件将不被检索;nofollow
:页面上的链接不能够被查问。
说一下SPA单页面有什么优缺点?
长处:1.体验好,不刷新,缩小 申请 数据ajax异步获取 页面流程;2.前后端拆散3.加重服务端压力4.共用一套后端程序代码,适配多端毛病:1.首屏加载过慢;2.SEO 不利于搜索引擎抓取
const对象的属性能够批改吗
const保障的并不是变量的值不能改变,而是变量指向的那个内存地址不能改变。对于根本类型的数据(数值、字符串、布尔值),其值就保留在变量指向的那个内存地址,因而等同于常量。
但对于援用类型的数据(次要是对象和数组)来说,变量指向数据的内存地址,保留的只是一个指针,const只能保障这个指针是固定不变的,至于它指向的数据结构是不是可变的,就齐全不能管制了。
JS 隐式转换,显示转换
个别非根底类型进行转换时会先调用 valueOf,如果 valueOf 无奈返回根本类型值,就会调用 toString
字符串和数字
- "+" 操作符,如果有一个为字符串,那么都转化到字符串而后执行字符串拼接
- "-" 操作符,转换为数字,相减 (-a, a * 1 a/1) 都能进行隐式强制类型转换
[] + {} 和 {} + []
布尔值到数字
- 1 + true = 2
- 1 + false = 1
转换为布尔值
- for 中第二个
- while
- if
- 三元表达式
- || (逻辑或) && (逻辑与)右边的操作数
符号
- 不能被转换为数字
- 能被转换为布尔值(都是 true)
- 能够被转换成字符串 "Symbol(cool)"
宽松相等和严格相等
宽松相等容许进行强制类型转换,而严格相等不容许
字符串与数字
转换为数字而后比拟
其余类型与布尔类型
- 先把布尔类型转换为数字,而后持续进行比拟
对象与非对象
- 执行对象的 ToPrimitive(对象)而后持续进行比拟
假值列表
- undefined
- null
- false
- +0, -0, NaN
- ""
对盒模型的了解
CSS3中的盒模型有以下两种:规范盒子模型、IE盒子模型 盒模型都是由四个局部组成的,别离是margin、border、padding和content。
规范盒模型和IE盒模型的区别在于设置width和height时,所对应的范畴不同:
- 规范盒模型的width和height属性的范畴只蕴含了content,
- IE盒模型的width和height属性的范畴蕴含了border、padding和content。
能够通过批改元素的box-sizing属性来扭转元素的盒模型:
box-sizeing: content-box
示意规范盒模型(默认值)box-sizeing: border-box
示意IE盒模型(怪异盒模型)
如何阻止事件冒泡
- 一般浏览器应用:event.stopPropagation()
- IE浏览器应用:event.cancelBubble = true;
懒加载的概念
懒加载也叫做提早加载、按需加载,指的是在长网页中提早加载图片数据,是一种较好的网页性能优化的形式。在比拟长的网页或利用中,如果图片很多,所有的图片都被加载进去,而用户只能看到可视窗口的那一部分图片数据,这样就节约了性能。
如果应用图片的懒加载就能够解决以上问题。在滚动屏幕之前,可视化区域之外的图片不会进行加载,在滚动屏幕时才加载。这样使得网页的加载速度更快,缩小了服务器的负载。懒加载实用于图片较多,页面列表较长(长列表)的场景中。
常见的HTTP申请办法
- GET: 向服务器获取数据;
- POST:将实体提交到指定的资源,通常会造成服务器资源的批改;
- PUT:上传文件,更新数据;
- DELETE:删除服务器上的对象;
- HEAD:获取报文首部,与GET相比,不返回报文主体局部;
- OPTIONS:询问反对的申请办法,用来跨域申请;
- CONNECT:要求在与代理服务器通信时建设隧道,应用隧道进行TCP通信;
- TRACE: 回显服务器收到的申请,次要⽤于测试或诊断。
代码输入后果
Promise.reject('err!!!') .then((res) => { console.log('success', res) }, (err) => { console.log('error', err) }).catch(err => { console.log('catch', err) })
输入后果如下:
error err!!!
咱们晓得,.then
函数中的两个参数:
- 第一个参数是用来解决Promise胜利的函数
- 第二个则是解决失败的函数
也就是说Promise.resolve('1')
的值会进入胜利的函数,Promise.reject('2')
的值会进入失败的函数。
在这道题中,谬误间接被then
的第二个参数捕捉了,所以就不会被catch
捕捉了,输入后果为:error err!!!'
然而,如果是像上面这样:
Promise.resolve() .then(function success (res) { throw new Error('error!!!') }, function fail1 (err) { console.log('fail1', err) }).catch(function fail2 (err) { console.log('fail2', err) })
在then
的第一参数中抛出了谬误,那么他就不会被第二个参数不活了,而是被前面的catch
捕捉到。
行内元素有哪些?块级元素有哪些? 空(void)元素有那些?
- 行内元素有:
a b span img input select strong
; - 块级元素有:
div ul ol li dl dt dd h1 h2 h3 h4 h5 h6 p
;
空元素,即没有内容的HTML元素。空元素是在开始标签中敞开的,也就是空元素没有闭合标签:
- 常见的有:
<br>
、<hr>
、<img>
、<input>
、<link>
、<meta>
; - 鲜见的有:
<area>
、<base>
、<col>
、<colgroup>
、<command>
、<embed>
、<keygen>
、<param>
、<source>
、<track>
、<wbr>
。
代码输入后果
console.log(1)setTimeout(() => { console.log(2)})new Promise(resolve => { console.log(3) resolve(4)}).then(d => console.log(d))setTimeout(() => { console.log(5) new Promise(resolve => { resolve(6) }).then(d => console.log(d))})setTimeout(() => { console.log(7)})console.log(8)
输入后果如下:
13842567
代码执行过程如下:
- 首先执行script代码,打印出1;
- 遇到第一个定时器,退出到宏工作队列;
- 遇到Promise,执行代码,打印出3,遇到resolve,将其退出到微工作队列;
- 遇到第二个定时器,退出到宏工作队列;
- 遇到第三个定时器,退出到宏工作队列;
- 继续执行script代码,打印出8,第一轮执行完结;
- 执行微工作队列,打印出第一个Promise的resolve后果:4;
- 开始执行宏工作队列,执行第一个定时器,打印出2;
- 此时没有微工作,继续执行宏工作中的第二个定时器,首先打印出5,遇到Promise,首选打印出6,遇到resolve,将其退出到微工作队列;
- 执行微工作队列,打印出6;
- 执行宏工作队列中的最初一个定时器,打印出7。
对this对象的了解
this 是执行上下文中的一个属性,它指向最初一次调用这个办法的对象。在理论开发中,this 的指向能够通过四种调用模式来判断。
- 第一种是函数调用模式,当一个函数不是一个对象的属性时,间接作为函数来调用时,this 指向全局对象。
- 第二种是办法调用模式,如果一个函数作为一个对象的办法来调用时,this 指向这个对象。
- 第三种是结构器调用模式,如果一个函数用 new 调用时,函数执行前会新创建一个对象,this 指向这个新创建的对象。
- 第四种是 apply 、 call 和 bind 调用模式,这三个办法都能够显示的指定调用函数的 this 指向。其中 apply 办法接管两个参数:一个是 this 绑定的对象,一个是参数数组。call 办法接管的参数,第一个是 this 绑定的对象,前面的其余参数是传入函数执行的参数。也就是说,在应用 call() 办法时,传递给函数的参数必须一一列举进去。bind 办法通过传入一个对象,返回一个 this 绑定了传入对象的新函数。这个函数的 this 指向除了应用 new 时会被扭转,其余状况下都不会扭转。
这四种形式,应用结构器调用模式的优先级最高,而后是 apply、call 和 bind 调用模式,而后是办法调用模式,而后是函数调用模式。
什么是 DOM 和 BOM?
- DOM 指的是文档对象模型,它指的是把文档当做一个对象,这个对象次要定义了解决网页内容的办法和接口。
- BOM 指的是浏览器对象模型,它指的是把浏览器当做一个对象来看待,这个对象次要定义了与浏览器进行交互的法和接口。BOM的外围是 window,而 window 对象具备双重角色,它既是通过 js 拜访浏览器窗口的一个接口,又是一个 Global(全局)对象。这意味着在网页中定义的任何对象,变量和函数,都作为全局对象的一个属性或者办法存在。window 对象含有 location 对象、navigator 对象、screen 对象等子对象,并且 DOM 的最基本的对象 document 对象也是 BOM 的 window 对象的子对象。
写代码:实现函数可能深度克隆根本类型
浅克隆:
function shallowClone(obj) { let cloneObj = {}; for (let i in obj) { cloneObj[i] = obj[i]; } return cloneObj;}
深克隆:
- 思考根底类型
援用类型
- RegExp、Date、函数 不是 JSON 平安的
- 会失落 constructor,所有的构造函数都指向 Object
- 破解循环援用
function deepCopy(obj) { if (typeof obj === 'object') { var result = obj.constructor === Array ? [] : {}; for (var i in obj) { result[i] = typeof obj[i] === 'object' ? deepCopy(obj[i]) : obj[i]; } } else { var result = obj; } return result;}
Promise.any
形容:只有 promises
中有一个fulfilled
,就返回第一个fulfilled
的Promise
实例的返回值。
实现
Promise.any = function(promises) { return new Promise((resolve, reject) => { if(Array.isArray(promises)) { if(promises.length === 0) return reject(new AggregateError("All promises were rejected")); let count = 0; promises.forEach((item, index) => { Promise.resolve(item).then( value => resolve(value), reason => { count++; if(count === promises.length) { reject(new AggregateError("All promises were rejected")); }; } ); }) } else return reject(new TypeError("Argument is not iterable")); });}
为什么udp不会粘包?
- TCP协定是⾯向流的协定,UDP是⾯向音讯的协定。UDP段都是⼀条音讯,应⽤程序必须以音讯为单位提取数据,不能⼀次提取任意字节的数据
- UDP具备爱护音讯边界,在每个UDP包中就有了音讯头(消息来源地址,端⼝等信息),这样对于接收端来说就容易进⾏辨别解决了。传输协定把数据当作⼀条独⽴的音讯在⽹上传输,接收端只能接管独⽴的音讯。接收端⼀次只能接管发送端收回的⼀个数据包,如果⼀次承受数据的⼤⼩⼩于发送端⼀次发送的数据⼤⼩,就会失落⼀局部数据,即便失落,承受端也不会分两次去接管。
== 操作符的强制类型转换规定?
对于 ==
来说,如果比照单方的类型不一样,就会进行类型转换。如果比照 x
和 y
是否雷同,就会进行如下判断流程:
- 首先会判断两者类型是否雷同,雷同的话就比拟两者的大小;
- 类型不雷同的话,就会进行类型转换;
- 会先判断是否在比照
null
和undefined
,是的话就会返回true
- 判断两者类型是否为
string
和number
,是的话就会将字符串转换为number
1 == '1' ↓1 == 1
- 判断其中一方是否为
boolean
,是的话就会把boolean
转为number
再进行判断
'1' == true ↓'1' == 1 ↓ 1 == 1
- 判断其中一方是否为
object
且另一方为string
、number
或者symbol
,是的话就会把object
转为原始类型再进行判断
'1' == { name: 'js' } ↓'1' == '[object Object]'
应用 clear 属性革除浮动的原理?
应用clear属性革除浮动,其语法如下:
clear:none|left|right|both
如果单看字面意思,clear:left 是“革除左浮动”,clear:right 是“革除右浮动”,实际上,这种解释是有问题的,因为浮动始终还在,并没有革除。
官网对clear属性解释:“元素盒子的边不能和后面的浮动元素相邻”,对元素设置clear属性是为了防止浮动元素对该元素的影响,而不是革除掉浮动。
还须要留神 clear 属性指的是元素盒子的边不能和后面的浮动元素相邻,留神这里“后面的”3个字,也就是clear属性对“前面的”浮动元素是充耳不闻的。思考到float属性要么是left,要么是right,不可能同时存在,同时因为clear属性对“前面的”浮动元素充耳不闻,因而,当clear:left无效的时候,clear:right必然有效,也就是此时clear:left等同于设置clear:both;同样地,clear:right如果无效也是等同于设置clear:both。由此可见,clear:left和clear:right这两个申明就没有任何应用的价值,至多在CSS世界中是如此,间接应用clear:both吧。
个别应用伪元素的形式革除浮动:
.clear::after{ content:''; display: block; clear:both;}
clear属性只有块级元素才无效的,而::after等伪元素默认都是内联程度,这就是借助伪元素革除浮动影响时须要设置display属性值的起因。