JavaScript 手写题

news2024/11/20 12:24:59

基础手写

全排列(力扣原题)

要求以数组的形式返回字符串参数的所有排列组合。

注意:

  1. 字符串参数中的字符无重复且仅包含小写字母
    
  2. 返回的排列组合数组不区分顺序
    
const _permute = string => {
  const result = []
  const map = new Map()
  const dfs = (path) => {
    if (path.length === string.length) {
      result.push(path)
      return
    }
    for (let i = 0; i < string.length; i++) {
      if (map.get(string[i])) continue
      map.set(string[i], true)
      path += string[i]
      dfs(path)
      path = path.substring(0, path.length - 1)
      map.set(string[i], false)
    }
  }
  dfs('')
  return result
}
console.log(_permute('abc')) // [ 'abc', 'acb', 'bac', 'bca', 'cab', 'cba' ]
复制代码

instanceof

  • 如果 target 为基本数据类型直接返回 false

  • 判断 Fn.prototype 是否在 target 的隐式原型链上

const _instanceof = (target, Fn) => {
  if ((typeof target !== 'object' && typeof target !== 'function') || target === null)
  return false
  
  let proto = target.__proto__
  while (true) {
    if (proto === null) return false
    if (proto === Fn.prototype) return true
    proto = proto.__proto__
  }
}
function A() {}
const a = new A()
console.log(_instanceof(a, A)) // true
console.log(_instanceof(1, A)) // false
复制代码

Array.prototype.map

  • map 中的 exc 接受三个参数,分别是: 元素值、元素下标和原数组

  • map 返回的是一个新的数组,地址不一样

// 这里不能直接使用箭头函数,否则无法访问到 this
Array.prototype._map = function (exc) {
  const result = []
  this.forEach((item, index, arr) => {
    result[index] = exc(item, index, arr)
  })
  return result
}
const a = new Array(2).fill(2)
console.log(a.map((item, index, arr) => item * index + 1)) // [1,3]
console.log(a._map((item, index, arr) => item * index + 1))// [1,3]
复制代码

Array.prototype.filter

  • filter 中的 exc 接受三个参数,与map一致,主要实现的是数组的过滤功能,会根据 exc 函数的返回值来判断是否“留下”该值。

  • filter 返回的是一个新的数组,地址不一致。

Array.prototype._filter = function (exc) {
  const result = []
  this.forEach((item, index, arr) => {
    if (exc(item, index, arr)) {
      result.push(item)
    }
  })
  return result
}
const b = [1, 3, 4, 5, 6, 2, 5, 1, 8, 20]

console.log(b._filter(item => item % 2 === 0)) // [ 4, 6, 2, 8, 20 ]
复制代码

Array.prototype.reduce

  • reduce 接受两个参数,第一个为 exc 函数,第二个为初始值,如果不传默认为 0

  • reduce 最终会返回一个值,当然不一定是 Number 类型的,取决于你是怎么计算的,每次的计算结果都会作为下次 exc 中的第一个参数

Array.prototype._reduce = function (exc, initial = 0) {
  let result = initial
  this.forEach((item) => {
    result = exc(result, item)
  })
  return result
}
console.log(b.reduce((pre, cur) => pre + cur, 0)) // 55
console.log(b._reduce((pre, cur) => pre + cur, 0)) // 55
复制代码

Object.create

MDN[1] Object.create() 方法用于创建一个新对象,使用现有的对象来作为新创建对象的原型(prototype)。

Object.prototype._create = function (proto) {
  const Fn = function () { }
  Fn.prototype = proto
  return new Fn()
}
function A() { }
const obj = Object.create(A)
const obj2 = Object._create(A)
console.log(obj.__proto__ === A) // true
console.log(obj.__proto__ === A) // true
复制代码

Function.prototype.call

call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。

Function.prototype._call = function (ctx, ...args) {
  // 如果不为空,则需要进行对象包装
  const o = ctx == undefined ? window : Object(ctx)
  // 给 ctx 添加独一无二的属性
  const key = Symbol()
  o[key] = this
  // 执行函数,得到返回结果
  const result = o[key](...args)
  // 删除该属性
  delete o[key]
  return result
}

