拿到大厂前端offer的前端开发是怎么回答面试题的

前端工作2年,因Flutter拿到了阿里咸鱼offer,背后的努力值得我们学习 前言 在出现Flutter 起,有不少互联网大厂投入实践,先是有闲鱼团队大规模引入 Flutter,后有飞猪、百度贴吧、今日头条、西瓜视频、美团外卖、京东商城等团队在多个场景下落地了 Flutter 项目。而我一个大学室友看准了风口,工作两年了,决定转战Flutter,目标阿里咸鱼,这对于他来说是个挑战,在Flutter这方面知识还是有所欠缺,就疫情那会为准备面试在家学习Flutter,学的脑袋嗡嗡的,好在最后拿到了阿里咸鱼offer。 Flutter面试准备 简单看一个框架知识点肯定是不行,就了解了Flu 阅读详情

什么情况会阻塞渲染?

首先渲染的前提是生成渲染树,所以 HTML 和 CSS 肯定会阻塞渲染。如果你想渲染的越快,你越应该降低一开始需要渲染的文件大小,并且扁平层级,优化选择器。然后当浏览器在解析到 script 标签时,会暂停构建 DOM,完成后才会从暂停的地方重新开始。也就是说,如果你想首屏渲染的越快,就越不应该在首屏就加载 JS 文件,这也是都建议将 script 标签放在 body 标签底部的原因。

当然在当下,并不是说 script 标签必须放在底部,因为你可以给 script 标签添加 defer 或者 async 属性。当 script 标签加上 defer 属性以后,表示该 JS 文件会并行下载,但是会放到 HTML 解析完成后顺序执行,所以对于这种情况你可以把 script 标签放在任意位置。对于没有任何依赖的 JS 文件可以加上 async 属性,表示 JS 文件下载和解析不会阻塞渲染。

对浏览器的缓存机制的理解

浏览器缓存的全过程:

  • 浏览器第一次加载资源,服务器返回 200,浏览器从服务器下载资源文件,并缓存资源文件与 response header,以供下次加载时对比使用;

  • 下一次加载资源时,由于强制缓存优先级较高,先比较当前时间与上一次返回 200 时的时间差,如果没有超过 cache-control 设置的 max-age,则没有过期,并命中强缓存,直接从本地读取资源。如果浏览器不支持HTTP1.1,则使用 expires 头判断是否过期;

  • 如果资源已过期,则表明强制缓存没有被命中,则开始协商缓存,向服务器发送带有 If-None-Match 和 If-Modified-Since 的请求;

  • 服务器收到请求后,优先根据 Etag 的值判断被请求的文件有没有做修改,Etag 值一致则没有修改,命中协商缓存,返回 304;如果不一致则有改动,直接返回新的资源文件带上新的 Etag 值并返回 200;

  • 如果服务器收到的请求没有 Etag 值,则将 If-Modified-Since 和被请求文件的最后修改时间做比对,一致则命中协商缓存,返回 304;不一致则返回新的 last-modified 和文件并返回 200;

    很多网站的资源后面都加了版本号,这样做的目的是:每次升级了 JS 或 CSS 文件后,为了防止浏览器进行缓存,强制改变版本号,客户端浏览器就会重新下载新的 JS 或 CSS 文件 ,以保证用户能够及时获得网站的最新更新。

HTTP状态码

  • 1xx 信息性状态码 websocket upgrade
  • 2xx 成功状态码
    • 200 服务器已成功处理了请求
    • 204(没有响应体)
    • 206(范围请求 暂停继续下载)
  • 3xx 重定向状态码
    • 301(永久) :请求的页面已永久跳转到新的url
    • 302(临时) :允许各种各样的重定向,一般情况下都会实现为到 GET 的重定向,但是不能确保 POST 会重定向为 POST
    • 303 只允许任意请求到 GET 的重定向
    • 304 未修改:自从上次请求后,请求的网页未修改过
    • 307:307 和 302 一样,除了不允许 POST 到 GET 的重定向
  • 4xx 客户端错误状态码
    • 400 客户端参数错误
    • 401 没有登录
    • 403 登录了没权限 比如管理系统
    • 404 页面不存在
    • 405 禁用请求中指定的方法
  • 5xx 服务端错误状态码
    • 500 服务器错误:服务器内部错误,无法完成请求
    • 502 错误网关:服务器作为网关或代理出现错误
    • 503 服务不可用:服务器目前无法使用
    • 504 网关超时:网关或代理服务器,未及时获取请求

