如何理解JavaScript定时器的4种写法-附带面试题讲解

news2024/11/25 1:38:06

在JavaScript里,我们已经会使用一些原生提供的方法来实现需要延时执行的操作代码,比如很多在线时钟的制作,图片轮播的实现,还有一些广告弹窗,但凡可以自动执行的东西,都是可以和定时器有关的。今天就来和大家分享一下,关于我们在JavaScript里经常会使用到的定时器方法

在JavaScript里,我们要学习四个定时器的使用方法,setTiemout、setInterval、setImmediate、requestAnimationFrame,一起来看看吧!

什么是定时器

JavaScript中提供了一些原生的函数方法来实现延时去执行某一段代码,这个就是定时器

下面我们来认识一下这些定时器

setTimeout:

设置一个定时器,在定时器到期后执行一次函数或代码段

 var timeoutId = window.setTimeout(func[, delay,param1,...]);
 var timeoutId = window.setTimeout(code[, delay]);

上面用到的关键词名称的意义:

timeoutId: 定时器ID

func: 延迟后执行的函数

code: 延迟后执行的代码字符串,不推荐使用原理类似eval()

delay: 延迟的时间(单位:毫秒),默认值为0

param1: 向延迟函数传递而外的参数,IE9以上支持

setInterval:

以固定的时间间隔重复调用一个函数或者代码段

 var intervalId = window.setInterval(func, delay[, param1,...]);
 var intervalId = window.setInterval(code, delay);

intervalId: 重复操作的ID

func: 延迟调用的函数

code: 代码段

delay: 延迟时间,没有默认值

setImmediate:

在浏览器完全结束当前运行的操作之后立即执行指定的函数(仅IE10和Node 0.10+中有实现),类似setTimeout(func, 0)

 var immediateId = setImmediate(func[, param1, param2, ...]);
 var immediateId = setImmediate(func);

immediateId: 定时器ID

func: 回调

requestAnimationFrame:

专门为实现高性能的帧动画而设计的API,但是不能指定延迟时间,而是根据浏览器的刷新频率而定(帧)

 var requestId = window.requestAnimationFrame(func);

func: 回调

举几个栗子加深思考

基本用法

 // 下面代码执行之后会输出什么?
 var intervalId, timeoutId;
 timeoutId = setTimeout(function() {
    console.log(1);
 }, 300);
 setTimeout(function() {
 clearTimeout(timeoutId);
     console.log(2);
 }, 100);
 setTimeout('console.log("5")', 400);
 intervalId = setInterval(function() {
     console.log(4);
 clearInterval(intervalId);
 }, 200);
 // 分别输出: 2、4、5

setInterval 和 setTimeout的区别?

// 执行下面的代码块会输出什么?
 setTimeout(function() {
    console.log('timeout');
 }, 1000);
 setInterval(function() {
    console.log('interval')
 }, 1000);
 // 输出一次 timeout,每隔1S输出一次 interval
 /*--------------------------------*/
 // 通过setTimeout模拟setInterval 和 setInterval有啥区别么?
 varcallback = function() {
 if(times++ > max) {
 clearTimeout(timeoutId);
 clearInterval(intervalId);
 }
     console.log('start', Date.now() - start);
 for(var i = 0; i < 990000000; i++) {}
    console.log('end', Date.now() - start);
 },
 delay = 100,
 times = 0,
 max = 5,
 start = Date.now(),
 intervalId, timeoutId;
 functionimitateInterval(fn, delay) {
    timeoutId = setTimeout(function() {
 fn();
 if(times <= max) {
 imitateInterval(fn ,delay);
 }
 }, delay);
 }
 imitateInterval(callback, delay);
 intervalId = setInterval(callback, delay);

如果是setTimeout和setInterval的话,它俩仅仅在执行次数上有区别,setTimeout一次、setIntervaln次。

