浩鲸和阿里的面试题,并附带答案

310 阅读8分钟

Promise 的本质是什么?

本质是分离了异步数据获取和业务处理

实现 Promise

./MyPromise.js

调用 promise 的 reject()之后会不会进入 catch()里面?

如果then函数有第二个传参则不会进入,如果没有则会进入

说下强缓存和协商缓存

强缓存:

通过express(http 1.0)和catch-control(http1.1)进行控制。express 它的值为一个绝对时间的 GMT 格式的时间字符串。如果发送请求的时间在 expires 之前,那么本地缓存始终有效,否则就会发送请求到服务器来获取资源。

catch-controlmax-age=number。主要通过该字段进行判断,它是一个相对值。通过资源第一次请求时间和catch-control max-age 设置的有效时间计算得出一个过期时间。在拿当前时间和过期时间进行比较,如果在过期时间之前则命中缓存否则则重新请求catch-control还有以下常用值:

  • public:可以被所有的用户缓存,包括终端用户和 CDN 等中间代理服务器
  • private:只能终端用户缓存
  • no-cache:不使用本地缓存。需要使用协商缓存,先与服务器确认返回的响应是否被更改,如果之前的响应中存在 ETag,那么请求的时候会与服务端验证,如果资源未被更改,则可以避免重新下载。
  • no-store:禁止浏览器缓存。每次都需要去请求最新数据

协商缓存:

主要涉及到下面两组 header 字段,这两组搭档都是成对出现的,即第一次请求的响应头带上某个字段(Last-Modified 或者 Etag),则后续请求则会带上对应的请求字段(If-Modified-Since 或者 If-None-Match),若响应头没有 Last-Modified 或者 Etag 字段,则请求头也不会有对应的字段。

  • Etag:文件的 hash 值,通过服务端通过 response header 返回给终端
  • last-modified:文件最后修改时间
  • If-Modified-Since: 通过 request header 返回给服务端 值就是上一次请求的 last-modified 值。服务端拿到这个值和问的最后修改时间做对比,如果相同304如果不同就返回资源内容。
  • if-none-match:通过 request header 返回给服务端 值就是上一次请求的 Etag 的值

import 和 require 的区别

  • requireCommonJS模块化方案的产物 importES6
  • require 原生浏览器不支持 import浏览器可以支持
  • require运行时加载 import是静态编译
  • require输出是值的拷贝 import 输出的是值的引用
  • 双方用法不同

使用 array.forEach(()=>array.push(1))是否会出现死循环?

不会

使用 filter 对数组进行过滤时,修改过滤之后的数组里对象的值,原数组是否会修改如果会修改怎么进行避免?

//deepClone 深度拷贝函数
const filterArray = [{ a: { b: 1 } }].filter((item) => {
  if (item.a.b === 1) return deepClone(item);
});

说一下原型和原型链

  • 每个函数数据类型自带prototype属性,该属性指向的是函数的原型对象。

  • 每个对象数据类型自带__proto__,该属性的值指向他的构造函数的原型对象

  • 原型对象的constructor指向函数本身

  • 当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还查不到,就去找原型的原型,原型链的尽头是Object.prototype 如果还找不到就返回null

说一下 git 有哪几种 hooks

  • pre-commit 检查每次的 commit message 是否有拼写错误,或是否符合某种规范
  • post-commit 提交完成后运行。
  • pre-receive 统一上传到远程库的代码的编码。
  • post-receive 挂钩在整个过程完结以后运行,可以用来更新其他系统服务或者通知用户。

谈一下 webpack 的基本配置

  • entry 打包入口
  • output 输出文件
  • devServer 开发服务器,可以配置热更新、端口、报错是否显示在页面上等
  • module 告知 webpack 每一种文件类型需要什么加载器处理 例如file-loaderurl-loaderless-loadervue-loaderjsx-loader
  • plugins 扩展 webpack 功能 常用的例如:CopyWebpackPlugin(复制文件夹到另一个目录里面)、HtmlWebpackPlugin(生成一个 html 文件,使用 script 标签引入 webpack 包)、DefinePlugin(编译时注入全局变量)、ExtractTextWebpackPlugin(提取 CSS 文件)、CommonsChunkPlugin(提供公共模块)、uglifyjs-webpack-plugin(JS 压缩插件)、happyPack(多线程打包)等

