各种手写源码
技术面试如果足够有诚意就让人拿出笔记本当场写,随便查,你才能看到面试者在真实的写代码的时候是什么状态,什么思路。就看面试者去哪里查,怎么查,你就能得到比让人默写 API 要有价值得多的信息
——尤雨溪
async/await 实现
实现一个双向数据绑定
Array.isArray 实现
promise 实现
防抖
文章可见防抖与节流
饭都
javascript
function debounce(func, wait, flag) {
let timer = null;
return function (...args) {
clearTimeout(timer);
if (!timer && flag) {
func.apply(this, args)
} else {
timer = setTimeout(() => {
func.apply(this, args)
}, wait)
}
}
}
节流
javascript
function throttle(func, wait) {
let pre,
timer = null;
if (Date.now() - pre > wait) {
clearTimeout(timer);
timer = null;
pre = Date.now()
func.apply(this, args)
} else if (!timer) {
timer = setTimeout(() => {
func.apply(this, args)
}, wait)
}
}
new
文章可看new 做了什么
ES5 版本:
javascript
function new2(Constructor, ...args) {
let obj = Object.create(null);
obj.__proto__ = Constructor.prototype;
let result = Constructor.apply(obj, args);
return typeof result === 'object' ? result : obj;
}
ES3 版本:
javascript
function new3() {
let obj = {},
Constructor = Array.prototype.shift.call(arguments)
var F = function(){}
F.prototype = Constructor.prototype
obj = new F()
var result = Constructor.apply(obj, arguments)
returb typeof result === 'object' ? result : obj
}
Object.create
javascript
function create(obj) {
function F() {}
F.prototype = obj;
return new F()
}
深拷贝
文章可看拷贝的密码
javascript
function deepClone(source, storage = new WeakMap()) {
// 针对基本数据类型
if (typeof source !== 'object' || source === null) {
return source
}
// 是否是日期
if (source.constructor === Date) {
return new Date(source)
}
// 是否是正则
if (source.constructor === RegExp) {
return new RegExp(source)
}
// 是否是数组
let target = source instanceof Array ? [] : {}
// 循环引用 返回存储的引用数据
if (storage.has(source)) return storage.get(source)
// 开辟存储空间设置临时存储值
storage.set(source, target)
// 是否包含 Symbol 类型
let isSymbol = Object.getOwnPropertySymbols(source)
// 包含 Symbol 类型
if (isSymbol.length) {
isSymbol.forEach((item) => {
if (typeof source[item] === 'object') {
target[item] = deepClone(source[item], storage);
return
}
target[item] = source[item]
})
}
// 不包含 Symbol
for(let key in source) {
if (source.hasOwnProperty(key)) {
target[key] = typeof source[key] === 'object' ? deepClone(sourcep[key], storage) : source[key]
}
}
return target;
}
instanceof
文章可看instanceof——找祖籍
javascript
function myInstanceof(left, right) {
if (typeof left !== 'object' || left === null) return false;
let proto = Object.getPrototypeOf(left);
while (true) {
if (proto == null) return false;
if (proto == right.prototype) return true;
proto = Object.getPrototypeOf(proto);
}
}
call、apply、bind
call
javascript
function myCall(context = window, args) {
if (this === Function.prototype) {
return undefined;
}
let fn = Symbol()
context[fn] = this;
let result = context[fn](...args)
delete context[fn];
return result
}
apply
javascript
function myApply(context = window, args) {
if (this === Function.prototype){
return undefined
}
let fn = Symbol()
context[fn] = this;
let result;
if (Array.isArray(arg)){
result = context[fn](...args)
} else {
result = context[fn]()
}
delete context[fn]
return result
}
bind
javascript
function myBind(context, ...args1) {
if (this === Function.prototype) {
return new TypeError('Error')
}
const _this = this;
return function F(...args2) {
if (this instance F) {
return new _this(...args1, ...args2)
}
return _this.apply(context, args1.concat(args2))
}
}
柯里化
ES5实现:
javascript
function curry(fn) {
return function curriedFn() {
var _args = Array.prototype.slice.call(arguments);
if (_args.length < fn.length) {
return function () {
var _args2 = Array.prototype.slice.call(arguments);
return curriedFn.apply(null, _args.concat(_args2));
};
}
return fn.apply(null, _args);
};
}
ES6实现:
javascript
function curry(fn) {
// 获取函数的参数数量
const argLength = fn.length;
// 定义递归的柯里化函数
function inner(...args) {
// 如果参数的数量满足要求,调用原函数
if (args.length >= argLength) {
return fn(...args)
} else {
// 否则返回一个新函数,继续接收参数
return function (...args2) {
return inner(...args, ...args2)
}
}
}
return inner;
}
或者(看你那种好理解)
javascript
function curry(fn) {
return function curriedFn(...args) {
if (args.length < fn.length) {
return function () {
return curriedFn(...args.concat(Array.from(arguments)));
};
}
return fn(...args);
};
}
发布订阅
javascript
class eventEmitter {
constructor() {
this.event = {}
}
on(type, callback) {
if (!this.event[type]) {
this.event[type] = [callback]
} else {
this.event[type].push(callback)
}
}
off(type, callback) {
if (!this.event[type]) {
return
}
this.event[type] = this.event[type].filter((item) => {
return item !== callback
})
}
emit(type, ...args) {
if (!this.event[type]) {
return
}
this.event[type].forEach((callback) => {
callback.apply(this, args)
})
}
once(type, callback) {
function f() {
callback()
this.off(type, f)
}
this.on(type, f)
}
}
示例:
javascript
const eventEmitter = new EventEmitter();
// 订阅事件
eventEmitter.on("公众号", (name) => {
console.log(`我订阅了${name}`)
})
// 发布事件
eventEmitter.emit('公众号', '随朱波流')
AJAX
async JavaScript and XML(JSON)
javascript
var xhr = new XMLHttpRequest();
xhr.open('GET', '/xxx', true)
// false 异步
// true 同步
xhr.setRequestHeader("Content-Type", "application/json")
xhr.onreadystatechange = function () {
if (xhr.readyState !== 4) return;
if (xhr.status === 200 || xhr.status === 304) {
console.log('响应数据:', xhr.responseText);
} else {
console.error('请求失败,状态码:' + xhr.status);
}
}
xhr.send();
304:协商缓存重定向
flat
即数组扁平化
javascript
let ary = [1, [2, [3, [4, 5]]], 6];// -> [1, 2, 3, 4, 5, 6]
普通递归
javascript
let result = [];
function flat(arr) {
for (let i = 0; i < arr.length; i++) {
let item = arr[i]
if (Array.isArray(item)) {
flat(item)
} else {
result.push(item)
}
}
}
迭代:for of
for of 是迭代器
javascript
function wrap() {
let ret = []
return function flat(arr) {
for (let item of arr) {
if (item.constructor === Array) {
ret.concat(flat(item))
} else {
ret.push(item)
}
}
return ret
}
}
console.log(wrap()(ary))
方法二:some
Array.prototype.some()
:找到符合条件的元素返回 true,否则则返回 false
javascript
const flatten = function(arr){
while(arr.some(item => Array.isArray(item))) {
arr = [].concat(...arr)
}
return arr
}
console.log(flatten(arr))
方法三:reduce
javascript
const flatten = arr = arr.reduce((acc, cur) => {
return Array.isArray(acc) ? [...acc, ...flatten(cur)] : [...acc, cur]
}, [])
写原型上
javascript
let ary = [1, [2, [3, [4, 5]]], 6];
Array.prototype.flatten = function(depth) {
let result = []
for (let i = 0; i < this.length; i++) {
let item = this[i];
if (Array.isArray(item) && depth > 0) {
result = [...result, ...this[i].flatten(depth -1)]
} else {
result.push(item)
}
}
return result
}
PS:数组原型上已经有 flat,所以改个名字