前端储存的⽅式有哪些?

  • cookies: 在HTML5标准前本地储存的主要⽅式,优点是兼容性好,请求头⾃带cookie⽅便,缺点是⼤⼩只有4k,⾃动请求头加⼊cookie浪费流量,每个domain限制20个cookie,使⽤起来麻烦,需要⾃⾏封装;
  • localStorage:HTML5加⼊的以键值对(Key-Value)为标准的⽅式,优点是操作⽅便,永久性储存(除⾮⼿动删除),⼤⼩为5M,兼容IE8+ ;
  • sessionStorage:与localStorage基本类似,区别是sessionStorage当⻚⾯关闭后会被清理,⽽且与cookie、localStorage不同,他不能在所有同源窗⼝中共享,是会话级别的储存⽅式;
  • Web SQL:2010年被W3C废弃的本地数据库数据存储⽅案,但是主流浏览器(⽕狐除外)都已经有了相关的实现,web sql类似于SQLite,是真正意义上的关系型数据库,⽤sql进⾏操作,当我们⽤JavaScript时要进⾏转换,较为繁琐;
  • IndexedDB: 是被正式纳⼊HTML5标准的数据库储存⽅案,它是NoSQL数据库,⽤键值对进⾏储存,可以进⾏快速读取操作,⾮常适合web场景,同时⽤JavaScript进⾏操作会⾮常便。

网络劫持有哪几种,如何防范?

⽹络劫持分为两种:

(1)DNS劫持: (输⼊京东被强制跳转到淘宝这就属于dns劫持)

  • DNS强制解析: 通过修改运营商的本地DNS记录,来引导⽤户流量到缓存服务器
  • 302跳转的⽅式: 通过监控⽹络出⼝的流量,分析判断哪些内容是可以进⾏劫持处理的,再对劫持的内存发起302跳转的回复,引导⽤户获取内容

(2)HTTP劫持: (访问⾕歌但是⼀直有贪玩蓝⽉的⼴告),由于http明⽂传输,运营商会修改你的http响应内容(即加⼴告)

DNS劫持由于涉嫌违法,已经被监管起来,现在很少会有DNS劫持,⽽http劫持依然⾮常盛⾏,最有效的办法就是全站HTTPS,将HTTP加密,这使得运营商⽆法获取明⽂,就⽆法劫持你的响应内容。

快排–时间复杂度 nlogn~ n^2 之间

题目描述:实现一个快排

实现代码如下:

function quickSort(arr) {
  if (arr.length < 2) {
    return arr;
  }
  const cur = arr[arr.length - 1];
  const left = arr.filter((v, i) => v <= cur && i !== arr.length - 1);
  const right = arr.filter((v) => v > cur);
  return [...quickSort(left), cur, ...quickSort(right)];
}
// console.log(quickSort([3, 6, 2, 4, 1]));

参考 前端进阶面试题详细解答

同步和异步的区别

  • 同步指的是当一个进程在执行某个请求时,如果这个请求需要等待一段时间才能返回,那么这个进程会一直等待下去,直到消息返回为止再继续向下执行。
  • 异步指的是当一个进程在执行某个请求时,如果这个请求需要等待一段时间才能返回,这个时候进程会继续往下执行,不会阻塞等待消息的返回,当消息返回时系统再通知进程进行处理。

如何防御 XSS 攻击?

可以看到XSS危害如此之大, 那么在开发网站时就要做好防御措施,具体措施如下:

  • 可以从浏览器的执行来进行预防,一种是使用纯前端的方式,不用服务器端拼接后返回(不使用服务端渲染)。另一种是对需要插入到 HTML 中的代码做好充分的转义。对于 DOM 型的攻击,主要是前端脚本的不可靠而造成的,对于数据获取渲染和字符串拼接的时候应该对可能出现的恶意代码情况进行判断。
  • 使用 CSP ,CSP 的本质是建立一个白名单,告诉浏览器哪些外部资源可以加载和执行,从而防止恶意代码的注入攻击。
  1. CSP 指的是内容安全策略,它的本质是建立一个白名单,告诉浏览器哪些外部资源可以加载和执行。我们只需要配置规则,如何拦截由浏览器自己来实现。
  2. 通常有两种方式来开启 CSP,一种是设置 HTTP 首部中的 Content-Security-Policy,一种是设置 meta 标签的方式
  • 对一些敏感信息进行保护,比如 cookie 使用 http-only,使得脚本无法获取。也可以使用验证码,避免脚本伪装成用户执行一些操作。

数组的遍历方法有哪些

方法是否改变原数组特点
forEach()否数组方法,不改变原数组,没有返回值
map()否数组方法,不改变原数组,有返回值,可链式调用
filter()否数组方法,过滤数组,返回包含符合条件的元素的数组,可链式调用
for…of否for…of遍历具有Iterator迭代器的对象的属性,返回的是数组的元素、对象的属性值,不能遍历普通的obj对象,将异步循环变成同步循环
every() 和 some()否数组方法,some()只要有一个是true,便返回true;而every()只要有一个是false,便返回false.
find() 和 findIndex()否数组方法,find()返回的是第一个符合条件的值;findIndex()返回的是第一个返回条件的值的索引值
reduce() 和 reduceRight()否数组方法,reduce()对数组正序操作;reduceRight()对数组逆序操作

