集中前端面试中拷问的【20+种区别】

181 阅读16分钟

toPrecision 和 toFixed 和 Math.round 的区别?

toPrecision 用于处理精度,精度是从左至右第一个不为 0 的数开始数起。
toFixed 是对小数点后指定位数取整,从小数点开始数起。
Math.round 是将一个数字四舍五入到一个整数。

多种运算符

逗号运算符

逗号操作符对它的每个操作数求值(从左到右),并返回最后一个操作数的值。

expr1, expr2, expr3...

会返回最后一个表达式 expr3 的结果,其他的表达式只会进行求值。

function reverse(arr) {
    return [arr[0], arr[1]]=[arr[1], arr[0]], arr[0] + arr[1]
}
const list = [1, 2]
reverse(list)   // 返回 3,此时 list 为[2, 1]

零合并操作符 ??

零合并操作符 ?? 是一个逻辑操作符,当左侧的操作数为 null 或者 undefined 时,返回右侧操作数,否则返回左侧操作数。

expr1 ?? expr2

|| 是一个布尔逻辑运算符,左侧的操作数会被强制转换成布尔值用于求值。任何假值(0, '', NaN, null, undefined)都不会被返回。这导致如果你使用 0、''、NaN 作为有效值,就会出现不可预料的后果。

undefined || 'default' // 'default'
null || 'default'      // 'default'
false || 'default'     // 'default'
0 || 'default'         // 'default'

undefined ?? 'default' // 'default'
null ?? 'default'      // 'default'
false ?? 'default'     // 'false'
0 ?? 'default'         // 0

可选链操作符 ?.

?. 操作符的功能类似于 . 链式操作符,不同之处在于,在引用为 null 或者 undefined 的情况下不会引起错误,该表达式短路返回值是 undefined

?. 操作符允许读取位于连接对象链深处的属性的值,而不必验证链中的每个引用是否有效。

当尝试访问可能不存在的对象属性时,可选链操作符将会使表达式更短、更简明。

  1. 当调用不存在的对象的属性
const obj = {
  a: 'foo',
  b: {
    c: 'bar'
  }
}

obj.b?.c      //  bar
obj.d?.c     // undefined
obj.d   // undefined

以前可能会通过 obj && obj.a && obj.a.b 来获取一个深度嵌套的子属性,现在可以直接 obj?.a?.b 即可

  1. 当调用不存在的数组
obj.arr?.[index] //undefined

obj.arr[index] //报错

let a = [1,2,3]
a[6]?.v  //undefined

a[6].v  //报错
  1. 当调用不存在的函数
obj.fun?.() //undefined

obj.fun() //报错

有符号左移操作符 <<(位运算符 )

parseInt('ffffff', 16) = 16777215,而16777215刚好为2^24 - 1

1<<24 == 16777216

通过Math.random()*(1<<24)可以得到0~16777216之间的随机数

[].forEach.call($$("*"),function(a){
  a.style.outline="1px solid #"+(~~(Math.random()*(1<<24))).toString(16)
})


(1)选取页面所有 DOM 元素。在浏览器的控制台中可以使用$$()方法来获取页面中相应的元素,这是现代浏览器提供的一个命令行 API 相当于 document.querySelectorAll 方法。

(2)循环遍历 DOM 元素

(3)给元素添加 outline 。由于渲染的 outline 是不在 CSS 盒模型中的,所以为元素添加 outline 并不会影响元素的大小和页面的布局。

(4)只需要整数部分,使用取反操作符 ~ 连续两次取反获得整数部分,然后再用 toString(16) 的方式,转换为一个十六进制的字符串。

有符号右移操作符>> (位运算符 )

将第一个操作数向右移动指定的位数,多余的位移到右边被丢弃,高位补其符号位,正数补 0,负数则补 1。因为新的最左位与前一个最左位的值相同,所以符号位(最左位)不会改变。

一般用 有符号右移操作符>> 来将一个数除 2,相当于先舍弃小数位然后进行一次 Math.floor

10 >> 1    // 5
13 >> 1    // 6 相当于
13.8 >> 1  // 6
-13 >> 1   // -7 相当于
-13.8 >> 1 // -7 

无符号右移操作符 >>>(位运算符 )

将符号位作为二进制数据的一部分向右移动,高位始终补 0,对于正整数和算数右移没有区别,对于负数来说由于符号位被补 0,成为正数后就不用再求补码了,所以结果总是非负的。即便右移 0 个比特,结果也是非负的。