const obj = {
  name: '11',
  fun() {
    console.log(this.name)
  }
}

const obj2 = { name: '22' }
obj.fun() // 11
obj.fun.call(obj2) // 22
obj.fun._call(obj2) // 22
复制代码

Function.prototype.bind

bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

const obj = {
  name: '11',
  fun() {
    console.log(this.name)
  }
}
Function.prototype._bind = function (ctx, ...args) {
  // 获取函数体
  const _self = this
  // 用一个新函数包裹,避免立即执行
  const bindFn = (...reset) => {
    return _self.call(ctx, ...args, ...reset)
  }
  return bindFn
}
const obj2 = { name: '22' }
obj.fun() // 11
const fn = obj.fun.bind(obj2)
const fn2 = obj.fun._bind(obj2)
fn() // 22
fn2() // 22
复制代码

New 关键字

new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。

const _new = function(constructor) {
  // 创建一个空对象
  const obj = {}
  // 原型链挂载
  obj.__proto__ = constructor.prototype;
  // 将obj 复制给构造体中的 this,并且返回结果
  const result = constructor.call(obj)
  // 如果返回对象不为一个对象则直接返回刚才创建的对象
  return typeof result === 'object' && result !== null ? : result : obj
}
复制代码

浅拷贝

const _shallowClone = target => {
  // 基本数据类型直接返回
  if (typeof target === 'object' && target !== null) {
    // 获取target 的构造体
    const constructor = target.constructor
    // 如果构造体为以下几种类型直接返回
    if (/^(Function|RegExp|Date|Map|Set)$/i.test(constructor.name)) return target
    // 判断是否是一个数组
    const cloneTarget = Array.isArray(target) ? [] : {}
    for (prop in target) {
      // 只拷贝其自身的属性
      if (target.hasOwnProperty(prop)) {
        cloneTarget[prop] = target[prop]
      }
    }
    return cloneTarget
  } else {
    return target
  }
}
复制代码

深拷贝

实现思路和浅拷贝一致,只不过需要注意几点

  1. 函数 正则 日期 ES6新对象 等不是直接返回其地址,而是重新创建
    
  2. 需要避免出现循环引用的情况
    
const _completeDeepClone = (target, map = new WeakMap()) => {
  // 基本数据类型,直接返回
  if (typeof target !== 'object' || target === null) return target
  // 函数 正则 日期 ES6新对象,执行构造题,返回新的对象
  const constructor = target.constructor
  if (/^(Function|RegExp|Date|Map|Set)$/i.test(constructor.name)) return new constructor(target)
  // map标记每一个出现过的属性,避免循环引用
  if (map.get(target)) return map.get(target)
  map.set(target, true)
  const cloneTarget = Array.isArray(target) ? [] : {}
  for (prop in target) {
    if (target.hasOwnProperty(prop)) {
      cloneTarget[prop] = _completeDeepClone(target[prop], map)
    }
  }
  return cloneTarget
}
复制代码

寄生组合式继承

一图胜千言

 

 

function Parent(name) {
  this.name = name
}
Parent.prototype.getName = function () {
  return this.name
}

function Son(name, age) {
  // 这里其实就等于 this.name = name
  Parent.call(this, name)
  this.age = age
}

Son.prototype.getAge = function () {
  return this.age
}
Son.prototype.__proto__ = Object.create(Parent.prototype)

const son1 = new Son('shao', 20)

console.log(son1.getName()) // shao
console.log(son1.getAge()) // 20
复制代码

发布订阅者模式

class EventEmitter {
  constructor() {
    // key: 事件名
    // value: callback [] 回调数组
    this.events = {}
  }
  on(name, callback) {
    if (this.events[name]) {
      this.events[name].push(callback)
    } else {
      this.events[name] = [callback]
    }
  }
  off(name, callback) {
    if (!this.message[name]) return;
    if (!callback) {
      // 如果没有callback,就删掉整个事件
      this.message[name] = undefined;
    }
    this.message[name] = this.message[name].filter((item) => item !== callback);

  }
  emit(name, ...args) {
    if (!this.events[name]) return
    this.events[name].forEach(cb => cb(...args))
  }
}
复制代码

