1. 冒泡算法
注:重复从第一个位置开始,比较相邻的元素,前>后,则交换位置。最右已经最大的数不用再比较。
function bubble(arr) {
if (!Array.isArray(arr)) {
return
}
let len = arr.length
for (let i = 0; i < len - 1; i++) {
//随着数组末尾最大的数越来越多,遍历的次数应该越来越小
for (let j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
//交换元素位置
let temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
return arr
}
2.call、apply、bind实现
注:众所周知,call、apply是一样的,只是传参有点不一样,前者字符串,后者数组。 手写虽然没必要,但是面试笔试可能用到,且需要封装在所有函数的原型上。
call:
/**
*
* @param {*} thisArg this绑定谁
* @param {...any} args 剩余参数
* @returns
*/
// 1.给所有函数添加mycall方法
Function.prototype.mycall = function (thisArg, ...args) {
// 拿到调用这个方法的函数
let fn = this
//判断传入thisArg是否对象类型
thisArg = (thisArg == 0 || thisArg) ? Object(thisArg) : window
thisArg.fn = fn
let result = thisArg.fn(...args)
delete thisArg.fn
//或者
// fn.call(thisArg)
//拿到结果返回出去
return result
}
//测试代码
// function foo(num1, num2) {
// console.log(num1 + num2, this);
// return num1 + num2
// }
// const count = foo.wqcall('abc', 10, 20)
// console.log(count);
apply:
//自己实现apply
Function.prototype.myapply = function (thisArg, argArray = []) {
//可能fn函数有重复,用symbol就不会重复了
let s1 = Symbol('fn')
let fn = this
thisArg = (thisArg === 0 || thisArg) ? Object(thisArg) : window
thisArg[s1] = fn
const result = thisArg[s1](...argArray)
delete thisArg[s1]
return result
}
bind:
/**
*
* @param {*} thisArg this绑定谁
* @param {...any} argArray 剩余参数
* @returns
*/
Function.prototype.mybind = function (thisArg, ...argArray) {
// 1.获取真实需要调用的函数
var fn = this
// 2.绑定this
thisArg = (thisArg == 0 || thisArg) ? Object(thisArg) : window
//bind要用函数代理 args是调用bind返回的函数时传的参
function proxyFn(...args) {
thisArg.fn = fn
var finalArgs = [...argArray, ...args]
var result = thisArg.fn(...finalArgs)
delete thisArg.fn
return result
}
return proxyFn
}
function foo(num1, num2, num3) {
console.log("foo函数执行", this, num1, num2, num3);
}
var fn = foo.wqbind("bcb", 1, 2)
fn(3)
3. 深拷贝
//对obj进行深拷贝
let s1 = Symbol('aaa')
let s2 = Symbol('bbb')
const obj = {
name: 'wq',
friends: {
name: 'wk',
borthers: 'wdd'
},
hobbies: ['aaa', 'bbb', 'ccc'],
foo: function () {
console.log('函数');
},
[s1]: 'abc',
s2: s2,
set: new Set(['aaa', 'bbb', 'ccc']),
map: new Map([['aaa', 'bbb'], ['ccc', 'ddd']])
}
//判断是否是对象的工具函数
function isObject(value) {
const valueType = typeof value
return (value !== 'null') && (valueType === 'object' || valueType === 'function')
}
//深拷贝
function deepClone(originValue, map = new WeakMap()) {
//判断是否是set
if (originValue instanceof Set) {
return new Set([...originValue])
}
//判断是否是map
if (originValue instanceof Map) {
return new Map([...originValue])
}
//判断是否是symbol
if (typeof originValue === 'symbol') {
return Symbol(originValue.description)
}
//判断是否是函数
if (typeof originValue === 'function') {
return originValue
}
//如果不是对象,就直接返回值
if (!isObject(originValue)) {
return originValue
}
//如果map里包含这个对象,则是循环引用
if (map.has(originValue)) {
return map.get(originValue)
}
//如果是对象或者数组
const newObject = Array.isArray(originValue) ? [] : {}
map.set(originValue, newObject)
for (const key in originValue) {
newObject[key] = deepClone(originValue[key], map)
}
//symbol无法遍历出来,特殊处理
const symbolKeys = Object.getOwnPropertySymbols(originValue)
for (const skeys of symbolKeys) {
newObject[skeys] = deepClone(originValue[skeys], map)
}
return newObject
}
加入循环引用测试
obj.info = obj
const newObject = deepClone(obj)
obj.friends.name = 'ssss'
console.log(newObject);
4.防抖
/**
* @param {*} fn 调用的函数
* @param {*} delay 延时多久
* @param {*} immediate 是否立即调用
* @returns 闭包
*/
function debounce(fn, delay, immediate = true) {
let timer = null
const _debounce = function (...args) {
if (timer) clearTimeout(timer)
if (immediate) {
let now = !timer
timer = setTimeout(() => {
timer = null
}, delay);
now && fn.apply(this, args)
} else {
timer = setTimeout(() => {
timer = null
fn.apply(this, args)
}, delay);
}
}
return _debounce
}
//测试
const inputEl = document.querySelector("input")
let counter = 0
const inputChange = function (event, a) {
console.log(`发送了第${++counter}次网络请求`, this, event, a);
}
inputEl.oninput = debounce(inputChange, 2000, false)