0b111>>>1  //3
(0b111>>>1).toString(2)   // "11"

此处注意toString()的写法,前面数字必须带括号,toString(2)是转换成二进制

(4).toString(2) // '100'
4.toString(2)  //报错

位运算符 &

判断奇偶数可以使用 & 1,正负数都适应

原理:使用 & 1,来判断二进制数的最低位是不是 1,这样除了最低位之外都被置 0,取余的结果只剩最低位。

const a = 5
!!(a & 1)                    // true
!!(a % 2)                    // true

位运算符 |

可以对一个数字 | 0 来取整,负数也同样适用

原理:使用位运算符时会抛弃小数位,我们可以利用这个特性来给数字取整,比如给任意数字 & 上二进制的 32 个 1,或者 | 上 0,显而易见后者简单些。

1.3 | 0         // 1
-1.9 | 0        // -1

双位运算符 ~~

替代正数的 Math.floor( ),替代负数的 Math.ceil( )。双否定位操作符的优势在于它执行相同的操作运行速度更快。

~~4.5                // 4
Math.floor(4.5)      // 4
Math.ceil(4.5)       // 5
 
~~-4.5               // -4
Math.floor(-4.5)     // -5
Math.ceil(-4.5)      // -4

undefined 与 undeclared 的区别?

已在作用域中声明但还没有赋值的变量,是 undefined 的。相反,还没有在作用域中声明过的变量,是 undeclared 的。

对于 undeclared 变量的引用,浏览器会报引用错误,如 ReferenceError: b is not defined 。但是我们可以使用 typeof 的安全防范机制来避免报错,因为对于 undeclared(或者 not defined )变量,typeof 会返回 "undefined"。

null 和 undefined 的区别?

  1. Undefined 和 Null 都是基本数据类型,这两个基本数据类型分别都只有一个值,就是 undefined 和 null。

  2. undefined 代表的含义是未定义,null 代表的含义是空对象(尚未创建的对象)。

  3. 一般变量声明了但还没有定义的时候会返回 undefined,null主要用于赋值给一些可能会返回对象的变量,作为初始化。

undefined 在 js 中不是一个保留字,这意味着我们可以使用 undefined 来作为一个变量名,这样的做法是非常危险的,它会影响我们对 undefined 值的判断。但是我们可以通过一些方法获得安全的 undefined 值,比如说 void 0。

  1. typeof undefined/null

typeof undefined //"undefined"

typeof null // "object" 这是一个历史遗留的问题,在JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于 null 代表的是空指针(大多数平台下值为 0x00),因此,null的类型标签也成为了 0,typeof null就错误的返回了”object”。在ES6中,当时曾经有提案为历史平凡, 将type null的值纠正为null, 但最后提案被拒了,所以还是保持”object”类型。

  1. == 和 ===

null == undefined //true

null === undefined //false

  1. 如何判断null和undefined?
  • null使用严格相等符===或不相等操作符!==判断
  • undefined使用严格相等符===或不相等操作符!== 和 typeof
  1. Number(null/undefined)
  • Number(null) // 0

  • Number(undefined) // NaN

  1. 用处 null的使用:
  • 如果定义的变量在将来用于保存对象,那么最好将该变量初始化为null
  • 当一个数据不再需要使用时,我们最好通过将其值设置为null来释放其引用,这个做法叫做解除引用

undefined:变量最好初始化,否则会等于undefined

Number()、parseInt() 和 parseFloat() 的区别

1. 如果是数字值

  • Number() 和 parseFloat() 只是简单的传入和返回。
  • parseInt() 根据基模式取整
Number(1.1); //1.1
parseInt(1.1)  // 1
parseFloat(1.1)  // 1.1

处理整数的时候parseInt()更常用

. 如果是字符串

  • parseInt()和parseFloat()相同点:在转换字符串时,会忽略字符串前面的空格,直到找到第一个非空格字符,如果第一个字符是数字字符,会继续解析第二个字符,直到解析完所有后续字符串或者遇到了一个非数字字符,如果第一个字符不是数字或者负号, 就会返回NaN,同样的,转换空字符串也会返回NaN。

  • parseInt()和parseFloat()不同点:

parseFloat() 所解析的字符串中第一个小数点是有效的; parseInt() 遇到小数点会停止解析,因为小数点并不是有效的数字字符。

parseFloat() 始终会忽略前导的零,十六进制格式的字符串始终会被转换成0; parseInt() 第二个参数可以设置基数,按照这个基数的进制来转换。