而通过setTimeout模拟的setInterval与setInterval的区别则在于:setTimeout只有在回调完成之后才会去调用下一次定时器,而setInterval则不管回调函数的执行情况,当到达规定时间就会在事件队列中插入一个执行回调的事件,所以在选择定时器的方式时需要考虑setInterval的这种特性是否会对你的业务代码有什么影响?

setTimeout(func, 0) 和 setImmediate(func)谁更快?

 console.time('immediate');
 console.time('timeout');
 setImmediate(() => {
     console.timeEnd('immediate');
 });
 setTimeout(() => {
     console.timeEnd('timeout');
 }, 0);

在Node.JS v6.7.0中测试发现setTimeout更早执行

几道经典的定时器面试题

下面代码运行后的结果是什么?

 // 题目一
 var t = true;
 
 setTimeout(function(){
    t = false;
 }, 1000);
 
 while(t){}
 
 alert('end');

 // 题目二
 for(var i = 0; i < 5; i++) {
 setTimeout(function() {
        console.log(i);
 }, 0);
 }
 
 // 题目三
 var obj = {
    msg: 'obj',
 shout: function() {
 alert(this.msg);
 },
 waitAndShout: function() {
 setTimeout(function() {
 this.shout();
 }, 0);
 }
 };
 obj.waitAndShout();

在讲解上面面试题的答案之前,我们先要理解一下定时器的工作原理,以方便理解上面的题目

JS定时器的工作原理

这里将用引用How JavaScript Timers Work中的例子来解释定时器的工作原理,该图为一个简单版的原理图。

如何理解JavaScript定时器的4种写法「带面试题讲解」

在这图中,左侧数字代表时间,单位毫秒;

左侧文字代表某一个操作完成后,浏览器去询问当前队列中存在哪些正在等待执行的操作;

蓝色方块表示正在执行的代码块;

右侧文字代表在代码运行过程中,出现哪些异步事件。

大致流程如下:

1.程序开始时,有一个JS代码块开始执行,执行时长约为18ms,在执行过程中有3个异步事件触发,其中包括一个setTimeout、鼠标点击事件、setInterval

2.第一个setTimeout先运行,延迟时间为10ms,稍后鼠标事件出现,浏览器在事件队列中插入点击的回调函数,稍后setInterval运行,10ms到达之后,setTimeout向事件队列中插入setTimeout的回调

当第一个代码块执行完成后,浏览器查看队列中有哪些事件在等待,他取出排在队列最前面的代码来执行

3.在浏览器处理鼠标点击回调时,setInterval再次检查到到达延迟时间,他将再次向事件队列中插入一个interval的回调,以后每隔指定的延迟时间之后都会向队列中插入一个回调

4.后面浏览器将在执行完当前队头的代码之后,将再次取出目前队头的事件来执行

在这也只是对定时器的工作原理做了简单的叙述,其实实际的实现处理过程会更加复杂。

面试题的答案

在我们理解了定时器的运行原理之后,接下来我们就基于运行原理的基础上,来看看上面的经典面试题的答案

第一题

alert永远都不会执行,因为JS是单线程的,且定时器的回调将在等待当前正在执行的任务完成后才执行,而while(t) {}直接就进入了死循环一直占用线程,不给回调函数执行机会

第二题

代码会输出 5 5 5 5 5,理由同上,当i = 0时,生成一个定时器,将回调插入到事件队列中,等待当前队列中无任务执行时立即执行,而此时for循环正在执行,所以回调被搁置。当for循环执行完成后,队列中存在着5个回调函数,他们的都将执行console.log(i)的操作,因为当前JS代码上中并没有使用块级作用域,所以i的值在for循环结束后一直为5,所以代码将输出5个5

第三题

