大家好,这篇文章我只写代码,如果有什么疑问,我们再评论区讨论。
数组
1、手写实现数组map
// array.map(function(currentValue, index, arr), thisValue)
Array.prototype._map = function(callback, thisArg) {
const _mapArr = [];
for (let i = 0; i < this.length; i++) {
const mappedValue = callback.call(thisArg, this[i], i, this);
_mapArr.push(mappedValue);
}
return _mapArr;
};
var numbers = [1, 2, 3, 4, 5];
const doubleNumbers = numbers._map(function(item) {
return item * this.multiplier;
}, { multiplier: 2 });
console.log(doubleNumbers); // [2, 4, 6, 8, 10]
2、手写实现数组reduce
// array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
Array.prototype._reduce = function(callback) {
var acc = this[0];
for (var i = 1; i < this.length; i++) {
acc = callback(acc, this[i], i, this);
}
return acc;
};
var numbers = [1, 2, 3, 4, 5];
var sum = numbers._reduce(function(total, currentValue) {
return total + currentValue;
});
console.log(sum); // 15
3、数组filter
对象
1、Object.create()
function create(obj) {
function F() {}
F.prototype = obj
return new F()
}
2、实现Object.assign
function create(obj) {
function F() {}
F.prototype = obj
return new F()
}
扁平化
1、数组扁平化-手写实现数组flat
Array.prototype._flat = function() {
return this.reduce(function(acc, currVal) {
if (Array.isArray(currVal)) {
return acc.concat(currVal._flat())
} else {
return acc.concat(currVal)
}
}, []);
};
var deepArray = [1, [2, [3, 4], 5]];
console.log(deepArray._flat()); // [1, 2, 3, 4, 5]
2、对象扁平化
function flattenObject(obj) {
let result = {};
function recurse(current, path) {
for (let key in current) {
if (current.hasOwnProperty(key)) {
let newPath = path + (path ? '.' : '') + key;
if (typeof current[key] === 'object') {
recurse(current[key], newPath);
} else {
result[newPath] = current[key];
}
}
}
}
recurse(obj, '');
return result;
}
// 使用示例
let nestedObject = {
a: {
b: {
c: 1,
d: 2
},
e: 3
},
f: 4
};
let flattenedObject = flattenObject(nestedObject);
console.log(flattenedObject);
Promise
1、Promise:
2、promise.all()的实现
3、promise.race的实现
防抖 & 节流
防抖函数
function debounce(func, delay) {
let timer;
return function() {
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, arguments);
}, delay);
};
}
const debouncedEventHandler = debounce(function() {
console.log('debounce')
}, 300);
节流函数
function throttle(func, delay) {
let canExecute = true;
return function() {
if (!canExecute) return;
canExecute = false;
setTimeout(() => {
func.apply(this, arguments);
canExecute = true;
}, delay);
};
}
const throttledEventHandler = throttle(function() {
console.log('throttle')
}, 300);
深拷贝
const originObj = { a: 1, b: { c: 2 } };
// 使用 `JSON.parse` 和 `JSON.stringify` 实现,适用于对象中不包含函数、`undefined` 等特殊值的情况。
// const deepObj = JSON.parse(JSON.stringify(originObj));
// 递归实现
function deepCopy(obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
const newObj = Array.isArray(obj) ? [] : {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = deepCopy(obj[key]);
}
}
return newObj;
}
const deepObj = deepCopy(originObj);
console.log(deepCopiedObject);
this
手写实现call
Function.prototype._call = function(context, ...args) {
context = context || window; // 设置默认上下文为全局对象(window)
const uniqueKey = Symbol(); // 创建一个唯一的键,以免与现有属性冲突
context[uniqueKey] = this; // 将原函数赋值给上下文对象的一个临时属性
const result = context[uniqueKey](...args); // 通过上下文对象调用原函数,传入参数
delete context[uniqueKey]; // 删除临时属性,清理上下文对象
return result;
};
function greet(name) {
console.log(`Hello, ${name}! My name is ${this.name}.`);
}
const person = { name: 'John' };
greet._call(person, 'Alice'); // Hello, Alice! My name is John.
手写实现apply
// 自定义实现 apply
Function.prototype._apply = function(context, argsArray) {
context = context || window; // 设置默认上下文为全局对象(window)
const uniqueKey = Symbol(); // 创建一个唯一的键,以免与现有属性冲突
context[uniqueKey] = this; // 将原函数赋值给上下文对象的一个临时属性
const result = context[uniqueKey](...argsArray); // 通过上下文对象调用原函数,传入参数数组
delete context[uniqueKey]; // 删除临时属性,清理上下文对象
return result;
};
function sum(a, b) {
return a + b + this.c;
}
const obj = { c: 3 };
const numbers = [1, 2];
const result = sum._apply(obj, numbers); // 6
console.log(result);
手写实现bind函数
其他
函数柯里化的实现
手写实现new
操作符(没见过)
手写实现instanceof(没见过)
手写类型判断函数(没见过)
使用 setTimeout 实现 setInterval
实现 sleep 函数(没见过)
数据处理
1、发布-订阅模式
function sleep(time) {
return new Promise((resolve) => {
setTimeout(resolve, time)
})
}
// 使用
async function test() {
console.log('start')
await sleep(2000)
console.log('end')
}
test()
2、双向数据绑定
let obj = {}
let input = document.getElementById('input')
let span = document.getElementById('span')
// 数据劫持
Object.defineProperty(obj, 'text', {
configurable: true,
enumerable: true,
get() {
console.log('获取数据了')
},
set(newVal) {
console.log('数据更新了')
input.value = newVal
span.innerHTML = newVal
}
})
// 输入监听
input.addEventListener('keyup', function(e) {
obj.text = e.target.value
})
3、数组转树形(Tree)结构
// 构建了一个节点映射(map),然后遍历数组两次,一次用于构建节点映射,另一次用于构建树结构。
function arrayToTree(data) {
const map = {};
const tree = [];
data.forEach(item => {
map[item.id] = { ...item, children: [] };
});
data.forEach(item => {
if (item.parent_id !== 0) {
map[item.parent_id].children.push(map[item.id]);
} else {
tree.push(map[item.id]);
}
});
return tree;
}
const dataArray = [
{ "id": 12, "parent_id": 1, "name": "朝阳区" },
{ "id": 241, "parent_id": 24, "name": "田林街道" },
{ "id": 31, "parent_id": 3, "name": "广州市" },
{ "id": 13, "parent_id": 1, "name": "昌平区" },
{ "id": 2421, "parent_id": 242, "name": "上海科技绿洲" },
{ "id": 21, "parent_id": 2, "name": "静安区" },
{ "id": 242, "parent_id": 24, "name": "漕河泾街道" },
{ "id": 22, "parent_id": 2, "name": "黄浦区" },
{ "id": 11, "parent_id": 1, "name": "顺义区" },
{ "id": 2, "parent_id": 0, "name": "上海市" },
{ "id": 24, "parent_id": 2, "name": "徐汇区" },
{ "id": 1, "parent_id": 0, "name": "北京市" },
{ "id": 2422, "parent_id": 242, "name": "漕河泾开发区" },
{ "id": 32, "parent_id": 3, "name": "深圳市" },
{ "id": 33, "parent_id": 3, "name": "东莞市" },
{ "id": 3, "parent_id": 0, "name": "广东省" }
];
const treeData = arrayToTree(dataArray);
console.log(JSON.stringify(treeData, null, 2));
算法题
字符串出现的不重复最长长度
小孩报数问题
有30个小孩儿,编号从1-30,围成一圈依此报数,1、2、3 数到 3 的小孩儿退出这个圈, 然后下一个小孩 重新报数 1、2、3,问最后剩下的那个小孩儿的编号是多少?
function childNum(num, count){
let allplayer = [];
for(let i = 0; i < num; i++){
allplayer[i] = i + 1;
}
let exitCount = 0; // 离开人数
let counter = 0; // 记录报数
let curIndex = 0; // 当前下标
while(exitCount < num - 1){
if(allplayer[curIndex] !== 0) counter++;
if(counter == count){
allplayer[curIndex] = 0;
counter = 0;
exitCount++;
}
curIndex++;
if(curIndex == num){
curIndex = 0
};
}
for(i = 0; i < num; i++){
if(allplayer[i] !== 0){
return allplayer[i]
}
}
}
childNum(30, 3)
统计一个字符串出现最多的字母
输入 : afjghdfraaaasdenas
输出 : a
前面出现过去重的算法,这里需要是统计重复次数。
function findMostFrequentLetter(str) {
// 将字符串转换为小写以进行不区分大小写的统计
const lowerCaseStr = str.toLowerCase();
// 创建一个对象来存储每个字母的出现次数
const charCount = {};
// 遍历字符串并统计每个字母的出现次数
for (let i = 0; i < lowerCaseStr.length; i++) {
const char = lowerCaseStr[i];
if ((char >= 'a' && char <= 'z')) { // 仅考虑字母
charCount[char] = (charCount[char] || 0) + 1;
}
}
// 找到出现次数最多的字母
let mostFrequentChar = '';
let maxCount = 0;
for (let char in charCount) {
if (charCount[char] > maxCount) {
mostFrequentChar = char;
maxCount = charCount[char];
}
}
return mostFrequentChar;
}
// 示例
const inputString = "afjghdfraaaasdenas";
const result = findMostFrequentLetter(inputString);
console.log(result); // 输出:a