parseFloat() 只解析十进制,因此它没有第二个参数指定基数的用法; parseInt()方法有基模式,可以把二进制、八进制、十六进制或其他任何进制的字符串转换成整数;

 Number("123AF");  //NaN
 parseInt("123AF");     //123
 parseFloat("123AF");  //123
 
 
 Number("0xA");  //10
 parseInt("0xA");     //10
 parseFloat("0xA");   //0
Number(""); //0
parseInt('')  // NaN
parseFloat('')  // NaN


Number("Hello");   //NaN
parseInt('Hello')  // NaN
parseFloat('Hello')  // NaN

Number(" 1.1a");   //NaN
parseInt(' 1.1a')  // 1
parseFloat(' 1.1a')  // 1.1

Number(" a1.1 ");   //NaN
parseInt(" a1.1 ")  // NaN
parseFloat(" a1.1 ")  // NaN

Number('1.1.1')  // NaN
parseInt("1.1.1")  // 1
parseFloat("1.1.1")  // 1.1
Number("1.1");   //1
parseInt('1.1')  // 1
parseFloat('1.1')  // 1.1
  • Number()

1) 如果字符串中只包含数字时,将其转换为十进制数值,忽略前导0

2) 如果字符串中包含有效浮点格式,如“1.1”,将其转换为对应的浮点数字,忽略前导0

3) 如果字符串中包含有效的十六进制格式,如“0xf”,将其转换为相同大小的十进制数值

4) 如果字符串为空,将其转换为0

5) 如果字符串中包含除上述格式之外的字符,则将其转换为NaN

Number("Hello world");       //NaN
Number("");            //0
Number("0000011");        //11

3. 其他类型

  • parseInt() 和 parseFloat()都返回NaN

  • Number()

1)如果是布尔值,true和false值将分别被转换为1和0。

Number(true) // 1
Number(false) // 0

2)如果是null和undefined

Number(null) // 0
Number(undefined) // NaN

3)如果是对象

调用对象的valueOf()方法,然后依照前面的规则转换返回的值。如果转换的结果是NaN,则调用对象的toString()方法,然后再依照前面的规则转换返回的字符串值。

isNaN() 和 Number.isNaN() 函数的区别?

isNaN() 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断

Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,这种方法对于 NaN 的判断更为准确。

documen.write 和 innerHTML 的区别?

document.write 的内容会代替整个文档内容,会重写整个页面,会导致页面全部重绘

innerHTML 的内容只是替代指定元素的内容,只会重写页面中的部分内容,不会导致页面全部重绘

innerHTML 与 outerHTML 的区别

对于这样一个 HTML 元素:<div>content<br/></div>

innerHTML:内部 HTMLcontent<br/>;
outerHTML:外部 HTML,<div>content<br/></div>;
innerText:内部文本,content

.call() 、.apply() 的区别

它们的作用一模一样,区别在于传入参数的形式的不同。

apply 接受两个参数,第一个参数指定了函数体内 this 对象的指向,第二个参数为一个带下标的集合,这个集合可以为数组,也可以为类数组,apply 方法把这个集合中的元素作为参数传递给被调用的函数。

call 传入的参数数量不固定,跟 apply 相同的是,第一个参数也是代表函数体内的 this 指向,从第二个参数开始往后,每个参数被依次传入函数。

Object.is() 与原来的比较操作符 “===”、“==” 的区别

使用==进行相等判断时,如果两边的类型不一致,则会进行强制类型转化后再进行比较。

使用===进行相等判断时,如果两边的类型不一致时,不会做强制类型准换,直接返回 false。

Object.is 在三等号判等的基础上特别处理了 NaN 、-0 和 +0 ,保证 -0 和 +0 不再相同,但 Object.is(NaN, NaN) 会返回 true.

Object.is 应被认为有其特殊的用途,而不能用它认为它比其它的相等对比更宽松或严格。

使用 Object.is 来进行相等判断时,一般情况下和三等号的判断相同,它处理了一些特殊的情况,比如 -0 和 +0 不再相等,两个 NaN 认定为是相等的。

escape、encodeURI、encodeURIComponent 的区别

  • escape是对字符串进行编码,作用是让它们在所有电脑上可读。编码之后的效果是%XX或者%uXXXX这种形式。其中 ASCII字母、数字、@*/+ ,这几个字符不会被编码,其余的都会。

注意:这个方法是针对字符串使用的,不适用于URL。

  • encodeURI和encodeURIComponent都是对RUL编码,唯一区别就是编码的字符范围,其中