观察者模式

class Observerd {
  constructor() {
    // 我要看看到底有多少人在观察俺
    this.observerList = []
  }
  addObserver(observer) {
    // 添加一个观察俺的人
    this.observerList.push(observer)
  }
  notify() {
    // 我要闹点动静,所有观察者都会知道这个信息,具体怎么做就是他们自己的事情了
    this.observerList.forEach(observer => observer.update())
  }
}


class Observer {
  constructor(doSome) {
    // 观察到小白鼠有动静之后,观察者做的事情
    this.doSome = doSome
  }
  update() {
    console.log(this.doSome)
  }
}

const ob1 = new Observer('我是ob1,我观察到小白鼠有反应了,太饿了,我得去吃个饭了')
const ob2 = new Observer('我是ob2,我观察到小白鼠有反应了,我要继续工作!')
const xiaoBaiShu = new Observerd()
xiaoBaiShu.addObserver(ob1)
xiaoBaiShu.addObserver(ob2)
xiaoBaiShu.notify() // .... .... 
复制代码

多说一句:怎么理解发布订阅者和观察者的区别呢 ?

其实发布订阅者模式只有一个中间者,好像啥事情都需要它亲自来做。而且仔细观察的话,发布订阅者模式会存在一个事件名和事件的对应关系,今天可以发布天气预报,只有订阅了天气预报的才会被通知,订阅了 KFC疯狂星期四闹钟事件 的不会被提醒。

而观察者模式,等被观察者发出了一点动静(执行notify),所有观察者都会被通知。

节流

节流函数(throttle)就是让事件处理函数(handler)在大于等于执行周期时才能执行,周期之内不执行,即事件一直被触发,那么事件将会按每小段固定时间一次的频率执行。

function throttle(fn, delay = 300) {
  // 这里始终记得字节二面的时候,建议我不写 flag 好家伙
  let isThrottling = false
  // 核心思路,函数多次执行只有当 isThrottling 为 false 时才会进入函数体
  return function (...args) {
    if (!isThrottling) {
      isThrottling = true
      setTimeout(() => {
        isThrottling = false
        fn.apply(this, args)
      }, delay)
    }
  }
}
复制代码

防抖

事件响应函数在一段时间后才执行,如果这段时间内再次调用,则重新计算执行时间

function debounce(fn, delay = 300) {
  let timer = null
  return function (...args) {
    // 每次进来都会清空定时器,所以在 delay 事件中重复执行之后执行最后一次
    clearInterval(timer)
    timer = setTimeout(() => {
      fn.apply(this, args)
    }, delay)
  }
}
复制代码

once 函数

函数返回结果会被缓存下来,只会计算一次。

const f = (x) => x;
const onceF = once(f);
//=> 3
onceF(3);
//=> 3
onceF(4);
复制代码
const once = (fn) => {
  let res, isFirst = true
  return function (...args) {
    if (!isFirst) return res
    res = fn.call(this, ...args)
    isFirst = false
    return res
  }
}
复制代码

累加函数应用

实现一个累加函数,下面的几种情况都能正确的调用。

console.log(sum(1, 2)(3)()) // 6
console.log(sum(1)(2)(3)()) // 6
console.log(sum(1, 2, 4)(4)()) // 11
复制代码
function sum(...args) {
  let params = args
  const _sum = (...newArgs) => {
    if (newArgs.length === 0) {
      return params.reduce((pre, cur) => pre + cur, 0)
    } else {
      params = [...params, ...newArgs]
      return _sum
    }
  }
  return _sum
}
复制代码

进阶

实现 repeat 方法

