Skip to main content

Handing 手写类

随机全部
顺序全部
随机置顶
随机 🍀
顺序 🍀
5道(49
随机 ⚡️
重置
1
🌗

实现一个 instanceof

function myInstanceof(left, right) {
let proto = Object.getPrototypeOf(left)

while (true) {
if (proto === null) return false;
if (proto === right.prototype) return true;
proto = Object.getPrototypeOf(proto);
}
}

实现一个 call 函数

  1. 判断调用对象是否为函数,即使我们是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况;
  2. 判断传入上下文对象是否存在,如果不存在,则设置为 window;
  3. 处理传入的参数,截取第一个参数后的所有参数;
  4. 将函数作为上下文对象的一个属性;
  5. 使用上下文对象来调用这个方法,并保存返回结果;
  6. 删除刚才新增的属性;
  7. 返回结果。
Function.prototype.myCall = function (context, ...args) {
if (typeof this !== 'function') {
throw new TypeError('Error');
}
context = context || window;
context.fn = this;
const result = context.fn(...args);
delete context.fn;
return result;
}

实现一个 apply 函数

  1. 判断调用对象是否为函数,即使我们是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况;
  2. 判断传入上下文对象是否存在,如果不存在,则设置为 window;
  3. 将函数作为上下文对象的一个属性;
  4. 判断参数值是否传入;
  5. 使用上下文对象来调用这个方法,并保存返回结果;
  6. 删除刚才新增的属性;
  7. 返回结果。
Function.prototype.myApply = function (context, arr) {
if (typeof this !== 'function') {
throw new TypeError('Error');
}
context = context || window;
context.fn = this;
let result;
if (!arr) {
result = context.fn();
} else {
result = context.fn(...arr);
}
delete context.fn;
return result;
}

实现一个 bind 函数

  1. 判断调用对象是否为函数,即使我们是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况;
  2. 保存当前函数的引用,获取其余传入参数值;
  3. 创建一个函数返回;
  4. 函数内部使用 apply 来绑定函数调用,需要判断函数作为构造函数的情况,这个时候需要传入当前函数的 this 给 apply 调用,其余情况都传入指定的上下文对象。
Function.prototype.myBind = function (context, ...args) {
if (typeof this !== 'function') {
throw new TypeError('Error');
}
const fn = this;
return function result(...innerArgs) {
return fn.apply(
this instanceof result ? this : context,
args.concat(...innerArgs)
);
}
}

实现一个 new 函数

function _new(obj, ...rest) {
const newObj = Object.create(obj.prototype);
const result = obj.apply(newObj, rest);
return result instanceof Object ? result : newObj;
}

实现 Object.create() 函数

function _create(obj, props) {
function Fn() { }
Fn.prototype = obj;
const fn = new Fn();
if (props) {
Object.defineProperties(fn, props)
}
return fn
}

实现 Object.is() 函数

function _is(x, y) {
if (x === y) {
// 使 +0 和 -0 返回 false
// 1/+0 = +Infinity 1/-0 = -Infinity -> +Infinity !== -Infinity
return x !== 0 || 1 / x === 1 / y;
}
// 使两个 NaN 返回 true
// 一个变量不等于自身变量,那么它一定是 NaN -> x 和 y 都是 NaN 时返回 true
return x !== x && y !== y;
};

实现数组的 flat 方法

function myFlat(arr, depth = 1) {
if (!Array.isArray(arr) || depth <= 0) {
return arr;
}
let result = [];
arr.forEach(item => {
result = result.concat(myFlat(item, depth - 1));
});
return result;
}

实现数组的 filter 方法

Array.prototype.myFilter = function (callback, thisArg) {
if (typeof callback !== 'function') {
throw new TypeError('callback type error');
}
const result = [];
this.forEach((item, index) => {
if (callback.call(thisArg, item, index, this)) {
result.push(item);
}
});
return result;
}

实现数组的 map 方法

Array.prototype.myMap = function (callback, context) {
if (typeof callback !== 'function') {
throw new TypeError('callback type error');
}
const result = [];
this.forEach((item, index) => {
result.push(callback.call(context, item, index, this));
});
return result;
};

CSS 手写 clearfix 清除浮动

.clearfix:after {
content: "";
display: block;
clear: both;
}

.clearfix {
zoom: 1; // 兼容 IE
}

CSS 用 flex 绘制个三点骰子

.box {
display: flex;
justify-content: space-between;
}

.item:nth-child(2) {
align-self: center;
}

.item:nth-child(3) {
align-self: flex-end;
}

CSS 实现超出一行显示省略号

overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;

将对象的 key 值作为数组返回

const grade = {
"Tim": 96,
"Bang": 99
}
// --> ["Tim", "Bang"]

// ES5 实现
const result = []
for (let k in grade) {
result.push(k)
}

// ES8 实现
const result = Object.keys(grade)

将对象的 value 值作为数组返回

const grade = {
"Tim": 96,
"Bang": 99
}
// --> [96, 99]

// ES5 实现
const result = []
for (let k in grade) {
result.push(grade[k])
}

// ES8 实现
const result = Object.values(grade)

判断对象是否为空

function judge(obj) {
for (let i in obj) {
return false;
}
return true;
}

实现深拷贝函数

function deepCopy(obj) {
if (typeof obj !== "object" || obj === null) {
return obj;
}

let result;
if (obj instanceof Array) {
result = [];
} else {
result = {};
}

for (let key in obj) {
if (obj.hasOwnProperty(key)) {
result[key] = deepCopy(obj[key]);
}
}

return result;
}

实现构造函数的继承

function City() {
this.city = 'Guangzhou'
}

function District(name) {
this.name = name
City.call(this)
}

const district1 = new District('Haizhu') // {name: 'Haizhu'}

实现原型链的继承

function City() {
this.city = 'Guangzhou'
}

function District(name) {
this.name = name
}
District.prototype = new City()

const district1 = new District('Haizhu') // {name: 'Haizhu'}

实现 ES6 class 的继承

class City {
constructor(name) {
this.city = 'Guangzhou'
this.district = name
}
}

class District extends City {
constructor(name) {
super(name);
}
}

const district1 = new District("Haizhu") // {name: 'Haizhu'}

实现 JavaScript 中的异常捕获

try {
// todo
} catch (ex) {
// 手动捕获 catch
console.error(ex);
} finally {
// todo
}

实现函数柯里化

function curry(fn, ...args) {
if (args.length >= fn.length) {
return fn(...args)
}
return (...args2) => curry(fn, ...args, ...args2);
}

const add = (x, y) => {
console.log(x + y)
}
const curriedAdd = curry(add)
curriedAdd(1)(2) // 3
curriedAdd(1, 2) // 3

常见的正则表达式类问题

// 手写手机号正则表达式
// 手写邮箱正则表达式

实现获取 URL 中参数

const getParam = key => {
const params = new URLSearchParams(window.location.search);
return params.get(key)
}

模拟实现 Promise

function MyPromise(fn) {
this.state = "pending";
this.value = null;
this.resolveFns = [];
this.rejectFns = [];

function resolve(value) {
if (value instanceof MyPromise) {
return value.then(resolve, reject);
}
setTimeout(() => {
if (this.state === "pending") {
this.state = "resolved";
this.value = value;
this.resolveFns.forEach(callback => {
callback(value);
});
}
});
}

function reject(value) {
setTimeout(() => {
if (this.state === "pending") {
this.state = "rejected";
this.value = value;
this.rejectFns.forEach(callback => {
callback(value);
});
}
});
}

try {
fn(resolve, reject);
} catch (e) {
reject(e);
}
}

MyPromise.prototype.then = function (onResolved, onRejected) {
if (this.state === "pending") {
this.resolveFns.push(onResolved);
this.rejectFns.push(onRejected);
}
if (this.state === "resolved") {
onResolved(this.value);
}
if (this.state === "rejected") {
onRejected(this.value);
}
};

封装 React 受控组件

import React from 'react';
import useDefault from '../hooks/useDefault';

const Switch = (props) => {
const {
value,
defaultValue = false,
onChange
} = props;

const [innerValue, setInnerValue] = useDefault(value, defaultValue, onChange);

const handleSwitch = () => {
// 注意这里不需要额外调用 onChange,钩子函数中已经做了处理
setInnerValue(!innerValue)
}

return (
<button onClick={handleSwitch}>
{innerValue ? '开' : '关'}
</button>
);
};

实现防抖和节流函数

function debounce(fn, wait) {
let timer = null;

return function () {
if (timer) {
clearTimeout(timer);
timer = null;
}
timer = setTimeout(() => {
fn.apply(this, arguments)
}, wait);
}
}

Ajax 的使用

const xhr = new XMLHttpRequest();

xhr.open("GET", url, true);

xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText);
}
};