实现一个宽高自适应的正方形

  • 利用vw来实现:
.square {
  width: 10%;
  height: 10vw;
  background: tomato;
}

  • 利用元素的margin/padding百分比是相对父元素width的性质来实现:
.square {
  width: 20%;
  height: 0;
  padding-top: 20%;
  background: orange;
}

  • 利用子元素的margin-top的值来实现:
.square {
  width: 30%;
  overflow: hidden;
  background: yellow;
}
.square::after {
  content: '';
  display: block;
  margin-top: 100%;
}

事件是什么?事件模型?

事件是用户操作网页时发生的交互动作,比如 click/move, 事件除了用户触发的动作外,还可以是文档加载,窗口滚动和大小调整。事件被封装成一个 event 对象,包含了该事件发生时的所有相关信息( event 的属性)以及可以对事件进行的操作( event 的方法)。

事件是用户操作网页时发生的交互动作或者网页本身的一些操作,现代浏览器一共有三种事件模型:

  • DOM0 级事件模型,这种模型不会传播,所以没有事件流的概念,但是现在有的浏览器支持以冒泡的方式实现,它可以在网页中直接定义监听函数,也可以通过 js 属性来指定监听函数。所有浏览器都兼容这种方式。直接在dom对象上注册事件名称,就是DOM0写法。
  • IE 事件模型,在该事件模型中,一次事件共有两个过程,事件处理阶段和事件冒泡阶段。事件处理阶段会首先执行目标元素绑定的监听事件。然后是事件冒泡阶段,冒泡指的是事件从目标元素冒泡到 document,依次检查经过的节点是否绑定了事件监听函数,如果有则执行。这种模型通过attachEvent 来添加监听函数,可以添加多个监听函数,会按顺序依次执行。
  • DOM2 级事件模型,在该事件模型中,一次事件共有三个过程,第一个过程是事件捕获阶段。捕获指的是事件从 document 一直向下传播到目标元素,依次检查经过的节点是否绑定了事件监听函数,如果有则执行。后面两个阶段和 IE 事件模型的两个阶段相同。这种事件模型,事件绑定的函数是addEventListener,其中第三个参数可以指定事件是否在捕获阶段执行。

如何判断一个对象是否属于某个类?

  • 第一种方式,使用 instanceof 运算符来判断构造函数的 prototype 属性是否出现在对象的原型链中的任何位置。
  • 第二种方式,通过对象的 constructor 属性来判断,对象的 constructor 属性指向该对象的构造函数,但是这种方式不是很安全,因为 constructor 属性可以被改写。
  • 第三种方式,如果需要判断的是某个内置的引用类型的话,可以使用 Object.prototype.toString() 方法来打印对象的[[Class]] 属性来进行判断。

什么是margin重叠问题?如何解决?

问题描述: 两个块级元素的上外边距和下外边距可能会合并(折叠)为一个外边距,其大小会取其中外边距值大的那个,这种行为就是外边距折叠。需要注意的是,浮动的元素和绝对定位这种脱离文档流的元素的外边距不会折叠。重叠只会出现在垂直方向。

计算原则: 折叠合并后外边距的计算原则如下:

  • 如果两者都是正数,那么就去最大者
  • 如果是一正一负,就会正值减去负值的绝对值
  • 两个都是负值时,用0减去两个中绝对值大的那个

解决办法: 对于折叠的情况,主要有两种:兄弟之间重叠和父子之间重叠 (1)兄弟之间重叠

  • 底部元素变为行内盒子:display: inline-block
  • 底部元素设置浮动:float
  • 底部元素的position的值为absolute/fixed

(2)父子之间重叠

  • 父元素加入:overflow: hidden
  • 父元素添加透明边框:border:1px solid transparent
  • 子元素变为行内盒子:display: inline-block
  • 子元素加入浮动属性或定位

代码输出结果

const promise = new Promise((resolve, reject) => {
    resolve('success1');
    reject('error');
    resolve('success2');
});
promise.then((res) => {
    console.log('then:', res);
}).catch((err) => {
    console.log('catch:', err);
})

输出结果如下:

then:success1

这个题目考察的就是Promise的状态在发生变化之后,就不会再发生变化。开始状态由pending变为resolve,说明已经变为已完成状态,下面的两个状态的就不会再执行,同时下面的catch也不会捕获到错误。

僵尸进程和孤儿进程是什么?

  • 孤儿进程:父进程退出了,而它的一个或多个进程还在运行,那这些子进程都会成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
  • 僵尸进程:子进程比父进程先结束,而父进程又没有释放子进程占用的资源,那么子进程的进程描述符仍然保存在系统中,这种进程称之为僵死进程。

如何实现浏览器内多个标签页之间的通信?

