高级前端一面常考手写面试题指南
手写类型判断函数
实现 JSONP 方法
利用
<script>
标签不受跨域限制的特点,缺点是只能支持get
请求
创建
script
标签设置
script
标签的src
属性,以问号传递参数,设置好回调函数callback
名称插入到
html
文本中调用回调函数,
res
参数就是获取的数据
设置
CORS: Access-Control-Allow-Origin:*
postMessage
基于 Promise.all 实现 Ajax 的串行和并行
基于 Promise.all 实现 Ajax 的串行和并行
串行:请求是异步的,需要等待上一个请求成功,才能执行下一个请求
并行:同时发送多个请求「
HTTP
请求可以同时进行,但是 JS 的操作都是一步步的来的,因为 JS 是单线程」,等待所有请求都成功,我们再去做什么事情?
Promise.all 并发限制及 async-pool 的应用
并发限制指的是,每个时刻并发执行的 promise 数量是固定的,最终的执行结果还是保持与原来的
JS 实现 Ajax 并发请求控制的两大解决方案
tasks
:数组,数组包含很多方法,每一个方法执行就是发送一个请求「基于Promise
管理」
实现 Node 的 require 方法
require 基本原理
require 查找路径
require
和module.exports
干的事情并不复杂,我们先假设有一个全局对象{}
,初始情况下是空的,当你require
某个文件时,就将这个文件拿出来执行,如果这个文件里面存在module.exports
,当运行到这行代码时将module.exports
的值加入这个对象,键为对应的文件名,最终这个对象就长这样:
当你再次
require
某个文件时,如果这个对象里面有对应的值,就直接返回给你,如果没有就重复前面的步骤,执行目标文件,然后将它的module.exports
加入这个全局对象,并返回给调用者。这个全局对象其实就是我们经常听说的缓存。所以require
和module.exports
并没有什么黑魔法,就只是运行并获取目标文件的值,然后加入缓存,用的时候拿出来用就行
手写实现一个 require
参考:前端手写面试题详细解答
实现 forEach 方法
实现 Object.freeze
Object.freeze
冻结一个对象,让其不能再添加/删除属性,也不能修改该对象已有属性的可枚举性、可配置可写性,也不能修改已有属性的值和它的原型属性,最后返回一个和传入参数相同的对象
实现 some 方法
实现 Ajax
步骤
创建
XMLHttpRequest
实例发出 HTTP 请求
服务器返回 XML 格式的字符串
JS 解析 XML,并更新局部页面
不过随着历史进程的推进,XML 已经被淘汰,取而代之的是 JSON。
了解了属性和方法之后,根据 AJAX 的步骤,手写最简单的 GET 请求。
实现一个 compose 函数
组合多个函数,从右到左,比如:
compose(f, g, h)
最终得到这个结果(...args) => f(g(h(...args))).
题目描述:实现一个 compose
函数
实现代码如下
compose
创建了一个从右向左执行的数据流。如果要实现从左到右的数据流,可以直接更改compose
的部分代码即可实现
更换
Api
接口:把reduce
改为reduceRight
交互包裹位置:把
a(b(...args))
改为b(a(...args))
基于 Generator 函数实现 async/await 原理
核心:传递给我一个
Generator
函数,把函数中的内容基于Iterator
迭代器的特点一步步的执行
使用 Promise 封装 AJAX 请求
交换 a,b 的值,不能用临时变量
巧妙的利用两个数的和、差:
实现 call 方法
call 做了什么:
将函数设为对象的属性
执行和删除这个函数
指定
this
到函数并传入给定参数执行函数如果不传入参数,默认指向为
window
实现 instanceOf
思路:
步骤 1:先取得当前类的原型,当前实例对象的原型链
步骤 2:一直循环(执行原型链的查找机制)
取得当前实例对象原型链的原型链(
proto = proto.__proto__
,沿着原型链一直向上查找)如果 当前实例的原型链
__proto__
上找到了当前类的原型prototype
,则返回true
如果 一直找到
Object.prototype.__proto__ == null
,Object
的基类(null
)上面都没找到,则返回false
实现一个双向绑定
defineProperty 版本
proxy 版本
实现 redux-thunk
redux-thunk
可以利用redux
中间件让redux
支持异步的action
实现 apply 方法
apply 原理与 call 很相似,不多赘述
手写 Promise.then
then
方法返回一个新的 promise
实例,为了在 promise
状态发生变化时(resolve
/ reject
被调用时)再执行 then
里的函数,我们使用一个 callbacks
数组先把传给 then 的函数暂存起来,等状态改变时再调用。
**那么,怎么保证后一个 **then**
里的方法在前一个 ****then**
(可能是异步)结束之后再执行呢? 我们可以将传给 then
的函数和新 promise
的 resolve
一起 push
到前一个 promise
的 callbacks
数组中,达到承前启后的效果:
承前:当前一个
promise
完成后,调用其resolve
变更状态,在这个resolve
里会依次调用callbacks
里的回调,这样就执行了then
里的方法了启后:上一步中,当
then
里的方法执行完成后,返回一个结果,如果这个结果是个简单的值,就直接调用新promise
的resolve
,让其状态变更,这又会依次调用新promise
的callbacks
数组里的方法,循环往复。。如果返回的结果是个promise
,则需要等它完成之后再触发新promise
的resolve
,所以可以在其结果的then
里调用新promise
的resolve
注意:
连续多个
then
里的回调方法是同步注册的,但注册到了不同的callbacks
数组中,因为每次then
都返回新的promise
实例(参考上面的例子和图)注册完成后开始执行构造函数中的异步事件,异步完成之后依次调用
callbacks
数组中提前注册的回调
实现 AJAX 请求
AJAX 是 Asynchronous JavaScript and XML 的缩写,指的是通过 JavaScript 的 异步通信,从服务器获取 XML 文档从中提取数据,再更新当前网页的对应部分,而不用刷新整个网页。
创建 AJAX 请求的步骤:
创建一个 XMLHttpRequest 对象。
在这个对象上使用 open 方法创建一个 HTTP 请求,open 方法所需要的参数是请求的方法、请求的地址、是否异步和用户的认证信息。
在发起请求前,可以为这个对象添加一些信息和监听函数。比如说可以通过 setRequestHeader 方法来为请求添加头信息。还可以为这个对象添加一个状态监听函数。一个 XMLHttpRequest 对象一共有 5 个状态,当它的状态变化时会触发 onreadystatechange 事件,可以通过设置监听函数,来处理请求成功后的结果。当对象的 readyState 变为 4 的时候,代表服务器返回的数据接收完成,这个时候可以通过判断请求的状态,如果状态是 2xx 或者 304 的话则代表返回正常。这个时候就可以通过 response 中的数据来对页面进行更新了。
当对象的属性和监听函数设置完成后,最后调用 sent 方法来向服务器发起请求,可以传入参数作为发送的数据体。
手写 bind 函数
bind 函数的实现步骤:
判断调用对象是否为函数,即使我们是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况。
保存当前函数的引用,获取其余传入参数值。
创建一个函数返回
函数内部使用 apply 来绑定函数调用,需要判断函数作为构造函数的情况,这个时候需要传入当前函数的 this 给 apply 调用,其余情况都传入指定的上下文对象。
评论