这个问题涉及到this的指向问题,由setTimeout()调用的代码运行在与所在函数完全分离的执行环境上. 这会导致这些代码中包含的this关键字会指向window (或全局)对象,window对象中并不存在shout方法,所以就会报错,修改方案如下:

 var obj = {
     msg: 'obj',
 shout: function() {
 alert(this.msg);
 },
 waitAndShout: function() {
 var self = this; // 这里将this赋给一个变量
 setTimeout(function() {
            self.shout();
 }, 0);
 }
 };
 obj.waitAndShout();

需要注意的点

1.setTimeout有最小时间间隔限制,HTML5标准为4ms,小于4ms按照4ms处理,但是每个浏览器实现的最小间隔都不同

2.因为JS引擎只有一个线程,所以它将会强制异步事件排队执行

3.如果setInterval的回调执行时间长于指定的延迟,setInterval将无间隔的一个接一个执行

4.this的指向问题可以通过bind函数、定义变量、箭头函数的方式来解决


1.希望获取到页面中所有的checkbox怎么做?(不使用第三方框架)

var domList = document.getElementsByTagName(‘input’)
var checkBoxList = [];
var len = domList.length;  //缓存到局部变量
while (len--) {  //使用while的效率会比for循环更高
  if (domList[len].type == ‘checkbox’) {
      checkBoxList.push(domList[len]);
  }
}

2.当一个DOM节点被点击时候,我们希望能够执行一个函数,应该怎么做?

  1. 直接在DOM里绑定事件:<div οnclick=”test()”></div>
  2. 在JS里通过onclick绑定:xxx.onclick = test
  3. 通过事件添加进行绑定:addEventListener(xxx, ‘click’, test)

那么问题来了,Javascript的事件流模型都有什么?

  1. “事件冒泡”:事件开始由最具体的元素接受,然后逐级向上传播
  2. “事件捕捉”:事件由最不具体的节点先接收,然后逐级向下,一直到最具体的
  3. “DOM事件流”:三个阶段:事件捕捉,目标阶段,事件冒泡

3. var numberArray = [3,6,2,4,1,5];

1) 实现对该数组的倒排,输出[5,1,4,2,6,3]

2) 实现对该数组的降序排列,输出[6,5,4,3,2,1]

var numberArray = [3,6,2,4,1,5];
numberArray.reverse(); // 5,1,4,2,6,3
numberArray.sort(function(a,b){  //6,5,4,3,2,1
   return b-a;
})

4.输出今天的日期,以YYYY-MM-DD的方式,

比如今天是2020年7月1日,则输出2020-07-01

var d = new Date();
// 获取年,getFullYear()返回4位的数字
var year = d.getFullYear();
// 获取月,月份比较特殊,0是1月,11是12月
var month = d.getMonth() + 1;
// 变成两位
month = month < 10 ? '0' + month : month;
// 获取日
var day = d.getDate();
day = day < 10 ? '0' + day : day;
alert(year + '-' + month + '-' + day);

5.用js实现随机选取10--100之间的10个数字,存入一个数组,并排序。

var iArray = [];
funtion getRandom(istart, iend){
        var iChoice = iend - istart +1;
        return Math.floor(Math.random() * iChoice + istart);
}
for(var i=0; i<10; i++){
        iArray.push(getRandom(10,100));
}
iArray.sort();

6. 如何消除一个数组里面重复的元素?

var arr = [1, 2, 3, 3, 4, 4, 5, 5, 6, 1, 9, 3, 25, 4];
 
function deRepeat() {
    var newArr = [];
    var obj = {};
    var index = 0;
    var l = arr.length;
    for (var i = 0; i < l; i++) {
        if (obj[arr[i]] == undefined) {
            obj[arr[i]] = 1;
            newArr[index++] = arr[i];
        } else if (obj[arr[i]] == 1)
            continue;
    }
    return newArr;
 
}
var newArr2 = deRepeat(arr);
alert(newArr2); //输出1,2,3,4,5,6,9,25

7.下面这个ul,如何点击每一列的时候alert其index?