function repeat(fn, times, delay) {
  return async function (...args) {
    for (let i = 0; i < times; i++) {
      await new Promise((resolve, reject) => {
        setTimeout(() => {
          fn.call(this, ...args)
          resolve()
        }, delay)
      })
    }
  }
}
const repeatFn = repeat(console.log, 4, 1000)
// 函数调用四次,每次间隔 1s 打印 hello
repeatFn('hello')
复制代码

实现 Promise.all/race/allSettled/any

  • Promise 身上的这些方法返回的都是一个 Promise

  • Promise.resolve 接受一个 Promise,若非 promise 则将其变成功状态的 Promise

 

// 有一个失败则返回失败的结果,全部成功返回全成功的数组
Promise.all = function (promiseList = []) {
  return new Promise((resolve, reject) => {
    const result = []
    let count = 0
    if (promiseList.length === 0) {
      resolve(result)
      return
    }
    for (let i = 0; i < promiseList.length; i++) {
      Promise.resolve(promiseList[i]).then(res => {
        result[i] = res
        count++
        // 不能直接通过 result.length 进行比较,因为 会存在下标大的先赋值
        // 例如 i = 3 第一个返回结果,此时数组变为[empty,empty,empty,res]
        if (count === promiseList.length) {
          resolve(result)
        }
      }).catch(e => {
        reject(e)
      })
    }
  })
}
// 返回第一个成功或失败的结果
Promise.race = function (promiseList = []) {
  return new Promise((resolve, reject) => {
    if (promiseList.length === 0) {
      return resolve([])
    }
    for (let i = 0; i < promiseList.length; i++) {
      Promise.resolve(promiseList[i]).then(res => {
        resolve(res)
      }).catch(e => {
        reject(e)
      })
    }
  })
}
// 无论成功约否都返回,但是会添加一个 status 字段用于标记成功/失败
Promise.allSettled = function (promiseList = []) {
  return new Promise((resolve, reject) => {
    const result = []
    let count = 0

    const addRes = (i, data) => {
      result[i] = data
      count++
      if (count === promiseList.length) {
        resolve(result)
      }
    }
    
    if (promiseList.length === 0) return resolve(result)
    for (let i = 0; i < promiseList.length; i++) {
      Promise.resolve(promiseList[i]).then(res => {
        addRes(i, { status: 'fulfilled', data: res })
      }).catch(e => {
        addRes(i, { status: 'rejected', data: e })
      })
    }
  })
}
// AggregateError,当多个错误需要包装在一个错误中时,该对象表示一个错误。
// 和 Promise.all 相反,全部失败返回失败的结果数组,有一个成功则返回成功结果
Promise.any = function (promiseList = []) {
  return new Promise((resolve, reject) => {
    if (promiseList.length === 0) return resolve([])
    let count = 0
    const result = []
    for (let i = 0; i < promiseList.length; i++) {
      Promise.resolve(promiseList[i]).then(res => {
        resolve(res)
      }).catch(e => {
        count++
        result[i] = e
        if (count === promiseList.length) {
          reject(new AggregateError(result))
        }
      })
    }
  })
}
复制代码

整数千分位加逗号

1234567 -> 1,234,567
复制代码
function toThousands(num) {
  num = num.toString()
  let result = ''
  while (num.length > 3) {
    result = ',' + num.substring(num.length - 3) + result
    num = num.substring(0, num.length - 3)
  }
  result = num + result
  return result
}
console.log(toThousands(1234567)) // 1,234,567
console.log(toThousands(123456)) // 123,456
复制代码

洗牌函数

有几张牌张牌,用 js 来进行乱序排列,要保持公平性

const shuffle = (arr) => {
  // 不影响原来的数组
  const result = [...arr]
  for (let i = result.length; i > 0; i--) {
    // 随机从 [0,i - 1] 产生一个 index, 将 i - 1 于 index 对应数组的值进行交换
    const index = Math.floor(Math.random() * i);
    [result[index], result[i - 1]] = [result[i - 1], result[index]]
  }
  return result
}
const arr = [1, 2, 3, 4, 5]
console.log(shuffle(arr)) // [ 3, 1, 2, 5, 4 ]
console.log(shuffle(arr)) // [ 2, 3, 5, 1, 4 ]
console.log(shuffle(arr)) // [ 4, 2, 3, 1, 5 ]
console.log(shuffle(arr)) // [ 5, 4, 2, 3, 1 ]
复制代码