实现多个标签页之间的通信,本质上都是通过中介者模式来实现的。因为标签页之间没有办法直接通信,因此我们可以找一个中介者,让标签页和中介者进行通信,然后让这个中介者来进行消息的转发。通信方法如下:

  • 使用 websocket 协议,因为 websocket 协议可以实现服务器推送,所以服务器就可以用来当做这个中介者。标签页通过向服务器发送数据,然后由服务器向其他标签页推送转发。
  • 使用 ShareWorker 的方式,shareWorker 会在页面存在的生命周期内创建一个唯一的线程,并且开启多个页面也只会使用同一个线程。这个时候共享线程就可以充当中介者的角色。标签页间通过共享一个线程,然后通过这个共享的线程来实现数据的交换。
  • 使用 localStorage 的方式,我们可以在一个标签页对 localStorage 的变化事件进行监听,然后当另一个标签页修改数据的时候,我们就可以通过这个监听事件来获取到数据。这个时候 localStorage 对象就是充当的中介者的角色。
  • 使用 postMessage 方法,如果我们能够获得对应标签页的引用,就可以使用postMessage 方法,进行通信。

Node 中的 Event Loop 和浏览器中的有什么区别?process.nextTick 执行顺序?

Node 中的 Event Loop 和浏览器中的是完全不相同的东西。

Node 的 Event Loop 分为 6 个阶段,它们会按照顺序反复运行。每当进入某一个阶段的时候,都会从对应的回调队列中取出函数去执行。当队列为空或者执行的回调函数数量到达系统设定的阈值,就会进入下一阶段。

(1)Timers(计时器阶段):初次进入事件循环,会从计时器阶段开始。此阶段会判断是否存在过期的计时器回调(包含 setTimeout 和 setInterval),如果存在则会执行所有过期的计时器回调,执行完毕后,如果回调中触发了相应的微任务,会接着执行所有微任务,执行完微任务后再进入 Pending callbacks 阶段。

(2)Pending callbacks:执行推迟到下一个循环迭代的I / O回调(系统调用相关的回调)。

(3)Idle/Prepare:仅供内部使用。

(4)Poll(轮询阶段):

  • 当回调队列不为空时:会执行回调,若回调中触发了相应的微任务,这里的微任务执行时机和其他地方有所不同,不会等到所有回调执行完毕后才执行,而是针对每一个回调执行完毕后,就执行相应微任务。执行完所有的回调后,变为下面的情况。
  • 当回调队列为空时(没有回调或所有回调执行完毕):但如果存在有计时器(setTimeout、setInterval和setImmediate)没有执行,会结束轮询阶段,进入 Check 阶段。否则会阻塞并等待任何正在执行的I/O操作完成,并马上执行相应的回调,直到所有回调执行完毕。

(5)Check(查询阶段):会检查是否存在 setImmediate 相关的回调,如果存在则执行所有回调,执行完毕后,如果回调中触发了相应的微任务,会接着执行所有微任务,执行完微任务后再进入 Close callbacks 阶段。

(6)Close callbacks:执行一些关闭回调,比如socket.on(‘close’, …)等。

下面来看一个例子,首先在有些情况下,定时器的执行顺序其实是随机的

setTimeout(() => {    console.log('setTimeout')}, 0)setImmediate(() => {    console.log('setImmediate')})

对于以上代码来说,setTimeout 可能执行在前,也可能执行在后

  • 首先 setTimeout(fn, 0) === setTimeout(fn, 1),这是由源码决定的
  • 进入事件循环也是需要成本的,如果在准备时候花费了大于 1ms 的时间,那么在 timer 阶段就会直接执行 setTimeout 回调
  • 那么如果准备时间花费小于 1ms,那么就是 setImmediate 回调先执行了

当然在某些情况下,他们的执行顺序一定是固定的,比如以下代码:

const fs = require('fs')
fs.readFile(__filename, () => {
    setTimeout(() => {
        console.log('timeout');
    }, 0)
    setImmediate(() => {
        console.log('immediate')
    })
})

在上述代码中,setImmediate 永远先执行。因为两个代码写在 IO 回调中,IO 回调是在 poll 阶段执行,当回调执行完毕后队列为空,发现存在 setImmediate 回调,所以就直接跳转到 check 阶段去执行回调了。

上面都是 macrotask 的执行情况,对于 microtask 来说,它会在以上每个阶段完成前清空 microtask 队列,

setTimeout(() => {
  console.log('timer21')
}, 0)
Promise.resolve().then(function() {
  console.log('promise1')
})

对于以上代码来说,其实和浏览器中的输出是一样的,microtask 永远执行在 macrotask 前面。

最后来看 Node 中的 process.nextTick,这个函数其实是独立于 Event Loop 之外的,它有一个自己的队列,当每个阶段完成后,如果存在 nextTick 队列,就会清空队列中的所有回调函数,并且优先于其他 microtask 执行。