<ul id=”test”>
    <li>这是第一条</li>
    <li>这是第二条</li>
    <li>这是第三条</li>
</ul>
答案
// 方法一:
var lis=document.getElementById('2223').getElementsByTagName('li');
for(var i=0;i<3;i++)
{
    lis[i].index=i;
    lis[i].onclick=function(){
        alert(this.index);
    };
}
 
//方法二:
var lis=document.getElementById('2223').getElementsByTagName('li');
for(var i=0;i<3;i++)
{
    lis[i].index=i;
    lis[i].onclick=(function(a){
        return function() {
            alert(a);
        }
    })(i);
}

8.定义一个log方法,让它可以代理console.log的方法。

可行的方法一:

function log(msg)  {
    console.log(msg);
}
log("hello world!") // hello world!

如果要传入多个参数呢?显然上面的方法不能满足要求,所以更好的方法是:

function log() {
    console.log.apply(console, arguments);
};

9.在Javascript中什么是伪数组?如何将伪数组转化为标准数组?

答案:

伪数组(类数组):无法直接调用数组方法或期望length属性有什么特殊的行为,但仍可以对真正数组遍历方法来遍历它们。典型的是函数的argument参数,还有像调用getElementsByTagName,document.childNodes之类的,它们都返回NodeList对象都属于伪数组。可以使用
Array.prototype.slice.call(fakeArray)将数组转化为真正的Array对象。

10.对作用域上下文和this的理解,看下列代码:

var User = {
    count: 1,
 
    getCount: function() {
        return this.count;
    }
};
console.log(User.getCount()); // what?
var func = User.getCount;
console.log(func()); // what?

问两处 console 输出什么?为什么?

答案是 1 和 undefined。

func 是在 winodw 的上下文中被执行的,所以会访问不到 count 属性。


1. 实现一个call函数

// 思路:将要改变this指向的方法挂到目标this上执行并返回
Function.prototype.mycall = function (context) {
  if (typeof this !== 'function') {
    throw new TypeError('not funciton')
  }
  context = context || window
  context.fn = this
  let arg = [...arguments].slice(1)
  let result = context.fn(...arg)
  delete context.fn
  return result
} 

2. 实现一个apply函数

// 思路:将要改变this指向的方法挂到目标this上执行并返回
Function.prototype.myapply = function (context) {
  if (typeof this !== 'function') {
    throw new TypeError('not funciton')
  }
  context = context || window
  context.fn = this
  let result
  if (arguments[1]) {
    result = context.fn(...arguments[1])
  } else {
    result = context.fn()
  }
  delete context.fn
  return result
}

3. 实现一个bind函数

// 思路:类似call,但返回的是函数
Function.prototype.mybind = function (context) {
  if (typeof this !== 'function') {
    throw new TypeError('Error')
  }
  let _this = this
  let arg = [...arguments].slice(1)
  return function F() {
    // 处理函数使用new的情况
    if (this instanceof F) {
      return new _this(...arg, ...arguments)
    } else {
      return _this.apply(context, arg.concat(...arguments))
    }
  }
}

4. new本质

function myNew (fun) {
  return function () {
    // 创建一个新对象且将其隐式原型指向构造函数原型
    let obj = {
      __proto__ : fun.prototype
    }
    // 执行构造函数
    fun.call(obj, ...arguments)
    // 返回该对象
    return obj
  }
}
function person(name, age) {
  this.name = name
  this.age = age
}
let obj = myNew(person)('chen', 18) 
// {name: "chen", age: 18}

5. Object.create的基本实现原理

// 思路:将传入的对象作为原型
function create(obj) {
  function F() {}
  F.prototype = obj
  return new F()
}

6. instanceof的原理

// 思路:右边变量的原型存在于左边变量的原型链上
function instanceOf(left, right) {
  let leftValue = left.__proto__
  let rightValue = right.prototype
  while (true) {
    if (leftValue === null) {
      return false
    }
    if (leftValue === rightValue) {
      return true
    }
    leftValue = leftValue.__proto__
  }
}