xhr.send();

MySQL 增删改查语句

-- 插入数据
INSERT INTO users ( username, PASSWORD ) VALUES ('aaa', 123456);

-- 删除数据
DELETE FROM users WHERE username = 'aaa';

-- 修改数据
UPDATE users SET username = 'bbb' WHERE username = 'aaa';

-- 查询数据
SELECT username FROM users;

实现工厂模式

class Benz {
getName() {
console.log("奔驰");
}
}

class Audi {
getName() {
console.log("奥迪");
}
}

class Car {
constructor(name) {
switch (name) {
case "benz":
return new Benz();
case "audi":
return new Audi();
default:
throw TypeError("error name");
}
}
}

const benz = new Car("benz");
benz.getName(); // 奔驰

实现单例模式

class Benz {
getName() {
console.log("奔驰");
}
}

const Singleton = (function () {
let instance = null;

return {
getInstance: function () {
if (!instance) {
instance = new Benz();
}
return instance;
},
};
})();

const benz1 = Singleton.getInstance()
const benz2 = Singleton.getInstance()
console.log(benz1 === benz2) // true

实现适配器模式

class OldBenz {
getName() {
return '奔驰';
}
}

class NewBenz {
constructor() {
this.adapter = new OldBenz();
}
getName() {
const name = this.adapter.getName();
return name;
}
}

