没有合适的资源?快使用搜索试试~ 我知道了~
如今前端攻城狮的要求越来越高,会使用常见的API已经不能满足现如今前端日益快速发展的脚步。现在大厂基本都会要求面试者手写前端常见API的原理,以此来证明你对该知识点的理解程度。接下来,我将列举我面试时以及自认为比较重要的CSS部分、JS部分常见手写原理题!后续分享Vue全家桶、React全家桶手写原理图,敬请期待! JS部分 手写原生Ajax 平时项目开发中,一定会用到ajax请求后端接口获取数据在前端渲染效果。目前市面上有很多封装好的ajax请求库,例如:jQuery版的ajax、基于Promise的Axios请求库、Flyio等等。目前很多人都只会使用这些API,但是如今面试经常会被问到
资源详情
资源评论
资源推荐
前端面试大厂手写源码系列(上)前端面试大厂手写源码系列(上)
如今前端攻城狮的要求越来越高,会使用常见的API已经不能满足现如今前端日益快速发展的脚步。现在大厂基本都会要求面试者手写前端常见API的原理,以此来证明你对该知识点
的理解程度。接下来,我将列举我面试时以及自认为比较重要的CSS部分、JS部分常见手写原理题!后续分享Vue全家桶、React全家桶手写原理图,敬请期待!
JS部分部分
手写原生手写原生Ajax
平时项目开发中,一定会用到ajax请求后端接口获取数据在前端渲染效果。目前市面上有很多封装好的ajax请求库,例如:jQuery版的ajax、基于Promise的Axios请求库、Flyio等
等。目前很多人都只会使用这些API,但是如今面试经常会被问到:你了解ajax原理吗?你知道原生ajax实现步骤吗?…接下来,我将封装一个完整的原生ajax。
一个完整的 ajax 请求一般包括以下步骤:
实例化 XMLHttpRequest 对象
连接服务器
发送请求
介绍
function ajax(options) {
let method = options.method || 'GET', // 不传则默认为GET请求
params = options.params, // GET请求携带的参数
data = options.data, // POST请求传递的参数
url = options.url + (params ? '?' + Object.keys(params).map(key => key + '=' + params[key]).join('&') : ''),
async = options.async === false ? false : true,
success = options.success,
headers = options.headers;
let xhr;
// 创建xhr对象
if(window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject('Microsoft.XMLHTTP');
}
xhr.onreadystatechange = function() {
if(xhr.readyState === 4 && xhr.status === 200) {
success && success(xhr.responseText);
}
}
xhr.open(method, url, async);
if(headers) {
Object.keys(Headers).forEach(key => xhr.setRequestHeader(key, headers[key]))
}
method === 'GET' ? xhr.send() : xhr.send(data)
}
注意注意:IE5、6不兼容XMLHttpRequest,所以要使用ActiveXObject()对象,并传入 ‘Microsoft.XMLHTTP’,达到兼容目的。
readyState的五种状态详解:
0 - (未初始化)还没有调用send()方法
1 - (载入)已调用send()方法,正在发送请求
2 - (载入完成)send()方法执行完成,已经接收到全部响应内容
3 - (交互)正在解析响应内容
4 - (完成)响应内容解析完成,可以在客户端调用了
手写防抖和节流手写防抖和节流
如今前端界面效果越来越复杂,有一些频繁操作会导致页面性能和用户体验度低。像:输入框搜索会频繁调端口接口、放大缩小窗口等。
防抖 – debounce 当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。
const debounce = (fn, delay) => {
let timer = null;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
};
节流 – throttle 当持续触发事件时,保证一定时间段内只调用一次事件处理函数。
const throttle = (fn, delay = 500) => {
let flag = true;
return (...args) => {
if (!flag) return;
flag = false;
setTimeout(() => {
fn.apply(this, args);
flag = true;
}, delay);
};
};
手写手写jsonp的实现原理的实现原理
function jsonp({url, params, cb}) {
return new Promise((resolve, reject) => {
window[cb] = function (data) { // 声明全局变量
resolve(data)
document.body.removeChild(script)
}
params = {...params, cb}
let arrs = [] for(let key in params) {
arrs.push(`${key}=${params[key]}`)
}
let script = document.createElement('script')
script.src = `${url}?${arrs.join('&')}`
document.body.appendChild(script)
})
}
jsonp的缺点的缺点:
只能发送Get请求 不支持post put delete
不安全 xss攻击
手写手写apply的实现原理的实现原理
apply 的实现原理和 call 的实现原理差不多,只是参数形式不一样。— 数组
Function.prototype.apply = function(content = window) {
content.fn = this;
let result;
// 判断是否有第二个参数
if(arguments[1]) {
result = content.fn(...arguments[1]);
} else {
result = content.fn();
}
delete content.fn;
return result;
}
注意注意:当apply传入的第一个参数为null时,函数体内的this会指向window。
手写手写bind的实现原理的实现原理
bind 方法会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数。
Function.prototype.bind = function(content) {
if(typeof this != 'function') {
throw Error('not a function');
}
let _this = this;
let args = [...arguments].slice(1);
return function F() {
// 判断是否被当做构造函数使用
if(this instanceof F) {
return _this.apply(this, args.concat([...arguments]))
}
return _this.apply(content, args.concat([...arguments]))
}
}
手写手写call的实现原理的实现原理
call语法:fun.call(thisArg, arg1, arg2, arg3, …)
call 的核心原理:
将函数设为对象的属性
执行和删除这个函数
指定this到函数并传入给定参数执行函数
如果不传参数,默认指向window
Function.prototype.call2 = function(content = window) {
// 判断是否是underfine和null
// if(typeof content === 'undefined' || typeof content === null){
// content = window
// }
content.fn = this;
let args = [...arguments].slice(1);
let result = content.fn(...args);
delete content.fn;
return result;
}
注意注意:当call传入的第一个参数为null时,函数体内的this会指向window。
手写手写new的实现原理的实现原理
实现一个new操作符的具体实现步骤:
首先函数接受不定量的参数,第一个参数为构造函数,接下来的参数被构造函数使用
然后内部创建一个空对象 obj
因为 obj 对象需要访问到构造函数原型链上的属性,所以我们通过 setPrototypeOf 将两者联系起来。这段代码等同于 obj.proto = Con.prototype
将 obj 绑定到构造函数上,并且传入剩余的参数
判断构造函数返回值是否为对象,如果为对象就使用构造函数返回的值,否则使用 obj,这样就实现了忽略构造函数返回的原始值
/**
* 创建一个new操作符
* @param {*} Con 构造函数
* @param {...any} args 忘构造函数中传的参数
*/
function createNew(Con, ...args) {
let obj = {} // 创建一个对象,因为new操作符会返回一个对象
Object.setPrototypeOf(obj, Con.prototype) // 将对象与构造函数原型链接起来
// obj.__proto__ = Con.prototype // 等价于上面的写法
let result = Con.apply(obj, args) // 将构造函数中的this指向这个对象,并传递参数
return result instanceof Object ? result : obj
}
注意注意:
一、new操作符的几个作用:
new操作符返回一个对象,所以我们需要在内部创建一个对象
这个对象,也就是构造函数中的this,可以访问到挂载在this上的任意属性
这个对象可以访问到构造函数原型链上的属性,所以需要将对象与构造函数链接起来
返回原始值需要忽略,返回对象需要正常处理
二、new操作符的特点:
new通过构造函数Test创建处理的实例可以访问构造函数中的属性也可以访问构造函数原型链上的属性,所以:通过new操作符,实例与构造函数通过原型链连接了起来
构造函数如果返回原始值,那么这个返回值毫无意义
构造函数如果返回对象,那么这个返回值会被正常的使用,导致new操作符没有作用
手写手写instanceof的实现原理的实现原理
instanceof 用来检测一个对象在其原型链中是否存在一个构造函数的 prototype 属性
function instanceOf(left,right) {
let proto = left.__proto__;
let prototype = right.prototype
while(true) {
if(proto === null) return false
if(proto === prototype) return true
proto = proto.__proto__;
}
}
手写手写Promise A+规范规范
在面试中高级前端时。要求被手写Promise A+规范源码是必考题了。如果想详细了解,请参考 一步步教你实现Promise/A+ 规范 完整版
class Promise {
constructor(executor) {
this.status = 'pending' // 初始化状态
this.value = undefined // 初始化成功返回的值
this.reason = undefined // 初始化失败返回的原因
// 解决处理异步的resolve
this.onResolvedCallbacks = [] // 存放所有成功的resolve
this.onRejectedCallbacks = [] // 存放所有失败的reject
/**
* @param {*} value 成功返回值
* 定义resolve方法
* 注意:状态只能从pending->fulfilled和pending->rejected两个
*/
const resolve = (value) => {
if(this.status === 'pending') {
this.status = 'fulfilled' // 成功时将状态转换为成功态fulfilled
this.value = value // 将成功返回的值赋值给promise
// 为了解决异步resolve以及返回多层promise
this.onResolvedCallbacks.forEach(fn => {
fn() // 当状态变为成功态依次执行所有的resolve函数
})
}
}
const reject = (reason) => {
if(this.status === 'pending') {
this.status = 'rejected' // 失败时将状态转换为成功态失败态rejected
this.reason = reason // 将失败返回的原因赋值给promise
this.onRejectedCallbacks.forEach(fn => {
fn() // 当状态变为失败态依次执行所有的reject函数
})
}
}
executor(resolve, reject) // 执行promise传的回调函数
}
/**
* 定义promise的then方法
* @param {*} onFulfilled 成功的回调
* @param {*} onRejected 失败的回调
*/
then(onFulfilled, onRejected) {
// 为了解决then方法返回Promise的情况
const promise2 = new Promise((resolve, reject) => {
if(this.status === 'fulfilled') { // 如果状态为fulfilled时则将值传给这个成功的回调
setTimeout(() => {
const x = onFulfilled(this.value) // x的值有可能为 promise || 123 || '123'...
// 注意:此时调用promise2时还没有返回值,要用setTimeout模拟进入第二次事件循环;先有鸡先有蛋
resolvePromise(promise2, x, resolve, reject)
}, 0)
}
if(this.status === 'rejected') {
setTimeout(() => {
const x = onRejected(this.reason) // 如果状态为rejected时则将视频的原因传给失败的回调
resolvePromise(promise2, x, resolve, reject)
}, 0)
}
if(this.status === 'pending') { // 记录-》解决异步
this.onResolvedCallbacks.push(() => {
剩余12页未读,继续阅读
weixin_38590989
- 粉丝: 8
- 资源: 940
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论0