setTimeout(() => {
 console.log('timer1')
 Promise.resolve().then(function() {
   console.log('promise1')
 })
}, 0)
process.nextTick(() => {
 console.log('nextTick')
 process.nextTick(() => {
   console.log('nextTick')
   process.nextTick(() => {
     console.log('nextTick')
     process.nextTick(() => {
       console.log('nextTick')
     })
   })
 })
})

对于以上代码,永远都是先把 nextTick 全部打印出来。

JavaScript 类数组对象的定义?

一个拥有 length 属性和若干索引属性的对象就可以被称为类数组对象,类数组对象和数组类似,但是不能调用数组的方法。常见的类数组对象有 arguments 和 DOM 方法的返回结果,还有一个函数也可以被看作是类数组对象,因为它含有 length 属性值,代表可接收的参数个数。

常见的类数组转换为数组的方法有这样几种:

(1)通过 call 调用数组的 slice 方法来实现转换

Array.prototype.slice.call(arrayLike);

(2)通过 call 调用数组的 splice 方法来实现转换

Array.prototype.splice.call(arrayLike, 0);

(3)通过 apply 调用数组的 concat 方法来实现转换

Array.prototype.concat.apply([], arrayLike);

(4)通过 Array.from 方法来实现转换

Array.from(arrayLike);

对AJAX的理解,实现一个AJAX请求

AJAX是 Asynchronous JavaScript and XML 的缩写,指的是通过 JavaScript 的 异步通信,从服务器获取 XML 文档从中提取数据,再更新当前网页的对应部分,而不用刷新整个网页。

创建AJAX请求的步骤:

  • 创建一个 XMLHttpRequest 对象。
  • 在这个对象上使用 open 方法创建一个 HTTP 请求,open 方法所需要的参数是请求的方法、请求的地址、是否异步和用户的认证信息。
  • 在发起请求前,可以为这个对象添加一些信息和监听函数。比如说可以通过 setRequestHeader 方法来为请求添加头信息。还可以为这个对象添加一个状态监听函数。一个 XMLHttpRequest 对象一共有 5 个状态,当它的状态变化时会触发onreadystatechange 事件,可以通过设置监听函数,来处理请求成功后的结果。当对象的 readyState 变为 4 的时候,代表服务器返回的数据接收完成,这个时候可以通过判断请求的状态,如果状态是 2xx 或者 304 的话则代表返回正常。这个时候就可以通过 response 中的数据来对页面进行更新了。
  • 当对象的属性和监听函数设置完成后,最后调用 sent 方法来向服务器发起请求,可以传入参数作为发送的数据体。
const SERVER_URL = "/server";
let xhr = new XMLHttpRequest();
// 创建 Http 请求
xhr.open("GET", url, true);
// 设置状态监听函数
xhr.onreadystatechange = function() {
  if (this.readyState !== 4) return;
  // 当请求成功时
  if (this.status === 200) {
    handle(this.response);
  } else {
    console.error(this.statusText);
  }
};
// 设置请求失败时的监听函数
xhr.onerror = function() {
  console.error(this.statusText);
};
// 设置请求头信息
xhr.responseType = "json";
xhr.setRequestHeader("Accept", "application/json");
// 发送 Http 请求
xhr.send(null);

使用Promise封装AJAX:

// promise 封装实现:
function getJSON(url) {
  // 创建一个 promise 对象
  let promise = new Promise(function(resolve, reject) {
    let xhr = new XMLHttpRequest();
    // 新建一个 http 请求
    xhr.open("GET", url, true);
    // 设置状态的监听函数
    xhr.onreadystatechange = function() {
      if (this.readyState !== 4) return;
      // 当请求成功或失败时,改变 promise 的状态
      if (this.status === 200) {
        resolve(this.response);
      } else {
        reject(new Error(this.statusText));
      }
    };
    // 设置错误监听函数
    xhr.onerror = function() {
      reject(new Error(this.statusText));
    };
    // 设置响应的数据类型
    xhr.responseType = "json";
    // 设置请求头信息
    xhr.setRequestHeader("Accept", "application/json");
    // 发送 http 请求
    xhr.send(null);
  });
  return promise;
}

扩展运算符的作用及使用场景

(1)对象扩展运算符

对象的扩展运算符(…)用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中。

let bar = { a: 1, b: 2 };
let baz = { ...bar }; // { a: 1, b: 2 }

上述方法实际上等价于:

let bar = { a: 1, b: 2 };
let baz = Object.assign({}, bar); // { a: 1, b: 2 }

Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。Object.assign方法的第一个参数是目标对象,后面的参数都是源对象。(如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性)。

同样,如果用户自定义的属性,放在扩展运算符后面,则扩展运算符内部的同名属性会被覆盖掉。

let bar = {a: 1, b: 2};
let baz = {...bar, ...{a:2, b: 4}};  // {a: 2, b: 4}