const benz = new NewBenz();
console.log(benz.getName()); // 奔驰

实现装饰器模式

function decorator(car) {
car.color = 'black'
return car
}

@decorator
class Benz {
getName() {
console.log("奔驰")
}
}

console.log(Benz.color)

实现代理模式

const myCar = {
name: 'Benz',
price: 30
}

const carStore = new Proxy(myCar, {
get(target, key) {
if (key === 'price') {
return target[key] + 5
} else {
return target[key]
}
}
})

console.log(carStore.price, carStore.name) // 35 'Benz'

实现观察者模式

class Subject {
constructor() {
this.observers = [];
}
attach(observer) {
this.observers.push(observer);
}
notify() {
this.observers.forEach((o) => o.update());
}
}

class Observer {
update() {
console.log('通知:被观察者已更新');
}
}

// 创建被观察者
const subject = new Subject();
// 创建多个观察者
const o1 = new Observer();
const o2 = new Observer();
// 各个观察者订阅 subject 的通知
subject.attach(o1);
subject.attach(o2);

// 发出广播,执行所有观察者的 update 方法
subject.notify(); // 通知:被观察者已更新 × 2

实现迭代器模式

// 定义迭代器生成函数,入参是任意集合
function iteratorGenerator(items) {
let index = 0
return {
next: function () {
return {
done: index >= items.length,
value: index >= items.length ? undefined: items[index++],
}
}
}
}

const arr = ['a', 'b', 'c'];
const iterator = iteratorGenerator(arr);

iterator.next() // { done: false, value: 'a' }
iterator.next() // { done: false, value: 'b' }
iterator.next() // { done: false, value: 'c' }

实现冒泡排序算法