手写LRU

LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法[2],选择最近最久未使用的页面予以淘汰。该算法赋予每个页面[3]一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 t,当须淘汰一个页面时,选择现有页面中其 t 值最大的,即最近最少使用的页面予以淘汰。

/**
 * @param {number} capacity
 */
var LRUCache = function(capacity) {
    this.map = new Map()
    this.capacity = capacity
};

/** 
 * @param {number} key
 * @return {number}
 */
LRUCache.prototype.get = function(key) {
    if(this.map.has(key)){
        const value = this.map.get(key)
        // 更新存储位置
        this.map.delete(key)
        this.map.set(key,value)
        return value
    }
    return - 1
};

/** 
 * @param {number} key 
 * @param {number} value
 * @return {void}
 */
LRUCache.prototype.put = function(key, value) {
    if(this.map.has(key)){
        this.map.delete(key)
    }
    this.map.set(key,value)
    // 如果此时超过了最长可存储范围
    if(this.map.size > this.capacity){
        // 删除 map 中最久未使用的元素
        this.map.delete(this.map.keys().next().value)
    }
};
复制代码

更上一层楼

Generator

先看看下面输出的内容

async function getResult() {
    await new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(1);
            console.log(1);
        }, 1000);
    })
    await new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(2);
            console.log(2);
        }, 500);
    })
    await new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(3);
            console.log(3);
        }, 100);
    })

}
getResult()
// 1 2 3 
复制代码

那如何使用 Es6 中的 generator 实现类似的效果呢 ?

function* getResult(params) {
    yield new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(1);
            console.log(1);
        }, 1000);
    })
    yield new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(2);
            console.log(2);
        }, 500);
    })
    yield new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(3);
            console.log(3);
        }, 100);
    })
}
const gen = getResult()
// gen.next().value 就是每一次 yield 之后返回的 Promise
// gen.next() = {value: yeild 返回的数据,done: 迭代器是否走完}
gen.next().value.then(() => {
    gen.next().value.then(() => {
        gen.next();
    });
});// 依次打印 1 2 3
复制代码

将 gen.next() 封装一层,让其自己能够实现递归调用

const gen = getResult()
function co(g) {
  const nextObj = g.next();
  // 递归停止条件:当迭代器迭代到最后一个 yeild 
  if (nextObj.done) {
    return;
  }
  nextObj.value.then(()=>{
    co(g)
  })
}
co(gen)
复制代码

async-pool

 

 

aysnc-pool 的基本使用

const timeout = i => new Promise(resolve => setTimeout(() => resolve(i), i));
await asyncPool(2, [1000, 5000, 3000, 2000], timeout);
复制代码

asyncPool 这个函数接受三个参数

  • poolLimit(数字类型):表示限制的并发数;

  • array(数组类型):表示任务数组;

  • iteratorFn(函数类型):表示迭代函数,用于实现对每个任务项进行处理,该函数会返回一个 Promise 对象或异步函数。

这里提醒一下,promise.then 中的函数执行是一异步的,而赋值是同步的

const a = Promise.resolve().then(()=>console.log(a))
// 等价于 此时 a 等于一个 pending 状态的 promise
const a = Promise.resolve().then()
a.then(()=>{
  console.log(a)
})
复制代码

手写实现,这部分可能会多花点时间。可以拷贝代码多调试几次就知道了