利用上述特性就可以很方便的修改对象的部分属性。在redux中的reducer函数规定必须是一个纯函数,reducer中的state对象要求不能直接修改,可以通过扩展运算符把修改路径的对象都复制一遍,然后产生一个新的对象返回。

需要注意:扩展运算符对对象实例的拷贝属于浅拷贝。

(2)数组扩展运算符

数组的扩展运算符可以将一个数组转为用逗号分隔的参数序列,且每次只能展开一层数组。

console.log(...[1, 2, 3])
// 1 2 3
console.log(...[1, [2, 3, 4], 5])
// 1 [2, 3, 4] 5

下面是数组的扩展运算符的应用:

  • 将数组转换为参数序列
function add(x, y) {
  return x + y;
}
const numbers = [1, 2];
add(...numbers) // 3

  • 复制数组
const arr1 = [1, 2];
const arr2 = [...arr1];

要记住:扩展运算符(…)用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中,这里参数对象是个数组,数组里面的所有对象都是基础数据类型,将所有基础数据类型重新拷贝到新的数组中。

  • 合并数组

如果想在数组内合并数组,可以这样:

const arr1 = ['two', 'three'];const arr2 = ['one', ...arr1, 'four', 'five'];// ["one", "two", "three", "four", "five"]

  • 扩展运算符与解构赋值结合起来,用于生成数组
const [first, ...rest] = [1, 2, 3, 4, 5];first // 1rest  // [2, 3, 4, 5]

需要注意:如果将扩展运算符用于数组赋值,只能放在参数的最后一位,否则会报错。

const [...rest, last] = [1, 2, 3, 4, 5];         // 报错const [first, ...rest, last] = [1, 2, 3, 4, 5];  // 报错

  • 将字符串转为真正的数组
[...'hello']    // [ "h", "e", "l", "l", "o" ]

  • 任何 Iterator 接口的对象,都可以用扩展运算符转为真正的数组

比较常见的应用是可以将某些数据结构转为数组:

// arguments对象
function foo() {
  const args = [...arguments];
}

用于替换es5中的Array.prototype.slice.call(arguments)写法。

  • 使用Math函数获取数组中特定的值
const numbers = [9, 4, 7, 1];
Math.min(...numbers); // 1
Math.max(...numbers); // 9

2020届秋招/WEB前端工程师/面经/内附面试问题心得体会/vue框架面试题 以BAT大厂为目标的带佬们可以绕路了,不是不想,实在是实力有限,大概BAT是每个程序员的梦吧,希望以后可以有机会。先说一下背景,博主坐标厦门某双非,学校整体求职氛围比较慢热,暑假的时候学院甚至还在实训。我自己真正开始求职已经是在十月份了。是的你没看错,就是十月,金九银十的十。想告诉大家找工作什么时候都不要怕晚,只要你肯就有机会。短暂的迷惘之后,博主迅速调整状态,开始每天牛客网刷题,复... 阅读详情

相关推荐

差分隐私(Differential Privacy)

差分隐私,拉普拉斯机制和高斯机制的证明

Michale_L的博客 1万+

阿里前端工程师面试题+解题思路

公司 | 阿里 地点 | 杭州 职位 | 前端开发工程师 一面(提前批) ①介绍下自己的项目 ②AngularJS和React、Vue有什么区别?结合开发经历描述。 这个纯看理解和个人发挥了,面试官估计仔细看了我的简历,三个框架都用过所以这么问。 当时扯了很久关于框架的见解,在这种方面,千万不要背MVC或MVVM之类的概念。 ③项目中遇到什么问题,如何解决的? ④Node.js用过么,讲一讲。 用的不多,就把Node的事件循环讲了下,nextTick和setImmediate跳出来讲了讲

Blue92120的博客 2622

智能车图像处理去畸变+逆透视教程

图像处理,去畸变与逆透视整合

wu58430的博客 1万+

如何拿到9家大厂的前端校招offer

关注前端达人,与你共同进步本文由 杨珏成 首发于掘金,未经许可请勿转载原文链接:https://juejin.im/post/5d70ff205188253e4b2f0...

前端达人 1093

Android Activity面试题最全解析(5万字长文)

Intent是Android中用于启动活动、服务或广播的一种消息对象。它包含了一系列键值对数据,用于描述操作的目的以及需要传递的信息。IntentString:字符串intfloatlong:基本数据类型Parcelable:实现了Parcelable接口的对象:实现了接口的对象示例代码如下:Java深色版本1// 创建Intent并传递数据");67// 启动新的Activity是一个XML标签,用于定义ActivityService或可以响应的Intent类型。它包含了。

大模型大数据攻城狮的专栏 802

C++ Qt6 QtQuick/QML入门进阶与项目实战视频教程