7. 实现一个基本的Promise

// 未添加异步处理等其他边界情况
// ①自动执行函数,②三个状态,③then
class Promise {
  constructor (fn) {
    // 三个状态
    this.state = 'pending'
    this.value = undefined
    this.reason = undefined
    let resolve = value => {
      if (this.state === 'pending') {
        this.state = 'fulfilled'
        this.value = value
      }
    }
    let reject = value => {
      if (this.state === 'pending') {
        this.state = 'rejected'
        this.reason = value
      }
    }
    // 自动执行函数
    try {
      fn(resolve, reject)
    } catch (e) {
      reject(e)
    }
  }
  // then
  then(onFulfilled, onRejected) {
    switch (this.state) {
      case 'fulfilled':
        onFulfilled()
        break
      case 'rejected':
        onRejected()
        break
      default:
    }
  }
}

8. 实现浅拷贝

// 1. ...实现
let copy1 = {...{x:1}}
// 2. Object.assign实现
let copy2 = Object.assign({}, {x:1})

9. 使用setTimeout模拟setInterval

// 可避免setInterval因执行时间导致的间隔执行时间不一致
setTimeout (function () {
  // do something
  setTimeout (arguments.callee, 500)
}, 500)

10. js实现一个继承方法

// 借用构造函数继承实例属性
function Child () {
  Parent.call(this)
}
// 寄生继承原型属性
(function () {
  let Super = function () {}
  Super.prototype = Parent.prototype
  Child.prototype = new Super()
})()

11. 实现一个基本的深拷贝

// 1. JOSN.stringify()/JSON.parse()
let obj = {a: 1, b: {x: 3}}
JSON.parse(JSON.stringify(obj))
// 2. 递归拷贝
function deepClone(obj) {
 let copy = obj instanceof Array ? [] : {}
 for (let i in obj) {
  if (obj.hasOwnProperty(i)) {
  copy[i] = typeof obj[i] === 'object'?deepClone(obj[i]):obj[i]
    }
  }
  return copy
}

12. 实现一个基本的Event Bus

// 组件通信,一个触发与监听的过程
class EventEmitter {
  constructor () {
    // 存储事件
    this.events = this.events || new Map()
  }
  // 监听事件
  addListener (type, fn) {
    if (!this.events.get(type)) {
      this.events.set(type, fn)
    }
  }
  // 触发事件
  emit (type) {
    let handle = this.events.get(type)
    handle.apply(this, [...arguments].slice(1))
  }
}
// 测试
let emitter = new EventEmitter()
// 监听事件
emitter.addListener('ages', age => {
  console.log(age)
})
// 触发事件
emitter.emit('ages', 18)  // 18

13. 实现一个双向数据绑定

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
})

14. 实现一个简单路由

// hash路由
class Route{
  constructor(){
    // 路由存储对象
    this.routes = {}
    // 当前hash
    this.currentHash = ''
    // 绑定this,避免监听时this指向改变
    this.freshRoute = this.freshRoute.bind(this)
    // 监听
    window.addEventListener('load', this.freshRoute, false)
    window.addEventListener('hashchange', this.freshRoute, false)
  }
  // 存储
  storeRoute (path, cb) {
    this.routes[path] = cb || function () {}
  }
  // 更新
  freshRoute () {
    this.currentHash = location.hash.slice(1) || '/'
    this.routes[this.currentHash]()
  }   
}

15. 实现一个节流函数

// 思路:在规定时间内只触发一次
function throttle (fn, delay) {
  // 利用闭包保存时间
  let prev = Date.now()
  return function () {
    let context = this
    let arg = arguments
    let now = Date.now()
    if (now - prev >= delay) {
      fn.apply(context, arg)
      prev = Date.now()
    }
  }
}
function fn () {
  console.log('节流')
}
addEventListener('scroll', throttle(fn, 1000)) 