encodeURI方法不会对下列字符编码:
ASCII字母、数字、~!@#$&*()=:/,;?+'

encodeURIComponent方法不会对下列字符编码 :
ASCII字母、数字、~!*()'

也就是encodeURIComponent编码的范围更广,会将http://XXX中的//也编码,会导致URL不可用。

总之:

  • 如果只是编码字符串,不和URL有半毛钱关系,那么用escape,而且这个方法一般不会用到。
  • 如果你需要编码整个URL,然后需要使用这个URL,那么用encodeURI。
  • 当你需要编码URL中的参数的时候,那么encodeURIComponent是最好方法。
var param = "中文";
    console.log(escape(param)); //%u4E2D%u6587
    console.log(encodeURI(param)); //%E4%B8%AD%E6%96%87
    console.log(encodeURIComponent(param)); //%E4%B8%AD%E6%96%87
escape("http://www.w3school.com.cn/")
// http%3A//www.w3school.com.cn

escape("?!=()#%&")
//%3F%21%3D%28%29%23%25%26
encodeURI("http://www.w3school.com.cn/")
// http://www.w3school.com.cn/

encodeURI("http://www.w3school.com.cn/My first/")
// http://www.w3school.com.cn/My%20first/

encodeURI(",/?:@&=+$#")
//,/?:@&=+$#

对整个URL进行编码,而URL的特定标识符不会被转码。
encodeURIComponent("http://www.w3school.com.cn/")
// http%3A%2F%2Fwww.w3school.com.cn

encodeURIComponent("http://www.w3school.com.cn/p 1/")
// http%3A%2F%2Fwww.w3school.com.cn%2Fp%201%2F

encodeURIComponent(",/?:@&=+$#")
// %2C%2F%3F%3A%40%26%3D%2B%24%23

<a href="http://passport.baidu.com/?logout&aid=7&u='+encodeURIComponent("http://cang.baidu.com/bruce42")+'">退出</a>');</script>URL中的参数进行编码,因为参数也是一个URL,如果不编码会影响整个URL的跳转。

(Weak)Set、(Weak)Map的区别

看另一篇(Weak)Set和(Weak)Map你都懂吗

map和forEach的区别

var array = [1,2,3,4,5]; 
var x = array.forEach(function(value,index){     
	console.log(value);   //1 2 3 4 5  可遍历到所有数组元素       
	return value + 10
});
console.log(x);   //undefined    无论怎样,总返回undefined var y = array.map(function(value,index){     
	console.log(value);   //1 2 3 4 5 可遍历到所有数组元素     
	return value + 10
});
console.log(y);   //[11, 12, 13, 14, 15]

forEach() 方法对数组的每个元素执行一次提供的函数。总是返回undefined;

map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。返回值是一个新的数组;

substr、substring、 slice区别

参数都是正数

  • slice接收的是起始位置和结束位置(不包括结束位置)
  • substring接收的是起始位置和结束位置(不包括结束位置)
  • substr接收的则是起始位置和所要返回的字符串长度。

注:substring是以两个参数中较小一个作为起始位置,较大的参数作为结束位置

var test = 'hello world';

test.slice(4,7)             //o w
test.substring(4,7)        //o w
test.substr(4,7)           //o world

test.substring(7,4)          //o w

接收的参数有负数

  • slice会将它字符串的长度与对应的负数相加,结果作为参数
  • substring则干脆将负参数都直接转换为0
  • substr则仅仅是将第一个参数与字符串长度相加后的结果作为第一个参数
var test = 'hello world';  

test.slice(-3)        //rld    
test.substring(-3)    //hello world   
test.substr(-3)        //rld    
test.slice(3,-4)       //lo w    
test.substring(3,-4)   //hel    
test.substr(3,-4)      //空字符串

offsetWidth/offsetHeight、clientWidth/clientHeight 与 scrollWidth/scrollHeight 的区别?

clientWidth/clientHeight 返回的是元素的内部宽度,它的值只包含 content + padding,如果有滚动条,不包含滚动条。

clientTop 返回的是上边框的宽度。

clientLeft 返回的左边框的宽度。

offsetWidth/offsetHeight 返回的是元素的布局宽度,它的值包含 content + padding + border 包含了滚动条。

offsetTop 返回的是当前元素相对于其 offsetParent 元素的顶部的距离。

offsetLeft 返回的是当前元素相对于其 offsetParent 元素的左部的距离。

scrollWidth/scrollHeight 返回值包含 content + padding + 溢出内容的尺寸。

