前端面试知识点整理——常见手撕代码
function bubbleSort(nums) {
//每轮循环都从最后一个元素开始 比较并交换 一次循环会把最小的数顶到最上面
for (let i = 0; i < nums.length - 1; i++) { //只是控制次数为n-1
for (let j = nums.length - 1; j > i; j--) {
if (nums[j] < nums[j - 1]) {
//交换
let temp = nums[j];
nums[j] = nums[j - 1];
nums[j - 1] = temp;
}
}
}
}
//test
nums = [5, 1, 4, 2, 8];
bubbleSort(nums);
console.log(nums);
function selectionSort(nums) {
//和冒泡排序类似,但是并不在每次比较后交换 而是记录最小值(初识最小值为nums[i]) 最后再交换一次
//每次循环也是从最后开始 把最小元素放到最顶部
for (let i = 0; i < nums.length - 1; i++) { //n -1循环
let index = i;
for (let j = nums.length - 1; j > i; j--) {
if (nums[j] < nums[index]) {
index = j;
}
}
//交换
let temp = nums[i];
nums[i] = nums[index];
nums[index] = temp;
}
}
//test
nums = [5, 1, 4, 2, 8];
selectionSort(nums);
console.log(nums);
function insertionSort(nums) {
//插入排序 从第二个元素开始 把元素插入到合适的位置 每次比较(除了最后一次)都要交换
for (let i = 1; i < nums.length; i++) {
for (let j = i; j > 0; j--) {
if (nums[j] < nums[j - 1]) {
//交换
let temp = nums[j];
nums[j] = nums[j - 1];
nums[j - 1] = temp;
} else {
break;
}
}
}
}
//test
nums = [5, 1, 4, 2, 8];
insertionSort(nums);
console.log(nums);
//快速排序最差O(n^2)最优O(nlogn)
function qsort(nums, l, r) {
if (r <= l) return; //注意定义递归中止条件
let pivot = nums[l]; //选择最左为轴值
swap(nums, l, r); //把轴值与最右交换
let i = l;
for (let j = l; j < r; j++) {
if (nums[j] < pivot) {
swap(nums, i, j);
i++;
}
}
swap(nums, i, r); //此时i为轴值下标
qsort(nums, l, i - 1);
qsort(nums, i + 1, r);
}
function swap(nums, i, j) {
let temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
//test
nums = [5, 1, 4, 2, 8, 11, 2, 3];
qsort(nums, 0, nums.length - 1);
console.log(nums);
//堆排序 建堆O(n) 删除n个O(nlogn)
function heapSort(nums) {
if (nums.length <= 1) return nums;
let res = [];
let heapSize = nums.length;
buildHeap(nums, heapSize);
for (let i = 0; i < nums.length; i++) {
res.push(nums[0]);
swap(nums, 0, --heapSize);
siftDown(nums, 0, heapSize);
}
return res;
}
//建堆 (最小堆)
function buildHeap(nums, heapSize) {
for (let i = Math.floor(heapSize / 2) - 1; i >= 0; i--) {
siftDown(nums, i, heapSize);
}
}
//siftDown
function siftDown(nums, i, heapSize) {
let smallest = i;
let l = 2 * i + 1;
let r = 2 * i + 2;
if (l < heapSize && nums[l] < nums[smallest]) {
smallest = l;
}
if (r < heapSize && nums[r] < nums[smallest]) {
smallest = r;
}
if (smallest != i) {
swap(nums, i, smallest);
siftDown(nums, smallest, heapSize);
}
}
function swap(nums, i, j) {
let temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
//test
nums = [5, 1, 4, 2, 8, 11, 2, 3];
let res = heapSort(nums);
console.log(res);
function mergeSort(nums) {
if (nums.length <= 1) return nums;
let middle = Math.floor(nums.length / 2);
let arr1 = nums.slice(0, middle);
let arr2 = nums.slice(middle);
return merge(mergeSort(arr1), mergeSort(arr2));
}
function merge(arr1, arr2) {
let res = [];
while (arr1.length > 0 && arr2.length > 0) {
if (arr1[0] <= arr2[0]) {
res.push(arr1.shift());
} else {
res.push(arr2.shift());
}
}
return res.concat(arr1).concat(arr2);
}
//test
nums = [5, 1, 4, 2, 8, 11, 2, 3];
let res = mergeSort(nums);
console.log(res);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input type="text">
<script>
const input = document.querySelector('input');
function debounce(fn, delay) {
let timer = null;
return function () {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
fn();
}, delay)
}
}
input.onkeyup = debounce(() => {
console.log(input.value);
}, 3000)
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input type="text">
<script>
const input = document.querySelector('input');
function throttle(fn, delay) {
let timer = null;
return function () {
if (timer) {
return;
}
timer = setTimeout(() => {
fn();
timer = null;
}, delay)
}
}
input.onkeyup = throttle(() => {
console.log(input.value);
}, 3000)
</script>
</body>
</html>
function sum(...args) {
//对第一层参数求和
let x = args.reduce((acc, next) => {
return acc + next;
})
//返回一个新的函数
return function (...args2) { //第二层的参数
//当没有第二层参数时,返回x即可
if (args2.length == 0) return x;
let y = args2.reduce((acc, next) => {
return acc + next;
})
return sum(x + y); //返回x+y作为新的第一层
}
}
console.log(sum(1, 2)(3)(4)()); // 10
console.log(sum(1)(2, 3, 4, 5)(10)()); // 25
//自己写一个减法的 天才!
function decrease(...args) {
let x = args.reduce((acc, next) => {
return acc - next;
})
console.log(x);
return function (...args2) {
if (args2.length == 0) return x;
let y = args2.reduce((acc, next) => {
return acc - next;
}, 0)
console.log(y);
return decrease(x + y);
}
}
console.log(decrease(1, 2)(3)(4, 5)()); // -13
console.log(decrease(1)(2, 3, 4, 5)(10)()); // -23
String.prototype.trim = function () {
return this.replace(/^\s+/g, "").replace(/\s+$/g, "");
}
let str = ' 123 ';
console.log(str);
let str1 = str.trim();
console.log(str1);
function flatten(arr) {
let res = [];
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
res = res.concat(flatten(arr[i]));
} else {
res.push(arr[i]);
}
}
return res;
}
let arr = [1, 2, 3, [4, 5, 6, [7, 8, 9]], 10];
console.log(flatten(arr));
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
img {
display: block;
width: 100%;
height: 300px;
margin-bottom: 10px;
}
</style>
</head>
<body>
<img data-src="mao.jpg" alt="">
<img data-src="mao.jpg" alt="">
<img data-src="mao.jpg" alt="">
<img data-src="mao.jpg" alt="">
<img data-src="mao.jpg" alt="">
<img data-src="mao.jpg" alt="">
<img data-src="mao.jpg" alt="">
<img data-src="mao.jpg" alt="">
<img data-src="mao.jpg" alt="">
<img data-src="mao.jpg" alt="">
<img data-src="mao.jpg" alt="">
<img data-src="mao.jpg" alt="">
</body>
<script>
var imgs = document.querySelectorAll('img');
//获得元素距离页面顶部的距离
function getTop(e) {
var T = e.offsetTop;
while (e = e.offsetParent) {
T += e.offsetTop;
}
return T;
}
function lazyLoad(imgs) {
//获取可视区高度
var H = window.innerHeight || document.documentElement.clientHeight;
//获取被卷页面高度
var S = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
for (let i = 0; i < imgs.length; i++) {
if (H + S > getTop(imgs[i])) {
imgs[i].src = imgs[i].getAttribute('data-src');
}
}
}
window.onload = window.onscroll = function () {
lazyLoad(imgs);
}
</script>
</html>
function deepClone(obj) {
var clone;
if (obj && typeof obj !== 'object') clone = obj;
else {
clone = Array.isArray(obj) ? [] : {};
for (let k in obj) {
if (obj.hasOwnProperty(k)) {
if (obj[k] && typeof obj[k] === 'object') {
clone[k] = deepClone(obj[k]);
} else {
clone[k] = obj[k];
}
}
}
}
return clone;
}
//test
let obj = {
name: 'vivian',
age: 18,
mark: {
one: 1,
two: 2
},
arr: [1, 2, 3]
}
let clone = deepClone(obj);
console.log(clone);
//bind改变this指向,不调用函数
Function.prototype.mybind = function (context, ...arg) {
let fun = this;
return function () {
return fun.apply(context, arg)
}
}
//test
let obj = {
name: 'vivian'
}
function test(arg1, arg2, arg3) {
console.log(this.name);
console.log(arg1, arg2, arg3);
}
let f = test.bind(obj, 1, 2, 3); //返回一个函数
f();
//apply改变this指向 调用函数 参数为数组
Function.prototype.myApply = function (context, arg) {
context.fn = this;
let res;
if (!arg) {
res = context.fn();
} else {
res = context.fn(...arg);
}
delete context.fn;
return res;
}
//test
let obj = {
name: 'vivian'
}
function test(arg1, arg2, arg3) {
console.log(this.name);
console.log(arg1, arg2, arg3);
}
test.myApply(obj, [1, 2, 3]);
//call改变this指向 调用函数
Function.prototype.mycall = function (context, ...arg) {
context.fn = this; //this是test函数,把他作为context的方法而存在
let res = context.fn(...arg);
delete context.fn;
return res;
}
//test
let obj = {
name: 'vivian'
}
function test(arg1, arg2, arg3) {
console.log(this.name);
console.log(arg1, arg2, arg3);
}
test.mycall(obj, 1, 2, 3);
class EventEmitter {
constructor() {
//缓存列表
this.list = {};
}
//on:把callback函数注册到缓存列表中
on(eventName, callback) {
if (!this.list[eventName]) {
//当还没有这个事件时,为这个事件添加一个缓存列表
this.list[eventName] = [callback];
} else {
//当已经存在这个事件的缓存列表之后,直接添加
this.list[eventName].push(callback);
}
}
//emit:根据event去执行对应缓存列表里面的函数
emit(eventName, ...args) {
this.list[eventName].forEach(fn => fn.apply(this, args));
}
//once:只监听一次
once(eventName, callback) {
const fn = () => {
callback();
this.remove(eventName, fn);
}
this.on(eventName, fn);
}
//remove:取消订阅
remove(eventName, callback) {
this.list[eventName] = this.list[eventName].filter(fn => fn != callback);
}
}
const PEDDING = Symbol();
const FULFILLED = Symbol();
const REJECTED = Symbol();
const myPromise = function (fn) {
this.status = PEDDING;
this.value = '';
const resolve = (value) => {
this.status = FULFILLED;
this.value = value;
}
const reject = (error) => {
this.status = REJECTED;
this.value = error;
}
this.then = (onFulfilled, onRejected) => {
if (this.status == FULFILLED) {
onFulfilled(this.value);
}
if (this.status == REJECTED) {
onRejected(this.value);
}
}
try {
fn(resolve, reject);
} catch (error) {
reject(error);
}
}
//test
let p = new myPromise((resolve, reject) => {
resolve(123);
})
p.then(value => {
console.log(value);
})
let p2 = new Promise((resolve, reject) => {
resolve(456);
})
p2.then(value => {
console.log(value);
})
function isPromise(obj) {
return !!obj && (typeof obj === 'function' || typeof obj === 'object') && typeof obj.then == 'function';
}
function myPromiseAll(arr) {
let res = []
return new Promise((resolve, reject) => {
for (let i = 0; i < arr.length; i++) {
if (isPromise(arr[i])) {
arr[i].then(data => {
res[i] = data;
if (res.length === arr.length) {
resolve(res)
}
}).catch(error => {
reject(error)
})
} else {
res[i] = arr[i];
}
}
})
}
//test
var p1 = Promise.resolve('a');
var p2 = Promise.resolve('b');
var p3 = Promise.resolve('c');
Promise.all([p1, p2, p3]).then(function (value) {
console.log(value);
})
const ptest = myPromiseAll([p1, p2, p3]);
ptest.then(value => {
console.log(value);
})
function myPromiseRace(arr) {
return new Promise((resolve, reject) => {
for (let i = 0; i < arr.length; i++) {
return arr[i].then(resolve, reject);
}
})
}
//test
const p1 = Promise.reject('a');
const p2 = Promise.resolve('b');
const p3 = Promise.resolve('c');
Promise.race([p1, p2, p3]).then(value => {
console.log(value);
}).catch(error => {
console.log(error);
})
myPromiseRace([p1, p2, p3]).then(value => {
console.log(value);
}).catch(error => {
console.log(error);
})
let newscript = document.createElement('script');
newscript.src = 'https://www.abc.com?callback=fn';;
document.body.appendChild(newscript);
function fn(data) {
console.log(data);
}
function _new() {
//1. 创建一个新对象
let obj = new Object();
//2. 让this指向这个对象
let [func, ...arg] = [...arguments];
obj.__proto__ = func.prototype;
//3. 执行构造函数里面的代码
let res = func.apply(obj, arg);
//4. 返回这个对象
if (res && (typeof res === 'object') || (typeof res === 'Function')) {
return res;
} else {
return obj;
}
}
function Person(uname, age) {
this.uname = uname;
this.age = age;
}
let obj1 = new Person('vivian', 18);
let obj2 = _new(Person, 'vivian', 18);
console.log(obj1, obj2);
function instance_of(left, right) {
let prototype = right.prototype;
left = left.__proto__;
while (true) {
if (!left) return false;
if (left == prototype) return true;
left = left.__proto__;
}
}
console.log([] instanceof Array);
console.log(instance_of([], Array));
function myInterval(fn, delay) {
let content = this;
setTimeout(() => {
fn.call(content);
myInterval(fn, delay); //递归
}, delay);
}
myInterval(() => {
console.log(1);
}, 2000)