二分查找
function search(arr, target){
let left = 0;
let right = arr.length - 1;
while(left <= right){
// right-left算出两者之间的距离再除以2取中间值,再加上left
let mid = Math.floor((right-left)/2) + left;
if(arr[mid] > target){
right = mid - 1;
}else if(arr[mid] < target){
left = mid + 1;
}else{
return mid;
}
}
return -1;
}
let res = search([2,3,4,6,11,23], 11);
console.log(res);
排序
排序算法稳定性
排序稳定性是排序算法的重要属性,指的是排序关键字相同的项目,排序前后的顺序不变
常见的排序算法之众,插入排序,合并排序,冒泡排序等都是稳定的,堆排序,快速排序等是不稳定的
冒泡排序
比较所有相邻元素,如果第一个比第二个大,则交换,一轮下来,可以保证最后一个数是最大的
function bubble(arr, target){
let len = arr.length;
for(let i = 0; i < len; i++){
// 因为后面的数已经排好了,所以不用再进行比较了
for(let j = 0; j < len - i; j++){
if(arr[j] > arr[j + 1]){
[arr[j], arr[j+1]] = [arr[j+1], arr[j]];
}
}
}
return arr;
}
console.log(bubble([3, 11, 2, 11, 5, 23]));
快速排序O(logN)
选择一个数为准基,遍历arr,比它大的放在left,比它小的放在right,递归
function quick(arr){
if(arr.length <= 1) return arr;
let left = [],
right = [];
let pivotIndex = Math.floor(arr.length / 2);
let pivot = arr.splice(pivotIndex,1)[0];
for(let i = 0; i < arr.length; i++){
if(arr[i] > pivot){
right.push(arr[i])
}else{
left.push(arr[i])
}
}
return quick(left).concat([pivot],quick(right))
}
console.log(quick([3, 11, 2, 11, 5, 23]));
插入排序
从第二个数往前比,比他大就往后排,以此类推,进行到最后一个数
function insert(arr){
for(let i = 0; i < arr.length; i++){
const temp = arr[i];
let j = i;
while(j > 0){
if(arr[j-1] > temp){
arr[j] = arr[j-1];
}else{
break;
}
j -= 1;
}
arr[j] = temp;
}
return arr;
}
console.log(insert([3, 11, 2, 11, 5, 23]));
选择排序
找到数组中最小值,选中并将其放在第一位;然后找第二小的值放在第二位;以此类推,执行n-1轮
function check(arr){
for(let i = 0;i < arr.length;i++){
let indexMin = i;
for(let j = i; j < arr.length; j++){
if(arr[j] < arr[indexMin]){
indexMin = j;
}
}
if(indexMin !== i){
[arr[i], arr[indexMin]] = [arr[indexMin], arr[i]]
}
}
return arr;
}
归并排序
function merge(left, right){
let temp = [];
while(left.length && right.length){
if(left[0] < right[0]){
temp.push(left.shift())
} else {
temp.push(right.shift());
}
}
return temp.concat(left, right);
}
function mergeSort(arr){
const len = arr.length;
if(len < 2) return arr;
let mid = Math.floor(len / 2);
let left = arr.slice(0, mid);
let right = arr.slice(mid);
return merge(mergeSort(left), mergeSort(right))
}
堆排序
JavaScript 数据结构与算法之美 - 归并排序、快速排序、希尔排序、堆排序 - 掘金
const heapSort = arr => {
// 初始化大顶堆,从第一个非叶子结点开始
for(let i = Math.floor(arr.length / 2 - 1); i >= 0; i--){
heapify(arr,i,arr.length);
}
// 排序,每一次 for 循环找出一个当前最大值,数组长度减一
for(let i = Math.floor(arr.length - 1); i > 0;i--){
// 排序,每一次 for 循环找出一个当前最大值,数组长度减一
swap(arr,0,i);
// 从根节点开始调整,并且最后一个结点已经为当前最大值,不需要再参与比较,所以第三个参数为 i,即比较到最后一个结点前一个即可
heapify(arr,0,i);
}
return arr;
}
// 交换两个节点
const swap = (arr,i ,j)=>{
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
// 将 i 结点以下的堆整理为大顶堆,注意这一步实现的基础实际上是:
// 假设结点 i 以下的子堆已经是一个大顶堆,heapify 函数实现的
// 功能是实际上是:找到 结点 i 在包括结点 i 的堆中的正确位置。
// 后面将写一个 for 循环,从第一个非叶子结点开始,对每一个非叶子结点
// 都执行 heapify 操作,所以就满足了结点 i 以下的子堆已经是一大顶堆
const heapify = (arr,i,length)=>{
let temp = arr[i];// 当前父节点
// j < length 的目的是对结点 i 以下的结点全部做顺序调整
for(let j = 2 * i + 1; j < length; j = 2 * j + 1){
temp = arr[i];// 将 array[i] 取出,整个过程相当于找到 array[i] 应处于的位置
if(j + 1 < length && array[j] < array[j + 1]){
j++;// 找到两个孩子中较大的一个,再与父节点比较
}
if(temp < arr[j]){
swap(arr,i,j); // 如果父节点小于子节点:交换;否则跳出
i = j;// 交换后,temp 的下标变为 j
}else{
break;
}
}
}
无注释版
const heapSort = arr => {
for(let i = Math.floor(arr.length / 2 - 1); i >= 0; i--){
heapify(arr,i,arr.length);
}
for(let i = Math.floor(arr.length - 1); i > 0;i--){
swap(arr,0,i);
heapify(arr,0,i);
}
return arr;
}
const swap = (arr,i ,j)=>{
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
const heapify = (arr,i,length)=>{
let temp = arr[i];
for(let j = 2 * i + 1; j < length; j = 2 * j + 1){
temp = arr[i];
if(j + 1 < length && array[j] < array[j + 1]){
j++;
}
if(temp < arr[j]){
swap(arr,i,j);
i = j;
}else{
break;
}
}
}
二叉树
深度指的是节点到顶点的距离,求深度用前序遍历
高度指的是节点到底的距离,求高度用后序遍历
先序遍历
function front(arr){
const res = [];
const rec = n => {
if(!n) return;
res.push(n.val);
rec(n.left);
rec(n.right);
}
rec(root);
return res;
}
中序遍历
function front(arr){
const res = [];
const rec = n => {
if(!n) return;
rec(n.left);
res.push(n.val);
rec(n.right);
}
rec(root);
return res;
}
后序遍历
function back(arr){
const res = [];
const ret = n => {
if(!n) return;
rec(n.left);
rec(n.right);
res.push(n.val);
}
rec(root);
return res;
}
层序遍历
var levelOrder = function (root) {
let res = [];
let quene = [];
quene.push(root);
if(root === null) return res;
while(quene.length !== 0){
let len = quene.length;
let curLevel = [];
for(let i = 0; i < len ;i++){
let node = quene.shift();
curLevel.push(node.val);
node.left && quene.push(node.left);
node.right && quene.push(node.right);
}
res.push(curLevel);
}
return res;
}
ajax
let xhr = new XMLHttpRequest();
xhr.open('method', 'url','async');
xhr.send();
xhr.setRequestHeader('Content-Type','application/json');
xhr.onreadyStatechange = function(){
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status < 300){
// some code
}
}
}
promise封装ajax
const getJson = function (url){
return new Promise(fucntion (resolve, reject){
const handler = function (){
if(this.readyState !== 4){
return ;
}
if(this.status === 200){
resolve(this.response);
}else{
reject(new Error(this.statusText));
}
}
const client = new XHRHttpRequest();
client.open('GET', url);
client.onreadystatechange = handler;
client.responseType = 'json';
client.setRequestHeader('Accept','application/json');
client.send();
})
}
getJson("/posts.json").then(function(json) {
console.log('Contents: ' + json);
}, function(error) {
console.error('出错了', error);
});
防抖
触发事件后在n秒内函数只能触发一次,如果在n秒内又触发了时间,则会重新计算函数执行时间。单位时间内,操作n次,保留最后一次。
function debounce(fn, delay) {
let timeout = null;
return function () {
clearTimeout(timeout);
timeout = setTimeout(() => {
fn.apply(this, arguments);
}, delay)
}
}
节流
连续触发事件但是在n秒内只执行一次函数,节流会稀释函数的执行频率。单位时间内,操作n次,执行第一次
function throttle(fn, delay) {
let canrun = true;
return function () {
if(!canrun) return;
canrun = false;
setTimeout(() => {
fn.apply(this, arguments);
canrun = true;
}, delay)
}
}
new
- 在内存中创建一个新对象
- 这个新对象内部的[[prototype]]特性被赋值为构造函数的prototype属性
- 构造函数内部的this被赋值为这个新对象
- 执行构造函数的代码
- 如果构造函数返回空对象,则返回该对象,否则,返回刚创建的新对象
Function create(con, ...args){
var obj = {};
obj.__proto__ = con.prototype;
var result = con.apply(obj, args);
return result instanceof object ? result : obj;
}
var a = create(构造函数名称,需要传入的构造函数参数)
蹦床函数
可以将递归执行转为循环执行。
接受一个函数f作为参数,只要f执行后返回一个函数,就继续执行。注意,这里是返回一个函数,然后执行该函数,而不是函数里面调用函数,这样就避免了递归执行,从而消除调用栈过大的问题
function trampoline(f){
while(f && f instanceof Function){
f= f();
}
return f;
}
函数柯里化
柯里化函数应用 | Heying Ye’s Personal Website
function createCurry(fn){
if(typeof fn !== 'function'){
throw TyepError("fn is not function");
}
// 复用第一个参数
var args = [].slice.call(arguments, 1);
// 返回新函数
return funciton (){
// 收集剩余参数
var _args = [].slice.call(arguments);
// 返回结果
return fn.apply(this, args.concat(_args));
}
}
//add(19)(10, 20, 30),求该函数传递的参数和
var add = createCurry(function() {
//获取所有参数
var args = [].slice.call(arguments);
//返回累加结果
return args.reduce(function(accumulator, currentValue) {
return accumulator + currentValue
})
}, 19)
add(10, 20, 30); //79
隐式包装类
function createSymbolObject(description){
return function (){
return this
}.call(Symbol(description))
}
function createBigIntObject(description){
return function (){
return this
}.call(BigInt(description))
}
Promise
JavaScript 深入系列之 Promise 核心原理的模拟实现,通过 Promises/A+ 官方872个测试用例 · Issue #125 · yuanyuanbyte/Blog
看了就会,手写Promise原理,最通俗易懂的版本!!! - 掘金
从一道让我失眠的 Promise 面试题开始,深入分析 Promise 实现细节 - 掘金
class Promise {
constructor(exeutor){
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
let resolve = value => {
if(this.state === 'pending'){
this.state = 'fulfilled';
this.value = value;
}
}
let reject = reason => {
if(this.state === 'pending'){
this.state = 'rejected';
this.reason = reason;
}
}
try{
executor(resolve,reject);
}catch(err){
reject(err);
}
}
then(onFulfiled,onRejected){
if(this.state === 'fulfilled'){
onFulfilled(this.value);
}
if(this.state === 'rejected'){
onRejected(this.reason);
}
return this;
}
}
//promise.all
Promise.all = function(iterators){
let promises = Array.from(iterators);
let len = promises.length;
let res = new Array(len);
let resolveNum = 0;
return new Promise((resolve,reject)=>{
promises.forEach((promise,index)=>{
Promise.resolve(promise)
.then(value=>{
res[index] = value;
if(++resolveNum === len){
resolve(res);
}
})
.catch(reject);
})
})
}
// promise.race
Promise.race = function(iterators){
const promises = Array.from(iterators);
return new promise((resolve, reject) => {
promises.forEach(promise => {
Promise.resolve(promise).then(resolve).catch(reject);
})
})
}
// promise.any
Promise.any = function(iterators){
const promises = Array.from(iterators);
let len = promises.length;
let rejectedList = new Array(len);
let rejectedNum = 0;
return new Promise((resolve,reject)=>{
promises.forEach((promise,index)=>{
Promise.resolve(promise)
.then(resolve)
.catch(reason=>{
rejectedList[index] = reason;
if(++rejectedNum === len){
reject(rejectedList);
}
})
})
})
}
// promise.allSettled
const result = (success,value)=>{
success
? {status:'fulfilled',value}
: {status:'rejected',reason:value}
}
Promise.allSettled = function (iterators){
const promises = Array.from(iterators);
const len = promises.length;
const settledList = new Array(len);
let settledNum = 0;
return new promise((resolve,reject)=>{
promises.forEach((promise,index)=>{
Promise.resolve(promise)
.then(value=>{
settledList[index] = result(true,value);
if(++settledNum === len){
resolve(settledList);
}
})
.catch(reason=>{
settledList[index] = reason;
if(++settledNum === len){
reject(settledList);
}
})
})
})
}
class myPromise {
// 构造方法
constructor(executor){
// 初始化值
this.PromiseResult = null // 终值
this.PromiseState = 'pending' // 状态
this.onFulfilledCallbacks = [] // 保存成功回调
this.onRejectedCallbacks = [] // 保存失败回调
// 初始化this
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
// 执行传进来的函数
try{
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
resolve(value){
if (this.PromiseState !== 'pending') return
// 如果执行resolve,状态变为fulfilled
this.PromiseState = 'fulfilled';
// 终值为传进来的值
this.PromiseResult = value;
while (this.onFulfilledCallbacks.length) {
this.onFulfilledCallbacks.shift()(this.PromiseResult)
}
}
reject(reason){
if (this.PromiseState !== 'pending') return
// 如果执行reject,状态变为rejected
this.PromiseState = 'rejected';
// 终值为传进来的reason
this.PromiseResult = reason;
while (this.onRejectedCallbacks.length) {
this.onRejectedCallbacks.shift()(this.PromiseResult)
}
}
then(onFulfilled, onRejected){
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val;
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
let thenPromise = new myPromise((resolve, reject) => {
const resolvePromise = cb => {
setTimeout(()=>{
try {
const x = cb(this.PromiseResult);
if(x === thenPromise){
throw new Error('不能返回自身。。。')
}
if (x instanceof myPromise) {
x.then(resolve, reject)
} else {
// 非Promise就直接成功
resolve(x)
}
} catch (err) {
// 处理报错
reject(err)
throw new Error(err)
}
}
})
if(this.PromiseState === 'fulfilled'){
resolvePromise(onFulfilled);
}else if(this.PromiseState === 'rejected'){
resolvePromise(onRejected);
}else if(this.PromiseState === 'pending'){
// 如果状态为待定状态,暂时保存两个回调
this.onFulfilledCallbacks.push(resolvePromise.bind(this, onFulfilled));
this.onRejectedCallbacks.push(resolvePromise.bind(this, onRejected));
}
}
})
}
static all(promises) {
const result = [];
let count = 0;
return new myPromise((resolve, reject) => {
const addData = (index, value) => {
result[index] = value;
count++;
if(count === promises.length) resolve(result);
}
promises.forEach((promise, index) => {
if(promise instanceof myPromise){
promise.then(res => {
addData(index, res);
},err => reject(err))
}else{
addData(index, promise);
}
})
})
}
static race(promises){
return new myPromise((resolve, reject) => {
promises.forEach(promise => {
if(promise instanceof myPromise){
promise.then(res => {
resolve(res);
},err => {
reject(err);
})
}else{
resolve(promise)
}
})
})
}
static allSettled(promises){
return new myPromise((resolve, reject) => {
const res = [];
let count = 0;
const addData = (status, value, i) => {
res[i] = {
status,
value,
}
count++;
if(count === promises.length){
resolve(res);
}
}
promises.forEach((promise, i) => {
if(promise instanceof myPromise){
promise.then(res => {
addData('fulfilled', res, i);
},err => {
addData('rejected', err, i);
})
} else {
addData('fulfilled', promise, i);
}
})
})
}
static any(promises){
return new Promise((resolve, reject) => {
let count = 0;
promise.forEach(promise => {
promise.then(val => {
resolve(val);
},err => {
count++;
if(count === promises.length){
reject(new AggregateError('All promises were rejected'))
}
})
})
})
}
}
class myPromise {
static PENDING = 'pending';
static FULFILLED = 'fulfilled';
static REJECTED = 'rejected';
constructor(func){
this.PromiseState = myPromise.PENDING;
this.PromiseResult = null;
this.onFulfilledCallbacks = [];
this.onRejectedCakkbacks = [];
try {
func(this.resolve.bind(this), this.reject.bind(this));
} catch {
this.reject(error);
}
}
resolve(result){
if(this.PromiseState === myPromise.PENDING){
this.PromiseState = myPromise.FULFILLED;
this.PromiseResult = result;
onFulfilledCallbacks.forEach( callback => {
callback(result);
})
}
}
reject(reason){
if(this.PromiseState === myPromise.PENDING){
this.PromiseState = myPromise.REJECTED;
this.PromiseReason = reason;
onRejectedCallbacks.forEach( callback => {
callback(reason);
})
}
}
then(onFulfilled, onRejected){
let promise2 = new myPromise((resolve, reject) => {
if(this.PromiseState === myPromise.FULFILLED){
setTimeout(() => {
try {
if(typeof onFulfilled !== 'function'){
resolve(this.PromiseResult);
} else {
let x = onFulfilled(this.PromiseResult);
resolvePromise(promise2, x, resolve, reject);
}
} catch (e){
reject(e);
}
})
} else if (this.PromiseState === myPromise.REJECTED){
setTimeout(() => {
try {
if(typeof onRejected !== 'function'){
reject(this.PromiseResult);
} else {
let x = onRejected(this.PromiseResult);
resolvePromise(promise2, x, resolve, reject);
}
} catch (e){
reject(e);
}
})
} else if (this.PromiseState === myPromise.PENDING){
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
if(typeof onFulfilled !== 'function'){
resolve(this.PromiseResult);
} else {
let x = onFulfilled(this.PromiseResult);
resolvePromise(promise2, x, resolve, reject);
}
} catch (e){
reject(e);
}
})
})
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
if(typeof onRejected !== 'function'){
reject(this.PromiseResult);
} else {
let x = onRejected(this.PromiseResult);
resolvePromise(promise2, x, resolve, reject);
}
} catch (e){
reject(e);
}
})
})
}
})
return promise2
}
catch(onRejected){
return this.then(undefined, onRejected);
}
finally(callBack){
return this.then(callBack, callBack);
}
static resolve(value){
// 如果是一个promise则返回这个promise
if(value instanceof myPromise){
return value;
}else if(value instanceof Object && 'then' in value){
// 如果是一个具有then方法的对象则返回的promise会跟随这个thenable的对象
// 采用它的最终状态
return new myPromise((resolve, reject) => {
value.then(resolve, reject);
})
}
// 否则返回的promise值将以此值完成,即以辞职执行resolve()方法,状态为fulfilled;
return new myPromise(resolve => {
resolve(value);
})
}
static reject(reason){
return new myPromise((resolve, reject) => {
reject(reason);
})
}
static all(promises){
return new myPromise((resolve, reject) => {
if(Array.isArray(promises)){
let result = [];
let count = 0;
if(!promises.length){
return resolve(promises);
}
promises.forEach((promise, index) => {
myPromise.resolve(item).then(
value => {
count++;
result[index] = value;
count === promises.length && resolve(result);
},
reason => {
reject(reason);
}
)
})
} else {
return reject(new TypeError('Argument is not iterable'))
}
})
}
static allSettled(promises){
return new myPromise((resolve, reject) => {
if(Array.isArray(promises)){
let result = [];
let count = 0;
if(!promises.length) return resolve(promises);
promises.forEach((item, index) => {
myPromise.resolve(item).then(
value => {
count++;
result[index] = {
status: 'fulfilled',
value
};
count === promises.length && resolve(result);
},
reason => {
count++;
result[index] = {
status: 'rejected',
reason
};
count === promises.length && resolve(result);
}
)
})
} else {
return reject(new TypeError('Argument is not iterable'));
}
})
}
static any(promises){
if(Array.isArray(promises)){
let result = [];
let count = 0;
if(!promises.length) return reject(new AggregateError('All promises were rejected'))
promises.forEach(promise => {
myPromise.resolve(promise).then(
value => {
resolve(value);
},
reason => {
count++;
errors.push(reason);
count === promises.length && reject(new AggregrateError(errors));
}
)
})
} else {
return reject(new TypeError('Argument is not iterable'))
}
}
static race(promises){
return new myPromise((resolve, reject) => {
if(Array.isArray(promises)){
if(promises.length > 0){
promises.forEach(promise => {
myPromise.resolve(promise).then(resolve, reject);
})
}
} else {
return reject(new TypeError('Argument is not iterable'))
}
})
}
}
function resolvePromise(promise2, x, resolve, reject){
if(x === promise2){
throw new TypeError('Chaining cycle detected for promise');
}
if(x instanceof myPromise){
x.then(y => {
resolvePromise(promise2, y, resolve, reject);
}, reject);
} else if (x !== null && ((typeof x === 'object' || (typeof x === 'function')))){
try {
var then = x.then;
} catch (e) {
return reject(e);
}
if(typeof then === 'function'){
let called = false;
try {
then.call(
x,
y => {
if(called) return;
called = true;
reject(r);
}
)
} catch(e){
if(called) return;
called = true;
reject(e);
}
}else{
resolve(x)
}
} else {
return resolve(x);
}
}
树转数组
function treeToArr(nodes, pid = null){
const result = [];
for (let node of nodes) {
const curNode = {
id: node.id,
name: node.name,
pid
};
result.push(curNode)
if (node.children && node.children.length > 0) {
const childResult = treeToArr(node.children, node.id);
reult.push(...childrenResult);
}
}
return result;
}
const arr = [
{
id: 0,
name: '0',
children: [
{
id: 1,
name: '1',
children: [
{
id: 11,
name: '11'
}
]
}
]
}
];
数组转树
function arrToTree(arr){
return arr.reduce((prev, cur) => {
cur.children = arr.filter(v => v.parentId === cur.id);
if(!cur.parentId){
prev.push(cur);
}
return prev;
}, []);
}
const arr = [
{
id: 2,
name: '部门B',
parentId: 0
},
{
id: 3,
name: '部门C',
parentId: 1
},
{
id: 1,
name: '部门A',
parentId: 2
},
]
数组拍平
- 使用flat()拍平数组:该方法可传入一个数字作为拍平的层数,默认为1,设置为infinity后可实现全部拍平
- 使用正则表达式
// 转为字符串后拼接为数组样式最后将其转换为数组对象
Json.parse(‘[’+ json.stringify(arr).replace(/[|]/g ,‘ ’) + ‘]’)
- 使用reduce
let flat = arr => {
arr.reduce((pre, cur) => {
return pre.concat(Array.isArray(cur) ? flat(cur) : cur)
})
}
- 使用递归
const res = [];
const fns = arr => {
for(let i = 0; i < arr.length; i++){
if(Array.isArray(arr[i])){
fns(arr[i])
}else{
res.push(arr[i])
}
}
}
数组去重
- 原生js
Array.prototype.unique = function (arr){
let temp = {};
let res = [];
for(let i = 0;i < arr.length; i++){
if(!temp[this[i]]){
temp[this[i]] = 'abc';
res.push(this[i])
}
}
return arr;
}
- indexOf——返回某个指定的字符串值在字符串中首次出现的位置
function unique(arr){
if(!Array.isArray(arr)){
console.log('error');
return;
}
let res = [];
for(let i = 0;i < arr.length; i++){
if(res.indexOf(arr[i]) !== -1){
return;
}else{
res.push(arr[i])
}
}
return res;
}
- sort()先将数组进行排序,然后判断当前元素与前一个元素是否相同,相同说明重复,不相同就添加进res
function unique(array){
array = array.sort();
let res = [array[0]]
for(let i = 1;i<len;i++){
if(array[i] !== array[i-1]){
res.push(array[i]);
}
}
return res;
}
- 利用splice
function unique(arr){
let len = arr.length;
for(let i = 0; i < len; i++){
for(let j = i + 1; j < len; j++){
if(arr[i] === arr[j]){
arr.splice(j, l);
j--;
}
}
return arr;
}
}
- filter
function unique(arr){
return arr.filter(function (item, index, arr){
return arr.indexOf(item, 0) === index;
})
}
- 利用set
function unique(arr){
return Array.from(new Set(arr))
}
- map
function unique(arr){
const seen = new Map();
return arr.filter(a => !seen.has(a) && seen.set(a, 1))
}
图片懒加载
// 等所有的资源文件加载完毕之后再绑定事件
window.onload = function (){
// 获取图片列表,即img标签列表
let imgs = ducument.querySelectorAll('img');
function lazyLoad(imgs){
// 可视区域高度
let innerHeight = window.innerHeight;
// 滚动区域高度
let scrollTop = ducument.documentElement.scrollTop || document.body.scrollTop;
for(let i = 0;i < imgs.length; i++){
// 图片距离顶部的距离大于可视区域和滚动区域之和时懒加载
if((innerHeight + scrollTop) > imgs[i].offsetTop){
// 不加立即执行函数i会等于9
(function(i){
// 真实情况是页面开始有2秒空白,所以使用setTimeout定时2s
setTimeout(function (){
//创建一个临时图片,这个图片在内存中不会到页面上去。实现隐形加载
let temp = new Image();
//只会请求一次
temp.src = imgs[i].getAttribute('data-src');
temp.onload = function (){
// 获取自定义属性data-src,用真图片替换假图片
imgs[i].src = imgs[i].getAttribute('data-src');
}
},2000)
})(i)
}
}
}
lazyLoad(imgs);
window.onscroll = function(){
lazyLoad(imgs)
}
}
深浅克隆
深克隆
function deepClone(target, cache = new Map()){
if(cache.get(target)){
return cache.get(target);
}
if(target instanceof Object){
let dist;
if(target instanceof Array){
dist = [];
}else if(target instanceof Function){
dist = function (){
return target.call(this, ...arguments);
}
}else if(target instanceof RegExp){
dist = new RegExp(target.source, target.flags);
}else if(target instanceof Date){
dist = new Date(target);
}else{
dist = {};
}
cache.set(target, dist);
for(let key in target){
if (target.hasOwnProperty(key)) {
dist[key] = deepClone(target[key], cache);
}
}
return dist;
}else{
return target;
}
}
浅克隆
function clone(origin, target = null){
for(let prop in origin){
target[prop] = origin[prop];
}
retun target;
}
实现useHover hook
import React, { useState, useEffect } from 'react';
import ReactDom from 'react-dom';
const Tpp = () => {
const isHovered = useHover();
function useHover() {
const [isHovered, setIsHovered] = useState(false);
const handleMouseEnter = () => {
setIsHovered(true);
};
const handleMouseLeave = () => {
setIsHovered(false);
};
useEffect(() => {
// 获取元素的引用
const element = document.querySelector('.hover-element');
// 添加事件监听器
element.addEventListener('mouseenter', handleMouseEnter);
element.addEventListener('mouseleave', handleMouseLeave);
// 在组件卸载时清除事件监听器
return () => {
element.removeEventListener('mouseenter', handleMouseEnter);
element.removeEventListener('mouseleave', handleMouseLeave);
};
}, []);
return isHovered;
}
return (
<div>
<span className="hover-element">{ isHovered ? '鼠标悬停:是' : '鼠标悬停:否' } </span>
</div>
);
}
ReactDom.render(<Tpp />, document.getElementById('app'));
大数相加
function addBigNumbers(num1, num2) {
let len1 = num1.length;
let len2 = num2.length;
// 将两个大数转换为数组,并反转数组顺序方便从低位到高位相加
let arr1 = num1.split('').reverse();
let arr2 = num2.split('').reverse();
// 计算结果的数组
let result = [];
// 取两个大数中较长的长度作为循环次数
let maxLen = Math.max(len1, len2);
// 进位
let carry = 0;
for (let i = 0; i < maxLen; i++) {
let digit1 = i < len1 ? parseInt(arr1[i]) : 0;
let digit2 = i < len2 ? parseInt(arr2[i]) : 0;
let sum = digit1 + digit2 + carry;
// 计算当前位的数值和进位
let digit = sum % 10;
carry = Math.floor(sum / 10);
// 将当前位的数值插入结果数组
result.push(digit);
}
// 处理最高位的进位
if (carry > 0) {
result.push(carry);
}
// 反转结果数组,并转换为字符串
result = result.reverse().join('');
return result;
}
// 示例用法
let num1 = '123456789012345678901234567890';
let num2 = '987654321098765432109876543210';
let sum = addBigNumbers(num1, num2);
console.log(sum);