C++ Qt这些年在PC客户端、嵌入式、汽车座舱仪表等领域应用很广泛,例如剪映专业版、微信4.0、亿图脑图、Steam、美图秀秀、腾讯会议、钉钉(部分模块)等都是使用C++ QWidget/QML开发。特别是QML这种声明式UI开发更加快捷,QML的界面开发效率相对于QWidget更快速,界面效果更好,QtQuick/QML在Qt6版本也逐渐完善了,使用QML进行客户端开发是个不错的选择。

琅嬛福地 4487

北理大佬是如何拿到 9 家大厂的前端 offer (附面试题和典型思路)

本文由 杨珏成 首发于掘金,未经许可请勿转载原文链接:https://juejin.im/post/5d70ff205188253e4b2f07bd0x00 作者是谁...

前端下午茶 2111

对接金蝶云星空调用即时库存信息查询API(附JAVA实现)

这篇文章教你如何对接金蝶API并且使用JAVA调用金蝶云星空的即时库存查询API

实用的博客 2608

一年半前端工作经验试水杭州:我是如何拿下网易、阿里和滴滴 offer 的

由于微信外链限制,推荐阅读等链接无法点击,可点击阅读原文跳转至原文,查看外链。前言笔者毕业于东北大学,大学毕业社招进入环球网,前端开发工程师一职。技术栈:React+no...

全栈前端精选 1万+

58.Sobel边缘检测算子

注:在梯度运算中,很可能会出现负的灰度值,我们不能再采用uint8类型作为像素的数据类型,而是采用了CV_16S或者CV_32F这种有负数范围的类型,运算结果里的负数也不能不处理,否则在显示的时候就会被截断为0,这样就会丢失边界信息。如下图所示,对中心像素Z5求取多个方向的灰度差分,对于Z5的8邻域,分为4个方向,即对角线和水平垂直4个方向对:(z1, z9) ,(z2, z8), (z3, z7), (z6, z4) 给定邻域方向梯度矢量g的幅度为:|g| = <像素灰度差分>/<相邻像素的距离>。

twnkie的博客 4884

CVE-2021-3156本地提权漏洞复现

受影响版本 sudo: 1.8.2 - 1.8.31p2 sudo: 1.9.0 - 1.9.5p1 测试 我这里是在本地centos7上进行测试。 需要目标机器上存在python编译器、目标主机出网或者能上传文件到目标主机。 以非root用户登录系统,并运行如下命令: sudoedit -s / 通常响应一个以 sudoedit: / 开头的报错,多半存在漏洞。 利用 提权脚本: https://www.o2oxy.cn/wp-content/uploa

The current road is different, love needs to distinguish between right and wrong 3779

JWT学习记录,这个回答让我错失offer

资料过多,篇幅有限CodeChina开源项目:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】自古成功在尝试。不尝试永远都不会成功。勇敢的尝试是成功的一半。CodeChina开源项目:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】自古成功在尝试。不尝试永远都不会成功。勇敢的尝试是成功的一半。

2401_84002730的博客 405

用MSBlock重塑C2f,让你的模型又轻又强(参数量与精度的双重突破)

打开确保模型解析器能识别MSBlock模块。通过将MSBlock集成到YOLOv8的C2f模块中,我们实现了一个“轻量且多尺度感知”的目标检测模型。这个改进不仅在工程上能降低部署成本、提升推理速度,更在科研上提供了“多尺度+动态核”的创新思路——这种思路可以延伸到其他网络(如ResNet、MobileNet)的改进中,帮你在论文中打造独特的研究点。如果你在实现过程中遇到问题,比如代码报错、训练收敛异常,可以先检查模块集成的每一步是否到位,再尝试调整MSBlock的卷积核尺寸、动态权重的计算方式等超参数。

m0_71589036的博客 105

2024年Web前端最新好的始终在后面,虾皮、快手、拼多多均失利,终拿字节 offer(2),2024年最新腾讯web前端开发面试题

其实前端开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。这里再分享一个复习的路线:(以下体系的复习资料是我从各路大佬收集整理好的)《前端开发四大模块核心知识笔记》最后,说个题外话,我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

2301_79985012的博客 864

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

这份前端面试题能帮助的不止是你Promise问题,还能拿到大厂(腾讯、百度、阿里)实习offer

前言 小编之前写过一篇:前端面试之问到promise怎么办?,温故而知新哦 怎么今天又来一篇与promise的文章呢 ,哈哈哈哈小伙伴们不要急着离开哈,是因为认识了一个去找实习的同学,聊了实习找的怎样了,让我印象最深刻的就是她讲promise的面试题,她说一面结束后就知道凉凉了,并且要是有机会很想和面试官说一句:面试官对不起!我终于会了Promise! 大概是这么个情况,所以呀小编又来讲讲promise,后面带有面试题。同学参加的是某大厂面试,大家看看面试题及同学的回答就知道这位同学有多难受了。 面试题

Kepler_II的博客 738

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