常用的跨域方式

jsonp nginx代理 CORS跨域

JSONP 跨域的原理

在客户端注册一个 callback (如:'testjsonpcallback'),然后动态添加一个 script 标签并且给这个标签添加 src 属性 把 callback=testjsonpcallback 拼在 src 上传给服务端。服务端得到 callback 的数值后,把将要输出的 json 内容包括起来,此时,服务器生成 json 数据才能被客户端正确接收。然后把拼好的之后返回给客户端。客户端执行返回来的函数,然后参数就会进入预先定义好的函数里。

说下 vue 的数据双向绑定原理

Vue 采用数据劫持结合发布者-订阅者模式的方法,通过 Object.defineProperty 方法属性拦截的方式来劫持各个属性的 getter/setter,通过(发布者)Observer监听所有属性,如果属性发生改变告诉订阅者watcher看看是否需要更新,因为订阅者有很多个所以通过消息订阅器Dep来收集订阅者再数据变动时发布消息给订阅者watcher,还需要模板解析器Compile对 template 进行扫描和解析,为watcher绑定相应的更新函数,当watcher接收到属性变化触发相应的监听回调来渲染视图。

说下你对 vue3 的了解

  • 使用ES2015的特性proxy进行数据拦截实现数据响应式
  • 更好的支持了tree-shaking
  • composition API
  • Fragments 支持多个根节点
  • 更好的支持了 TS
  • Custom Renderer API实现用 DOM 的方式进行 WebGL 编程

keep-alive 的作用

使用 keep-alive缓存组件,防止二次渲染

说下数组和对象的本质区别

  • 数组是有序的,对象是无序的
  • 数组原型链和对象的不同

对象可以用 数字当作 Key 吗?

可以

用 Object.keys()转换对象时,对象的 key 是数字的时候如何禁止转换成字符串而是转成数字

我没想到好的方法唯一的方法就是重写Object.keys()方法

箭头函数和快形函数的区别

箭头函数

  • 不绑定this,会捕获其所在的上下文的this值,作为自己的this
  • 不能被实例化
  • 没有原型链
  • 不绑定arguments
  • 不能当做Generator函数,不能使用yield关键字

对闭包的理解

可以访问另一个函数内部变量的函数。 使用场景:防止全局作用域污染、定义私有变量、使变量储存在内存中不被销毁等。

说下 get 请求和 post 的请求的区别

  • get 可以被缓存
  • get 可以被保存在浏览器历史中
  • get 对发送的数据类型有限制
  • get产生一个 TCP 数据包 post产生两个

get 和 post 请求的最大传多大数据

首先 get 请求和 post 请求没对有传输数据进行限制大小,是服务端和浏览器端进行设置的。IE 对 URL 长度的限制是 2083 字节(2K+35 字节) POST 默认是 2M 。

斐波那契的时间复杂度是多少?

不同的解决方法答案不同递归算法为 O(2^n) 非递归算法 O(n).

说下 event loop

event loop 分为 宏任务微任务; 宏任务:JS 正常运行的代码 setIntervalsetTimeoutUI Rendering; 微任务:Process.nextTick(Node独有)PromiseMutationObserver 整体代码块是宏任务,当遇到setTimeOut时,会开辟新的宏任务,然后继续执行。当遇到 Promise 之类的事件时会把他加入到微任务队列里面,当前宏任务执行完毕之后,会去检查微任务队列是否有任务。如果有则立即执行当前的微任务。当前微任务执行完毕之后,开始执行下一轮的宏任务。

vue-route 中 hash 和 history 的区别

hash:

  • 使用 hashchange 事件来监听 URL 的变化
  • 兼容性好
  • URL 有#的符号
  • 覆盖锚点功能
  • 修改#后面的地址不会向服务端重新请求 History:
  • 通过pushStatereplaceState替换 URL 并且不会向服务端发送请求
  • pushState设置的新 URL 可以是与当前 URL 同源的任意 URL;而 hash 只可修改 # 后面的部分

  • pushState设置的新 URL 可以与当前 URL 一模一样,这样也会把记录添加到栈中;而 hash 设置的新值必须与原来不一样才会触发动作将记录添加到栈中