scrollTop 属性返回的是一个元素的内容垂直滚动的像素数。

scrollLeft 属性返回的是元素滚动条到元素左边的距离。

URL 和 URI 的区别?

URI: Uniform Resource Identifier      指的是统一资源标识符
URL: Uniform Resource Location        指的是统一资源定位符
URN: Universal Resource Name          指的是统一资源名称

URI 指的是统一资源标识符,用唯一的标识来确定一个资源,它是一种抽象的定义,也就是说,不管使用什么方法来定义,只要能唯一的标识一个资源,就可以称为 URI。

URL 指的是统一资源定位符,URN 指的是统一资源名称。URL 和 URN 是 URI 的子集,URL 可以理解为使用地址来标识资源,URN 可以理解为使用名称来标识资源。

get 和 post 请求在缓存方面的区别

缓存一般只适用于那些不会更新服务端数据的请求。

一般 get 请求都是查找请求,不会对服务器资源数据造成修改,而 post 请求一般都会对服务器数据造成修改,所以,一般会对 get 请求进行缓存,很少会对 post 请求进行缓存。

ajax axios 和 fetch 的区别

看我的另一篇ajax 、axios、fetch的区别

defer 和 async 的区别

defer 这个属性会让脚本的加载(下载)与文档的解析同步,然后在文档解析完成后再执行这个脚本文件,这样的话就能使页面的渲染不被阻塞。多个设置了 defer 属性的脚本按规范来说最后是顺序执行的,但是在一些浏览器中可能不是这样。

比如:

<script src="file.js" defer> </script>

并行下载 file.js和其它有 defer 属性的script,执行是依照顺序执行的

async 这个属性会使脚本异步加载,不会阻塞页面的解析过程,但是当脚本加载完成后立即执行 js 脚本,这个时候如果文档没有解析完成的话同样会阻塞。多个 async 属性的脚本的执行顺序是不可预测的,一般不会按照代码的顺序依次执行。 它们将在onload 事件之前完成。

<script src="file.js" async> </script>

async属性是HTML5新增的。它将在下载后尽快执行,不能保证脚本会按顺序执行。

border:none以及border:0的区别

  1. 效果

边框样式无

border: none 

border-style:none;

边框宽度为0px

border: 0 

border-width:0;
  1. 性能差异

border:0;

浏览器对border-width、border-color进行渲染,占用内存。

border:none;

浏览器不进行渲染,不占用内存。

  1. 计算出的样式

Chrome:

border:none;
border:initial none initial;

border:0;
border:0 initial  initial ;

Firefox、360:

border:none; 
border:medium none;

border:0;
border:0 none;
  1. 浏览器兼容
  • IE7-不支持border:none;
  • W3C提示:请始终把border-style属性声明到border-color属性之前,元素必须在改变颜色之前获得边框。

错误说法:

  1. 当定义了border:none,即隐藏了边框的显示,实际就是边框宽度为0

  2. 当定义边框时,仅设置边框宽度也可以达到显示的效果

几个阻止行为的区别

  • preventDefault() 阻止事件默认行为
  • stopPropagation() W3C标准的阻止冒泡 ,作用在后续节点上,目的在执行完绑定到当前元素上的所有事件处理程序之后,停止执行所有后续节点的事件处理程序
  • stopImmediatePropagation 作用在当前节点以及事件链上的所有后续节点上,目的是在执行完当前事件处理程序之后,停止当前节点以及所有后续节点的事件处理程序的运行
  • cancelBubble() ie的阻止冒泡

transform 、 translate、 transition、 animation区别

  • transform:应用于元素的2D或3D转换。这个属性允许你将元素旋转,缩放,移动,倾斜等;
  • translate:移动,是transform的一个方法
  • transition:属性是一个简写属性,用于设置四个过渡属性:
    transition-property
    transition-duration
    transition-timing-function
    transition-delay
  • animation 属性是一个简写属性,用于设置六个动画属性:
    animation-name
    animation-duration
    animation-timing-function
    animation-delay
    animation-iteration-count
    animation-direction

link和@import的区别:

  • link是XHTML标签,无兼容问题;@import是在CSS2.1提出的,低版本的浏览器不支持。
  • link可以加载CSS,Javascript;@import只能加载CSS。
  • link加载的内容是与页面同时加载;@import需要页面网页完全载入以后加载。
  • 写法不同 link的写法
<link rel="stylesheet" href="index.css">

import的写法:

<style type=”text/css”>
    @import url(“index.css”);
</style>