实习程序员拿下9家大厂的前端校招offer,分享月薪破万的成功秘诀

我就读于北京理工大学软件工程专业,是一名大四学生。从大一开始投入以前端为主的全栈开发,独立开发过多个中型和小型项目 在学校里读书的时候,我就是一个闲不住的人。最近因为一个偶然的契机,接触到了校招季,最后定下了本科毕业就工作的规划目标。 于是我在一个月的时间里参加了9家国内大厂校招,收获了如下结果(截至2019年9月5日): 腾讯(WXG):等待二面 阿里巴巴(淘宝FED):三面等结果 字节跳动...

IT-编程资讯 1670

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

那些简历造假拿 Offer 的程序员,后来都怎么样了?,前端开发应该如何准备面试

特别是他,口才很好,那天三位面试官频频点头表示认可。第二轮是笔试,他和黑大硕士也都过了。当时他心里还窃喜,原来自己都赶上名校硕士的水平了。第三轮是终面,CTO也去了,加上之前的面试官,一共是四位面试官。他在回答其他面试官的问题时,CTO一直在低头看他简历。终于,CTO开始问问题了,上来就问“说说你的教育经历。李光光傻眼了,简历上写的是本科。就这样,在众目睽睽之下,他不得不承认自己学历造假,是因为怕简历不过关。尽管讲述了自己被迫辍学、早早赚钱养家的心酸故事,也没能挽回获得Offer的机会。

qq_58071132的博客 1183

好事多磨!6轮面试后终于拿到字节前端校招offer(内含6轮面经)

大概1月初的时候,我在各个渠道就收到了**字节跳动年前扩招**的喜讯,我心想,春招压力这么大(因为春招的求职者大多都是备战了很久的大佬或者是秋招实习结束回来更有经验的同学),字节竟然年前开始扩招了,那我不如抓住这个机会尝试一下,降低一些竞争压力 于是我就用了一周的时间边准备面试,边投简历

零一的博客 4616

横扫9家大厂前端校招offer,全文14560字,阅读需80分钟

本文由 杨珏成 首发于掘金,未经许可请勿转载原文链接:https://juejin.im/post/5d70ff205188253e4b2f07bd0x00 作者是谁我...

frontend_frank的博客 960

最新那些简历造假拿 Offer 的程序员,后来都怎么样了?,前端中为什么需要Handler

你要问前端开发难不难,我就得说计算机领域里常说的一句话,这句话就是『难的不会,会的不难』,对于不熟悉某领域技术的人来说,因为不了解所以产生神秘感,神秘感就会让人感觉很难,也就是『难的不会』;当学会这项技术之后,知道什么什么技术能做到什么做不到,只是做起来花多少时间的问题而已,没啥难的,所以就是『会的不难』。开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】我特地针对初学者整理一套前端学习资料他曾经是北京某大型IT培训机构的老板的司机。业余没事儿给学校招招生,赚点外快。

2401_84619606的博客 316

我的web前端面试心法(已拿字节offer),web前端开发师学习

前端面试题汇总前端面试题是我面试过程中遇到的面试题,每一次面试后我都会复盘总结。

2301_79055083的博客 1001

前端自学公式化方法论:从零基础到拿下大厂Offer的完整路线

前端开发作为互联网行业的常青技术方向,其知识体系庞杂且更新迅速,自学者常因缺乏系统规划而陷入“学了忘、忘了学”的循环。真正高效的学习路径,不是无目的地堆砌知识点,而是将前端技能树拆解为可量化、可验证的工程流程。从HTML/CSS布局基础,到JavaScript核心机制如闭包与事件循环,再到Vue/React框架的项目实践,每一阶段都应有明确的产出物。通过开发覆盖组件封装、状态管理、性能优化与工程化配置的完整项目,结合面试题溯源推导,自学者既能构建扎实的知识底座,也能将项目经验转化为应对大厂面试的谈资。时间管

weixin_29008055的博客 287

android开发手册!这个回答让我错失offer!offer拿到手软

前言 每个程序员都有一个梦想,那就是进一线互联网公司深造,不要跟我说你不想进去,如果给你一个这样的平台,不管是薪资待遇还是接触的高度来说,对我们程序员来说都是一个机会,我以前有一个同事,就是从阿里出来的,原来是p7,后面来了我们这里当了技术总监,人家的代码写的让你不得不服。 今天我特意收集了最新面试题,虽然花了一些时间,经过整理之后分享给大家,大家一起来看看什么互联网面试题,一起来认识一下,看看自己能掌握多少! 收集反馈的面经资料比较乱,最近终于空出时间,我们进行了分类,循序渐进,由基础到深入,由易到简。

m0_56130999的博客 172
上一篇: 前端常考面试题整理
下一篇: 一文彻底搞懂前端缓存机制
hellocoder2029
博客等级 码龄4年 15粉丝 80原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值