16. 实现一个防抖函数

// 思路:在规定时间内未触发第二次,则执行
function debounce (fn, delay) {
  // 利用闭包保存定时器
  let timer = null
  return function () {
    let context = this
    let arg = arguments
    // 在规定时间内再次触发会先清除定时器后再重设定时器
    clearTimeout(timer)
    timer = setTimeout(function () {
      fn.apply(context, arg)
    }, delay)
  }
}
function fn () {
  console.log('防抖')
}
addEventListener('scroll', debounce(fn, 1000)) 

 问题1:Scope作用范围

考虑下面的代码:

(function() {   var a = b = 5;})();
console.log(b);

什么会被打印在控制台上?
回答
上面的代码会打印 5。
这个问题的诀窍是,这里有两个变量声明,但 a 使用关键字var声明的。代表它是一个函数的局部变量。与此相反,b 变成了全局变量。
这个问题的另一个诀窍是,它没有使用严格模式 ('use strict';) 。如果启用了严格模式,代码就会引发ReferenceError的错误:B没有定义(b is not defined)。请记住,严格模式,则需要明确指定,才能实现全局变量声明。比如,你应该写:

(function() {  
  'use strict'; 
  var a = window.b = 5;
})();
console.log(b);

问题2:创建“原生”(native)方法

给字符串对象定义一个repeatify功能。当传入一个整数n时,它会返回重复n次字符串的结果。例如:

console.log('hello'.repeatify(3));

应打印 hellohellohello。

回答
一个可能的实现如下所示:

String.prototype.repeatify = String.prototype.repeatify || function(times) {  
  var str = '';  
  for (var i = 0; i < times; i++) {   
    str += this;  
  }  
  return str
  ;};

现在的问题测试开发者有关JavaScript继承和prototype的知识点。这也验证了开发者是否知道该如何扩展内置对象(尽管这不应该做的)。
这里的另一个要点是,你要知道如何不覆盖可能已经定义的功能。通过测试一下该功能定义之前并不存在:

String.prototype.repeatify = String.prototype.repeatify || function(times) {/* code here */};

当你被要求做好JavaScript函数兼容时这种技术特别有用。

问题3:this在JavaScript中如何工作的

下面的代码会输出什么结果?给出你的答案。

var fullname = 'John Doe';var obj = {  
  fullname: 'Colin Ihrig',   prop: {    
    fullname: 'Aurelio De Rosa',    
    getFullname: function() {   
      return this.fullname;    
    }   
  }};
console.log(obj.prop.getFullname());
var test = obj.prop.getFullname; 
console.log(test());

回答
答案是Aurelio De Rosa和John Doe。

原因是,在一个函数中,this的行为,取决于JavaScript函数的调用方式和定义方式,而不仅仅是看它如何被定义的。
在第一个 console.log()调用中,getFullname() 被调用作为obj.prop对象的函数。

所以,上下文指的是后者,函数返回该对象的fullname。

与此相反,当getFullname()被分配到test变量时,上下文指的是全局对象(window)。

这是因为test是被隐式设置为全局对象的属性。

出于这个原因,该函数返回window的fullname,即定义在第一行的那个值。

问题4:声明提升(Hoisting)

执行这段代码,输出什么结果。

function test() {  
  console.log(a);  
  console.log(foo());  
  var a = 1;   
  function foo() {
    return 2;   
  }}
test();

回答
这段代码的结果是 undefined 和 2。
原因是,变量和函数的声明都被提前了(移到了函数的顶部),但变量不分配任何值。因此,在打印变量的时候,它在函数中存在(它被声明了),但它仍然是 undefined 。表示换句话说,上面的代码等同于以下内容:

function test() {
  var a;   
  function foo() { 
    return 2;   
  }    
  console.log(a); 
  console.log(foo());  
  a = 1;
} 
test();