async function asyncPool(poolLimit, array, iteratorFn) {
  const ret = []; // 存储所有的异步任务
  const executing = []; // 存储正在执行的异步任务
  for (const item of array) {
    // 调用iteratorFn函数创建异步任务
    const p = Promise.resolve().then(() => iteratorFn(item, array));
    ret.push(p); // 保存新的异步任务

    // 当poolLimit值小于或等于总任务个数时,进行并发控制
    if (poolLimit <= array.length) {
      // 当任务完成后,从正在执行的任务数组中移除已完成的任务
      const e = p.then(() => executing.splice(executing.indexOf(e), 1));
      executing.push(e); // 保存正在执行的异步任务
      if (executing.length >= poolLimit) {
        await Promise.race(executing); // 等待较快的任务执行完成
      }
    }
  }
  return Promise.all(ret);
}

const timeout = i => new Promise(resolve => setTimeout(() => { console.log(i); resolve(i) }, i));
// 当然,limit <= 0 的时候 我们可以理解为只允许一个请求存在 
asyncPool(2, [1000, 5000, 3000, 2000], timeout).then(res => {
  console.log(res)
})
复制代码

总共花费 6 s 时间,符合预期

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/955271.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue使用打印组件print-js

项目场景&#xff1a; 由于甲方要求&#xff0c;项目需要打印二维码标签&#xff0c;故开发此功能 开发流程 安装包&#xff1a;npm install print-js --saveprint-js的使用 <template><div id"print" ref"print" ><p>打印内容<p&…

可拖拽编辑的流程图X6

先上图 //index.html&#xff0c;有时候可能加载失败&#xff0c;那就再找一个别的cdn 或者npm下载&#xff0c;如果npm下载&#xff0c; //那么需要全局引入或者局部引入&#xff0c;代码里面写法也会不同&#xff0c;详细的可以看示例<script src"https://cdn.jsdeli…

python可视化——pycharm——Grid - Grid_overlap_multi_xy_axis图

这段代码使用了pyecharts库来创建一个Grid-Overlap图&#xff0c;包括柱状图和折线图。 首先&#xff0c;创建了一个柱状图对象bar&#xff0c;并添加了两个y轴的数据。第一个y轴代表csdn博客数量&#xff0c;第二个y轴代表粉丝数量。然后&#xff0c;使用extend_axis方法扩展…

6、深入解析Kotlin类与对象:构造、伴生、单例全面剖析

前言 本篇文章将带您了解Kotlin编程中的重要概念&#xff1a;类及构造函数、访问修饰符、伴生对象和单例模式。就像搭积木一样&#xff0c;我们会逐步揭开这些概念的面纱&#xff0c;让您轻松理解它们的作用和用法。无论您是编程新手还是有经验的开发者&#xff0c;本文都将为…

一个独立的测试人如何完成一个项目的测试 + 发布

其实啊&#xff0c;每个人都可以「独立完成一个项目的测试 发布」 很多同学&#xff0c;工作了五六年&#xff0c;都没有机会&#xff08;也许是&#xff1a;不敢&#xff09;独立负责一个完整项目的测试&#xff08;独立负责一个项目测试后的上线流程&#xff0c;机会就更少…

手把手教你调用5个公共API获取数字货币市场数据(内附详细源码)

数量技术宅团队在CSDN学院推出了量化投资系列课程 欢迎有兴趣系统学习量化投资的同学&#xff0c;点击下方链接报名&#xff1a; 量化投资速成营&#xff08;入门课程&#xff09; Python股票量化投资 Python期货量化投资 Python数字货币量化投资 C语言CTP期货交易系统开…

three.js(十):线性几何体