function bubbleSort(arr) {
for (let i = arr.length - 1; i > 0; i--) {
for (let j = 0; j < i; j++) {
if (arr[j] > arr[j + 1]) {
const temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
return arr;
}

const arr = [6, 5, 3, 4, 2, 1];
console.log(bubbleSort(arr)); // [1, 2, 3, 4, 5, 6]

实现选择排序算法

function selectionSort(arr) {
for (let i = 0, len = arr.length; i < len; i++) {
let minIndex = i;
for (let j = i + 1; j < len; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
const temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
return arr;
}

const arr = [6, 5, 3, 4, 2, 1];
console.log(selectionSort(arr)); // [1, 2, 3, 4, 5, 6]

实现插入排序算法

function insertionSort(arr) {
for (let i = 1, len = arr.length; i < len; i++) {
const insert = arr[i];
for (var j = i - 1; j >= 0; j--) {
if (insert < arr[j]) {
const tmp = arr[j];
arr[j + 1] = tmp;
} else {
break;
}
}
arr[j + 1] = insert;
}
return arr;
}

const arr = [6, 5, 3, 4, 2, 1];
console.log(insertionSort(arr)); // [1, 2, 3, 4, 5, 6]

实现归并排序算法

const mergeSort = arr => {
if (arr.length <= 1) {
return arr;
}
const mid = Math.floor(arr.length / 2);
const left = arr.slice(0, mid);
const right = arr.slice(mid);
// 合并成一个有序数组
const merge = (left, right) => {
const result = [];
// 将左右子数组较小的元素放入 result,直到有一个子数组遍历完毕
while (left.length && right.length) {
if (left[0] < right[0]) {
result.push(left.shift());
} else {
result.push(right.shift());
}
}
// 此时将另一个子数组剩余的元素放入 result
return result.concat(left).concat(right);
}

return merge(mergeSort(left), mergeSort(right));
}

const arr = [6, 5, 3, 4, 2, 1];
console.log(mergeSort(arr)); // [1, 2, 3, 4, 5, 6]

实现快速排序算法

const quickSort = (arr) => {
const len = arr.length;
if (len < 2) {
return arr;
} else {
const flag = arr[0];
const left = [];
const right = [];
for (let i = 1; i < len; i++) {
const temp = arr[i];
if (temp < flag) {
left.push(temp);
} else {
right.push(temp);
}
}
return quickSort(left).concat(flag, quickSort(right));
}
};

const arr = [6, 5, 3, 4, 2, 1];
console.log(quickSort(arr)); // [1, 2, 3, 4, 5, 6]

实现数组随机排序

const shuffle = (arr) => arr.sort(() => Math.random() - 0.5)

实现数组元素求和

const sum = (arr) => arr.reduce((total, item) => total += item)

实现数组扁平化

const flatten = (arr) => {
while (arr.some(item => Array.isArray(item))) {
arr = [].concat(...arr)
}
return arr
}

实现数组去重(越多越好)

// 嵌套循环的方式
const unique = (arr) => {
for (let i = 0, len = arr.length; i < len; i++) {
for (let j = i + 1; j < len; j++) {
if (arr[i] === arr[j]) {
// 如果有重复,就从原数组中删去重复的元素,并修改 len 和 j 的值
arr.splice(j, 1);
len--;
j--;
}
}
}
return arr;
}

// ES6 Set
const unique = (arr) => [...new Set(arr)]

// 对象的方式
const unique = (arr) => {
const result = [];
const obj = {}; // 用来去重的对象
for (let i = 0; i < arr.length; i++) {
if (!obj[arr[i]]) {
result.push(arr[i]);
obj[arr[i]] = 'x';
}
}
return result;
}

数组从小到大排序(+相反)

// 从小到大排
const sortArr1 = (arr) => arr.sort((a, b) => a - b)
// 从大到小排 = sortArr1(arr).reverse()
const sortArr2 = (arr) => arr.sort((a, b) => b - a)

实现二分搜索算法 (arr, num) => index

const binarySearch = (arr, num) => {
arr.sort((a, b) => a - b)
let left = 0
let right = arr.length - 1
while (left < right) {
const mid = Math.floor((left + right) / 2)
if (arr[mid] < num) {
left = mid + 1
} else if (arr[mid] > num) {
right = mid - 1
} else {
return mid
}
}
return -1
}

const arr = [6, 5, 3, 4, 2, 1];
binarySearch(arr, 3) // 2

实现 add(1)(2)(3)

// 柯里化函数
function curry(fn, ...args) {
// 当接收的参数数量与原函数形参数量一致时,执行原函数
if (args.length >= fn.length) {
return fn(...args)
}
// 否则递归返回一个 curry 函数接收剩余的参数
return (...args2) => curry(fn, ...args, ...args2);
}

// 使用
const add = (x, y, z) => {
return x + y + z
}
const curriedAdd = curry(add)
curriedAdd(1)(2)(3) // 6
curriedAdd(1, 2)(3) // 6
curriedAdd(1, 2, 3) // 6

循环打印红绿黄问题

// 红灯 3s 亮一次,绿灯 2s 亮一次,黄灯 1s 亮一次;如何让三个灯不断交替重复亮灯?

function red() {
console.log('red');
}

function green() {
console.log('green');
}

function yellow() {
console.log('yellow');
}