前端分享--面试高频的 24 个 XX 和 XX 的区别

391 阅读8分钟

1. 箭头函数和普通函数的区别

a. 箭头函数和普通函数的样式不同,箭头函数语法更加简洁、清晰,箭头函数是=>定义函数,普通函数是function定义函数。

b. 箭头函数会捕获其所在上下文的 this 值,作为自己的 this 值,定义的时候就确定并固定了。

c. 箭头函数不能作为构造函数使用,也不能使用new关键字(因为箭头函数没有自己的this,它的this其实是继承了外层执行环境中的this,且this指向永远不会改变,作为构造函数其的this要是指向创建的新对象)。

d. 箭头函数没有自己的arguments。在箭头函数中访问arguments实际上获得的是外层局部(函数)执行环境中的值。

e. call、apply、bind 并不会影响其 this 的指向。

f. 箭头函数没有原型prototype。

g. 箭头函数不能当作 Generator 函数,不能使用 yield 关键字。

2. var,let和const之间的区别

从以下三个方面说。

变量提升方面:var声明的变量存在变量提升,即变量可以在声明之前调用,值为undefined。
let和const不存在变量提升问题(注意这个‘问题’后缀,其实是有提升的,只不过是let和const具有一个暂时性死区的概念,即没有到其赋值时,之前就不能用),即它们所声明的变量一定要在声明后使用,否则报错。

块级作用域方面:var不存在块级作用域,let和const存在块级作用域

声明方面:var允许重复声明变量,let和const在同一作用域不允许重复声明变量。其中const声明一个只读的常量(因为如此,其声明时就一定要赋值,不然报错)。一旦声明,常量的值就不能改变。

如何使const声明的对象内属性不可变,只可读呢?
如果const声明了一个对象,对象里的属性是可以改变的。

const obj={name:'小黄'};
obj.name='同学';
console.log(obj.name);//同学

因为const声明的obj只是保存着其对象的引用地址,只要地址不变,就不会出错。

使用Object.freeze(obj) 冻结obj,就能使其内的属性不可变,但它有局限,就是obj对象中要是有属性是对象,该对象内属性还能改变,要全不可变,就需要使用递归等方式一层一层全部冻结。

3. defer和async的区别

背景: <script> 文件不在html的<body>下方 会导致页面卡顿,这两个关键字都是解决这个问题的 前者有执行先后顺序 后者是没有顺序 但是两者都是立即下载

defer:中文意思是延迟。用途是表示脚本会被延迟到整个页面都解析完毕后再运行。因此,在<script>元素中设置defer属性,相当于告诉浏览器立即下载,但延迟执行。
HTML5规范要求脚本按照它们出现的先后顺序执行,因此第一个延迟脚本会先于第二个延迟脚本执行,但执行脚本之间存在依赖,需要有执行的先后顺序时,就可以使用defer,延迟执行。我觉得把script脚本放在body底部和defer差不多。

async:中文意思是异步,这个属性与defer类似,都用于改变处理脚本的行为。同样与defer类似,async只适用于外部脚本文件,并告诉浏览器立即下载文件。但与defer不同的是,标记为async的脚本并不保证按照它们的先后顺序执行。
指定async属性的目的是不让页面等待两个脚本下载和执行,从而异步加载页面其他内容,这使用于之间互不依赖的各脚本。 3244530200-60e830300f029.png

看到这里,就能知道其的一些作用了

当网页交给浏览器的HTML解析器转变成一系列的词语(Token)。解释器根据词语构建节点(Node),形成DOM树。因为JavaScript代码可能会修改DOM树的结构,所以节点是JavaScript代码的话,就需要停止当前DOM树的创建,直到JavaScript的资源加载并被JavaScript引擎执行后才继续DOM树的创建。
这里就会产生阻塞,出现白屏问题(白屏问题优化有很多方面,这里就脚本阻塞这一小点),我们就可以使用async和defer属性来解决JavaScript脚本阻塞问题。

当然最稳妥的办法还是把script标签放置在body的底部,没有兼容性问题,不会因此产生白屏问题,没有执行顺序问题。