问题5:call() 和 apply()

现在让你解决前一个问题,使最后的console.log() 打印 Aurelio De Rosa。
回答
该问题可以通过强制使用 call() 或者 apply() 改变函数上下文。在下面我将使用call(),但在这种情况下,apply()会输出相同的结果:

console.log(test.call(obj.prop));

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

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

相关文章

网工内推 | 国企、上市公司,IA/IP认证即可,有年终、绩效

01 上海市机械设备成套&#xff08;集团&#xff09;有限公司 招聘岗位&#xff1a;网络工程师 职责描述&#xff1a; 1、 负责公司电脑、网络设备、电器设备、办公设备等硬件的管理、维护和使用&#xff0c;做好计算机硬件及办公设备台帐&#xff1b; 2、 负责公司办公软件的…

博客系统的页面设计

效果展示 博客列表页 博客详情页 博客登录页 博客编辑页 主要分成四个页面: 博客列表页 显示出都有哪些博客博客详情页 展示博客的详细正文博客登录页 进行登录操作博客编辑页 有一个 markdown 编译器,可以编写博客内容 1.实现博客列表页 1.背景设计 body {/*注意这里相对…

【UE5 C++ 學習日志】01. UEnhancedInput

UE5 提供了一種對複雜輸入處理或運行時重新映射按鍵增强輸入插件。此插件向上兼容UE4的默認輸入系統&#xff0c;并可以實現径向死区、同时按键、上下文输入和优先级安排等多種功能。 核心概念&#xff1a; &#xff08;1&#xff09;Input Actions&#xff1a; Input Actio…

ROS学习ROS基础

ROS学习&#xff08;一&#xff09; ROS基础 一、工作空间基本操作二、ROS通信编程——话题编程 "hello world " 例程 1、创建发布者&#xff08;talker&#xff09;2、创建订阅者&#xff08;listener&#xff09;3、添加编译选项4、运行可执行文件 自定义话题消息…

在PHP8中对数组进行排序-PHP8知识详解

在php8中&#xff0c;提供了丰富的排序函数&#xff0c;可以对数组进行排序操作。常见的排序函数如下几个&#xff1a;sort() 函数、rsort() 函数、asort() 函数、arsort() 函数、ksort() 函数、krsort() 函数、natsort()函数和natcascsort()函数。 1、sort() 函数&#xff1a;…

<C++> 红黑树模拟实现map和set

使用一颗红黑树同时封装map和set。 红黑树源码 #pragma once #include <cassert> #include <iostream> #include <utility> using namespace std;// 红黑树结点颜色 enum Colour {RED,BLACK, };template<class K, class V> struct RBTreeNode {//使用…

分析常见数据结构在内存中的存储形式

本文会在x64dbg中分析vector,list,map的内存存储特点 目录 分析vector在内存中的存储形式 x32dbg分析vector数组 总结一下vector的内存布局 分析 list 在内存中的存储形式 x32dbg分析 list 数组 总结一下 list 的内存布局 分析map在内存中的存储形式 x32dbg分析map 总…

python爬虫爬取电影数据并做可视化

思路&#xff1a; 1、发送请求&#xff0c;解析html里面的数据 2、保存到csv文件 3、数据处理 4、数据可视化 需要用到的库&#xff1a; import requests,csv #请求库和保存库 import pandas as pd #读取csv文件以及操作数据 from lxml import etree #解析html库 from …

内网穿透工具 Cpolar 帮您实现用友U8 Cloud 的外网部署,一键畅享云端ERP

文章目录 前言1. 用户需求2. Cpolar内网穿透的安装和注册2.1 Cpolar云端设置2.2 Cpolar Web UI本地设置 3. 公网访问测试 前言 用友U8 Cloud是用友公司推出的一款云端ERP解决方案。它以云计算技术为基础&#xff0c;为企业提供全面的企业资源管理解决方案&#xff0c;涵盖了财…

主机存活检测脚本

原理演示 在命令行下用下面命令安装scap模块&#xff1a; python -m pip install scapyscapy与scrapy 有非常大的区别。 scapy 是一个Python 的第三方模块&#xff0c;被称为“网络神器”。scapy 模块能够发送、捕获、分析和铸造网络数据 sr1发送接收函数 如图&#xff0c;安…

AI绘画变现渠道:日入100+,推荐一个本人实操的方法

关于AI绘画变现&#xff0c;之前写了几篇相关的文章&#xff0c;需要的自己查阅&#xff1a; AI绘画&#xff1a;如何让图片开口说话生成视频&#xff1f;变现渠道有哪些&#xff1f; 无私分享我的AI绘画变现之路&#xff0c;普通人可实操可模仿 AI壁纸号一周增加上千粉丝&a…

二叉树题目:层数最深叶子结点的和

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法一思路和算法代码复杂度分析 解法二思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;层数最深叶子结点的和 出处&#xff1a;1302. 层数最深叶子结点的和 难度 4 级 题目描述 要求 给定一个二叉树…

有效的括号(栈的高频面试题)

一、题目描述 题目连接&#xff1a;有效的括号 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。左括号必须以正确的顺…

我的创作纪念日 · 开始创作的第128天~

我的创作纪念日 开始创作的第128天 1️⃣ 机缘2️⃣ 收获3️⃣ 日常4️⃣ 憧憬 1️⃣ 机缘 时光匆匆&#xff0c;春去秋来&#xff0c;2023年在CSDN下笔的128天已去&#xff0c;回想当初成为创作者的初心&#xff0c;现在的心境已截然不同。当时正值上家公司工作变动&#xf…

【大数据】Doris 构建实时数仓落地方案详解(二):Doris 核心功能解读

Doris 构建实时数仓落地方案详解&#xff08;二&#xff09;&#xff1a;Doris 核心功能解读 1.Doris 发展历程2.Doris 三大模型3.Doris 数据导入4.Doris 多表关联5.Doris 核心设计6.Doris 查询优化7.Doris 应对实时数仓的痛点 1.Doris 发展历程 Apache Doris 是由 百度 研发并…

华为云云耀云服务器L实例评测|用Python的Flask框架加Nginx实现一个通用的爬虫项目

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;CSDN领军人物&#xff0c;全栈领域优质创作者✌&#xff0c;CSDN博客专家&#xff0c;阿里云社区专家博主&#xff0c;2023年6月CSDN上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;AWS/阿里云资深使用…

QUIC协议报文解析(三)

在前面的两篇文字里我们简单介绍了QUIC的发展历史&#xff0c;优点以及QUIC协议的连接原理。本篇文章将会以具体的QUIC报文为例&#xff0c;详细介绍QUIC报文的结构以及各个字段的含义。 早期QUIC版本众多&#xff0c;主要有谷歌家的gQUIC&#xff0c;以及IETF致力于将QUIC标准…

数据结构之堆的结构与实现

目录 一、堆的概念及结构 1.1堆的概念 1.2堆的性质 1.3堆的结构 二、堆的实现 2.1堆向下调整算法&#xff08;父亲与孩子做比较&#xff09; 2.2堆的向上调整算法&#xff08;孩子与父亲做比较&#xff09; 2.3堆的创建&#xff08;向下建堆&#xff09; 2.4向下建堆的时…

26 WEB漏洞-XSS跨站之订单及Shell箱子反杀记

目录 xss平台及工具使用session与Cookie获取问题演示案例某营销订单系统XSS盲打_平台某Shell箱子系统XSS盲打_工具其他参考应用案例-后台权限维持工具Http/s数据包提交Postman使用 xss平台及工具使用 凡是有数据交互的地方&#xff0c;前端是接收数据的&#xff0c;后端是要把…