线性几何体 WireframeGeometry 网格几何体EdgesGeometry 边缘几何体 WireframeGeometry 网格几何体 WireframeGeometry( geometry : BufferGeometry ) geometry — 任意几何体对象。 const geometry new SphereGeometry(); const wireframe new WireframeGeometry(geometr…

2022年06月 C/C++(五级)真题解析#中国电子学会#全国青少年软件编程等级考试

第1题&#xff1a;逃离迷宫 你在一个地下迷宫中找到了宝藏&#xff0c;但是也触发了迷宫机关&#xff0c;导致迷宫将在T分钟后坍塌&#xff0c;为此你需要在T分钟内逃离迷宫&#xff0c;你想知道你能不能逃离迷宫。迷宫是一个边长为m的正方形&#xff0c;其中"S"表示…

完善会计流程的关键功能:了解必备的会计软件功能!

会计软件已经成为许多大小企业的财务管理标配。会计软件可以帮助企业自动化财务流程&#xff0c;提高工作效率&#xff0c;减少错误&#xff0c;并提供准确和可靠的财务数据。一款合格的会计软件应该具备什么功能呢&#xff1f; 会计软件应有的功能 1、账户管理&#xff1a;会…

overlayfs

参考&#xff1a;How containers work: overlayfs how overlays work Overlay filesystems, also known as “union filesystems” or “union mounts” let you mount a filesystem using 2 directories: a “lower” directory, and an “upper” directory. Basically: t…

C语言之练习题

欢迎来到我的&#xff1a;世界 希望作者的文章对你有所帮助&#xff0c;有不足的地方还请指正&#xff0c;大家一起学习交流 ! 目录 前言填空题&#xff1a;第一题第二题第三题第四题 编程题&#xff1a;第一题&#xff1a;第二题&#xff1a; 总结 前言 填空题&#xff1a; …

网御ACM上网行为管理系统bottomframe.cgi接口存在SQL注入漏洞 附POC

文章目录 网御ACM上网行为管理系统bottomframe.cgi接口存在SQL注入漏洞 附POC1. 网御ACM上网行为管理系统简介2.漏洞描述3.影响版本4.fofa查询语句5.漏洞复现6.POC&EXP7.整改意见8.往期回顾 网御ACM上网行为管理系统bottomframe.cgi接口存在SQL注入漏洞 附POC 免责声明&am…

three.js(九):内置的路径合成几何体

路径合成几何体 TubeGeometry 管道LatheGeometry 车削ExtrudeGeometry 挤压 TubeGeometry 管道 TubeGeometry(path : Curve, tubularSegments : Integer, radius : Float, radialSegments : Integer, closed : Boolean) path — Curve - 一个由基类Curve继承而来的3D路径。 De…

关于Linux系统时间的问题

关于Linux系统时间的问题 当我们进行一些特定的业务需求时&#xff0c;需要修改当前Linux系统的系统时间。我们可以用以下命令进行修改时间。 data -s "2022-08-31 15:00:00"当我们将时间设置为某个时间点后&#xff0c;Linux系统的时间会出现一个问题&#xff1a;…

React原理 - React Reconciliation-上

目录 扩展学习资料 React Reconciliation Stack Reconciler【15版本、栈协调】 Stack Reconciler-事务性 事务性带来的弊端&#xff1a; 扩展学习资料 名称 链接 备注 官方文档 Reconciliation – React 英文 stack reconciler Implementation Notes – React 英文…

IntelliJ IDEA 2023.2.1使用Git时弹出“使用访问令牌登录”问题解决

这里写目录标题 一、内网Git环境GitLabGogsGitea 二、外网Git环境GitHubGitee 升级为IntelliJ IDEA 2023.2.1后&#xff0c;使用Git时弹出“使用访问令牌登录”的窗口&#xff0c;习惯使用Git帐号密码登录的用户&#xff0c;面对这个突如其来的弹窗真的很懵。 一、内网Git环境 …

虚拟化技术原理

计算虚拟化 介绍 把物理主机上物理资源&#xff08;CPU&#xff0c;内存&#xff0c;IO外设&#xff09;&#xff0c;通过虚拟化层抽象成超量、等量的逻辑资源&#xff08;虚拟CPU&#xff0c;虚拟内存&#xff0c;虚拟IO设备&#xff09;&#xff0c;然后重新组合形成新的虚…

大数据学习:impala基础

impala基础 1. impala介绍 1.1 impala概述 Impala是Cloudera公司推出&#xff0c;提供对HDFS、Hbase数据的高性能、低延迟的交互式SQL查询功能。官方测试性能比hive快10到100倍&#xff0c;其sql查询比sparkSQL还要更加快速&#xff0c;号称是当前大数据领域最快的查询sq工具…