4. async await对比promise的优缺点

async/await优点
a. 它做到了真正的串行的同步写法,代码阅读相对容易
b. 对于条件语句和其他流程语句比较友好,可以直接写到判断条件里面

function a() {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(222)
      }, 2222)
    })
  };
async function f() {
    try {
      if ( await a() === 222) {
        console.log('yes, it is!'// 会打印
      }
    } catch (err) {
      // ...
    }
  }

c. 处理复杂流程时,在代码清晰度方面有优势

async/await缺点
a. 无法处理promise返回的reject对象,要借助try...catch...

b. 用 await 可能会导致性能问题,因为 await 会阻塞代码,也许之后的异步代码并不依赖于前者,但仍然需要等待前者完成,导致代码失去了并发性。

//promise
Promise.all([ajax1(), ajax2()])

c. try...catch...内部的变量无法传递给下一个try...catch...,Promise和then/catch内部定义的变量,能通过then链条的参数传递到下一个then/catch,但是async/await的try内部的变量,如果用let和const定义则无法传递到下一个try...catch...,只能在外层作用域先定义好。

但async/await确确实实是解决了promise一些问题的。更加灵活的处理异步

promise的一些问题:
a. 一旦执行,无法中途取消,链式调用多个then中间不能随便跳出来

b. 错误无法在外部被捕捉到,只能在内部进行预判处理,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部

c. Promise内部如何执行,监测起来很难,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)

5.高阶函数与普通函数的区别

zhuanlan.zhihu.com/p/93331809

6.aynsc fetch ajax的区别?

zhuanlan.zhihu.com/p/264912752

7.对称加密 VS 非对称加密

对称加密中A和B会使用一个共享的密钥, A在发送数据之前,用这个密钥对数据加密。B在收到数据之后,用这个密钥对数据解密。因为加密解密用的是同一个密钥,所以这里的加密算法称为对称加密算法。

非对称加密使用两个密钥,一个是public key,一个是private key。通过一个特殊的数学算法,使得数据的加密和解密使用不同的密钥。因为用的是不同的密钥,所以称为非对称加密。非对称加密最著名的是RSA算法,这是以其发明者Rivest, Shamir 和Adleman命名。非对称加密算法里面的public key和private key在数学上是相关的,这样才能用一个加密,用另一个解密。不过,尽管是相关的,但以现有的数学算法,又没有办法从一个密钥,算出另一个密钥。

8.for VS forEach VS for...of VS for...in

关于迭代器Iterator的介绍:juejin.cn/post/699891…

for

for 循环与 forEach, for...of本质上的区别是for 循环是一种循环机制,只是能通过它遍历出数组,而 后两个是负责遍历(Array Set Map)可迭代对象的

forEach

for循环 while循环 for of 循环是可以通过break关键字跳出的,而forEach map这种循环是无法跳出的

首先break是用在循环体中的,forEach虽然是循环,但是代码写在回调函数里,这一点就直接决定forEach不能使用break。forEach其实是一个循环体和一个函数体的结合,循环体包裹着函数体,所以return只是跳出了函数体,但是并没有跳出循环体。

  • 只能用作遍历数组,不能遍历对象
  • 因为他是一个回调,所以不能使用break,return或continue来中断运行,一旦遍历就会遍历整个数组

for...in

  • 用作遍历对象
  • 也可以遍历数组,但是不推荐遍历数组,因为迭代的时候不一定是按照原顺序进行的,这无疑会影响数组的下标
  • 不仅会遍历对象自身的属性,还会遍历对象原型上的属性,这也是它和Object.keys的区别

for...of

for...of 语句创建一个循环来迭代可迭代的对象。在 ES6 中引入的 for...of 循环,以替代 for...in 和 forEach() ,并支持新的迭代协议。for...of 允许你遍历 Arrays(数组), Strings(字符串), Maps(映射), Sets(集合)等可迭代的数据结构等

  • 不能遍历对象
  • 是循环,所以可以使用break,return或者continue来中断
  • 最简洁、最直接的遍历数组元素的语法,避开了for-in循环的所有缺陷,解决了forEach的不可中断问题。