JS面试真题 part6

JS面试真题 part6

  • 26、如何判断一个元素是否在可视区域中
  • 27、什么是单点登录?如何实现
  • 28、 如何实现上拉加载,下拉刷新
  • 29、说说你对正则表达式的理解?应用场景?
  • 30、说说你对函数式编程的理解?优缺点

26、如何判断一个元素是否在可视区域中

自己回答:根据当前位置距离浏览器顶部的y轴距离x轴距离和浏览器显示屏的高度宽度进行对比
标准回答:
常用三种方式:

  1. offsetTop、scrollTop、可视区高度
  2. getBoundingClientRect
  3. Intersection Observer

1、offsetTop、scrollTop、可视区高度

主要关系:el.offsetTop - document.documentElement.scrollTop <= viewPortHeight
offsetTop:元素的上边框至包含元素的上内边框之间的像素距离
scrollTop:滚动条滚动距离

将元素的scrollTop和scrollLeft设置为0,可以重置元素的滚动位置

viewPortHeight:可视区高度、设备高度。

代码实现:

 function isInViewPortOfOne (el) {
 // viewPortHeight 
 const viewPortHeight = window.innerHeight || document.documentElement.c
lientHeight || document.body.clientHeight
 const offsetTop = el.offsetTop
 const scrollTop = document.documentElement.scrollTop
 const top = offsetTop - scrollTop
 return top <= viewPortHeight
}

2、getBoundingClientRect

返回值是一个DOMReact对象,拥有left,top,right,bottom,x,y,width和height属性

 const target = document.querySelector('.target');
const clientRect = target.getBoundingClientRect();
console.log(clientRect);
// {
// bottom: 556.21875,
// height: 393.59375,
// left: 333,
// right: 1017,
// top: 162.625,
// width: 684
// }

在这里插入图片描述
如果一个元素在视窗之内的话,那么它一定满足下面四个条件

  • top大于等于0
  • left大于等于0
  • bottom小于等于视窗高度
  • right小于等于视窗宽度

实现代码:

function isInViewPort(element) {
 const viewWidth = window.innerWidth || document.documentElement.clientWi
dth;
 const viewHeight = window.innerHeight || document.documentElement.client
Height;
 const {
 top,
 right,
 bottom,
 left,
 } = element.getBoundingClientRect();
 return (
 top >= 0 &&
 left >= 0 &&
 right <= viewWidth &&
 bottom <= viewHeight
 );
}

3、 Intersection Observer

Intersection Observer 重叠观察者,用于判断两个元素是否重叠,因为不用进行事件的监听,性能方面比 getBoundingClientRect会好很多

使用步骤主要分为两步:创建观察者和传入被观察者

创建观察者

 const options = {
 // 表示重叠面积占被观察者的比例,从0 - 1取值 
 // 1 表示完全被包含
 threshold: 1.0,
 root:document.querySelector('#scrollArea') // 必须是目标元素的父级元素
};
const callback = (entries, observer) => { ....}
const observer = new IntersectionObserver(callback, options);

通过new IntersectionObserver创建了观察者observer,传入的参数 callback在重叠比例超过threshold时会被执行

关于callback回调函数常用属性如下:

// callback
const callback = function(entries, observer) {
 entries.forEach(entry => {
 entry.time; // 触发的时间
 entry.rootBounds; // 根元素的位置矩形,这种情况下为视窗位置
 entry.boundingClientRect; // 被观察者的位置矩形
 entry.intersectionRect; // 重叠区域的位置矩形
 entry.intersectionRatio; // 重叠区域占被观察者面积的比例(被观察者不是矩形时也按矩形计算)
 entry.target; // 被观察者
 });
};

传入被观察者
通过 observer.observer(target) 这一行代码即可注册被观察者

const target = document.querySelector('.target');
observer.observe(target);

27、什么是单点登录?如何实现

标准回答:

什么是单点登录?

单点登录(Single Sign On),简称SSO,是目前比较流行的企业业务整合的解决方案之一

SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有互相信任的应用系统

SSO一般需要一个独立的认证中心(passport),子系统的登录均得通过passport,子系统本身将不参与登录操作

当一个系统成功登录以后,passport 将会颁发一个令牌给各个子系统,子系统可以拿着令牌获取各自的受保护资源,为了减少频繁认证,各个子系统在被 passport 授权以后,会建立一个局部会话,在一定时间内可以无需再次向 passport 发起认证。
在这里插入图片描述
上图有四个系统,当application1、application2、application3需要登录时,将跳到sso系统,sso系统完成登录。其他应用系统也就随之登录了。

如何实现

1、同域名下的单点登录:

cookiedomain属性设置为当前域的父域,并且父域的cookie会被子域所共享。path属性默认为web应用的上下文路径

利用 cookie 的这个特点,只需要将domain属性设置为当前域的父域,同时将cookie的path属性设置为根路径,将Session ID(或Token)保存到父域中。这样所有子域都可以访问这个cookie,不过这要求应用系统的域名建立在一个共同的主域下。

2、不同域名下的单点登录(一):

如果是不同域的情况下Cookie 是不共享的,这里我们可以部署一个认证中心,用于专门处理登录请求的独立的 Web 服务

用户统一在认证中心进行登录,登录成功后,认证中心记录用户的登录状态,并将token写入Cookie (注意这个 Cookie 是认证中心的,应用系统是访问不到的)

应用系统检查当前请求有没有Token,如果没有,说明用户在当前系统中尚未登录,那么就将页面跳转至认证中心

由于这个操作会将认证中心的Cookie 自动带过去,因此,认证中心能够根据:Cookie 知道用户是否已经登录过了

如果认证中心发现用户尚未登录,则返回登录页面,等待用户登录

如果发现用户已经登录过了,就不会让用户再次登录了,而是会跳转回目标URL,并在跳转前生成一个Token,拼接在目标 URL的后面,回传给目标应用系统

应用系统拿到 Token 之后,还需要向认证中心确认下Token的合法性,防止用户伪造。确认无误后,应用系统记录用户的登录状态,并将Token写入Cookie然后给本次访问放行。(注意这个Cookie 是当前应用系统的)

当用户再次访问当前应用系统时,就会自动带上这个Token,应用系统验证 Token 发现用户已登录,:于是就不会有认证中心什么事了

此种实现方式相对复杂,支持跨域,扩展性好,是单点登录的标准做法

3、不同域名下的单点登录(二):

可以选择将 Session ID(或 Token )保存到浏览器的 LocalStorage 中,让前端在每次向后端发送请求时,主动将 LocalStorage 的数据传递给服务端

这些都是由前端来控制的,后端需要做的仅仅是在用户登录成功后,将SessionID(或 Token)放在响应体中传递给前端

单点登录完全可以在前端实现。前端拿到SessionID(或 Token )后,除了将它写入自己的LocalStorage 中之外,还可以通过特殊手段将它写入多个其他域下的LocalStorage
关键代码如下:

//获取 token
var token = result.data.token;
// 动态创建一个不可见的iframe,在 iframe中加载一个跨域的 HTML
var iframe = document.createElement("iframe");
iframe.src = "http://app1.com/localstorage.html";
document.body.append(iframe);
// 使用postMessage()方法将token传递给iframe
setTimeout(function () {
 iframe.contentWindow.postMessage(token, "http://app1.com");
}, 4000);
setTimeout(function () {
 iframe.remove();
}, 6000);
//在这个iframe所加载的HTML中绑定一个事件监听器,当事件被触发时,把接收到的token数据写入localStorage
window.addEventListener('message', function (event) {
 localStorage.setItem('token', event.data)
}, false);

前端通过 iframe +postMessage()方式,将同一份 Token 写入到了多个域下的 Localstorage 中,前端每次在向后端发送请求之前,都会主动从 LocalStorage 中读取 Token 并在请求中携带,这样就实现了同一份 Token 被多个域所共享
此种实现方式完全由前端控制,几乎不需要后端参与,同样支持跨域

28、 如何实现上拉加载,下拉刷新

自己回答:一般存在于移动端,uniapp里有对应的api调用。原生的话,需要根据手指移动的距离和屏幕的高度进行对比,判断是向下滑还是向上拉

标准回答:
下拉刷新和上拉加载这两种交互方式通常出现在移动端中,本质上等同于pc网页中的分页,只是交互形式不同。
开源社区也有很多优秀的解决方案,如 iscrollbetter-scrollpulltorefresh.js

上拉加载实现原理:
在这里插入图片描述
上拉加载的本质是页面触底,或者快要触底的动作
首先了解几个属性

  • scrollTop:滚动视窗的高度距离window顶部的距离,它会随着往上滚动而不断增加,初始值是0,它是一个变化的值
  • clientHeight:它是一个定值,表示屏幕可视区域的高度
  • scrollHeight:页面不能滚动时也是存在的,此时scrollHeight等于clientHeight。scrollHeight表示body所有元素的总长度(包括body元素自身的padding)

综上得出触底公式:
scrollTop + clientHeight >= scrollHeight

简单实现

 let clientHeight = document.documentElement.clientHeight; //浏览器高度
let scrollHeight = document.body.scrollHeight;
let scrollTop = document.documentElement.scrollTop;
let distance = 50; // 距离视窗还有50的时候,开始触发
if ((scrollTop + clientHeight) >= (scrollHeight - distance)) {
 console.log("开始加载数据");
}

下拉刷新实现原理:

下拉刷新的本质是页面本身置于顶部时,用户下拉时需要触发的动作
关于下拉刷新的原生实现,主要分为三步:

  • 监听原生 touchstart 事件,记录其初始位置的值,e.touches[0].pageY;
  • 监听原生 touchmove 事件,记录并计算当前滑动的位置值与初始位置值的差值,大于0表示向下拉动,并借助CSS3translateY属性使元素跟随手势向下滑动对应的差值,同时也应设置一个允许滑动的最大值;
  • 监听原生 touchend 事件,若此时元素滑动达到最大值,则触发 callback ,同时将 translateY 重设为0,元素回到初始位置。

代码实现,html结构

 <main>
 <p class="refreshText"></p >
 <ul id="refreshContainer">
 <li>111</li>
 <li>222</li>
 <li>333</li>
 <li>444</li>
 <li>555</li>
 ...
 </ul>
</main>

监听touchstart事件,记录初始的值

var _element = document.getElementById('refreshContainer'),
 _refreshText = document.querySelector('.refreshText'),
 _startPos = 0, // 初始的值
 _transitionHeight = 0; // 移动的距离
_element.addEventListener('touchstart', function(e) {
 _startPos = e.touches[0].pageY; // 记录初始位置
 _element.style.position = 'relative';
 _element.style.transition = 'transform 0s';
}, false);

监听touchmove事件,记录滑动差值

_element.addEventListener('touchmove', function(e) {
 // e.touches[0].pageY 当前位置
 _transitionHeight = e.touches[0].pageY - _startPos; // 记录差值
 if (_transitionHeight > 0 && _transitionHeight < 60) {
 _refreshText.innerText = '下拉刷新';
 _element.style.transform = 'translateY('+_transitionHeight+'px)';
 if (_transitionHeight > 55) {
 _refreshText.innerText = '释放更新';
 }
 } 
}, false);

最后,就是监听touchend离开的事件

_element.addEventListener('touchend', function(e) {
 _element.style.transition = 'transform 0.5s ease 1s';
 _element.style.transform = 'translateY(0px)';
 _refreshText.innerText = '更新中...';
 // todo...
}, false);

从上面可以看到,在下拉到松手的过程中,经历了三个阶段

  • 当前手势滑动位置与初始位置差值大于零时,提示正在进行下拉刷新操作
  • 下拉到一定值时,显示松手释放后的操作提示
  • 下拉到达设定最大值松手时,执行回调,提示正在进行更新操作

29、说说你对正则表达式的理解?应用场景?

自己回答:需要匹配某种对应的规则的时候.。应用场景:比如手机号码验证,中文名字验证等

标准回答:

正则表达式是一种用来匹配字符串的强有力的武器,它的设计思想是用一种描述性的语言定义一个规则,凡是符合规则的字符串,就认为它“匹配”,否则该字符串就是不合法的。
构建方法有两种
1、字面量创建,其由包含在斜杠之间的模式组成

const re = /\d+/g;

2、调用RegExp对象的构造函数

const re = new RegExp("\\d+","g");
const rul = "\\d+"
const re1 = new RegExp(rul,"g");

使用构造函数创建,第一个参数可以是一个变量,遇到特殊字符 \ 需要使用 \\ 进行转义

应用场景:

验证QQ合法性(5~15位、全是数字、不以0开头)

const reg = /^[1-9][0-9]{4,14}$/
const isvalid = patrn.exec(s)

校验用户账号合法性(只能输入5-20个以字母开头、可带数字、“_”、“.”的字符串)

var patrn=/^[a-zA-Z]{1}([a-zA-Z0-9]|[._]){4,19}$/;
const isvalid = patrn.exec(s)

将url参数解析为对象

30、说说你对函数式编程的理解?优缺点

自己回答:面向过程的编程,去对象化,更关注函数功能,使函数更简洁,不依赖对象。优点:功能集中化,缺点:失去对象的关联性
标准回答:

函数式编程是一种“编程范式"(programming paradigm),一种编写程序的方法论

主要的编程范式有三种:命令式编程声明式编程函数式编程

相比命令式编程,函数式编程更加强调程序执行的结果而非执行的过程,倡导利用若干简单的执行单元让计算结果不断渐进,逐层推导复杂的运算,而非设计一个复杂的执行过程

举个例子,将数组每个元素进行平方操作,命令式编程与函数式编程如下

// 命令式编程
var array = [0, 1, 2, 3]
for(let i = 0; i < array.length; i++) {
 array[i] = Math.pow(array[i], 2)
}
// 函数式编程
[0, 1, 2, 3].map(num => Math.pow(num, 2))

简单来讲,就是要把过程逻辑写成函数,定义好输入参数,只关心它的输出结果
即是一种描述集合和集合之间的转换关系,输入通过函数都会返回有且只有一个输出值

在这里插入图片描述
可以看到,函数实际上是一个关系,或者说是一种映射,而这种映射关系是可以组合的,一旦我们知道一个函数的输出类型可以匹配另一个函数的输入,那他们就可以进行组合

了解几个相关概念

1、纯函数

函数式编程旨在尽可能的提高代码的无状态性和不变性。要做到这一点,就要学会使用无副作用的函数,也就是纯函数
纯函数是对给定的输入返回相同输出的函数,并且要求你所有的数据都是不可变的,即纯函数=无状态+数据不可变
在这里插入图片描述
举一个简单的例子

let double = value=>value*2;

特性:

  • 函数内部传入指定的值,就会返回确定唯一的值
  • 不会造成超出作用域的变化,例如修改全局变量或引用传递的参数

优势:

  • 使用纯函数,我们可以产生可测试的代码
  • 不依赖外部环境计算,不会产生副作用,提高函数的复用性
  • 可读性更强,函数不管是否是纯函数,都会有一个语义化的名称,更便于阅读
  • 可以组装成复杂任务的可能性。符合模块化概念及单一职责原则

2、高阶函数
在我们的编程世界中,我们需要处理的其实也只有“数据”和“关系”,而关系就是函数。
编程工作也就是在找一种映射关系,一旦关系找到了,问题就解决了。
在这里插入图片描述
在这里,就是高阶函数的作用,高级函数,就是以函数作为输入或输出的函数被称为高阶函数
通过高阶函数抽象过程,注重结果,如下面例子

 const forEach = function(arr,fn){
 for(let i=0;i<arr.length;i++){
 fn(arr[i]);
 }
}
let arr = [1,2,3];
forEach(arr,(item)=>{
 console.log(item);
})

上面通过高阶函数 forEach 来抽象循环如何做的逻辑,直接关注做了什么
高阶函数存在缓存的特性,主要是利用闭包作用

 const once = (fn)=>{
	 let done = false;
	 return function(){
		 if(!done){
			 fn.apply(this,fn);
		 }else{
			 console.log("该函数已经执行");
		 }
		 done = true;
	 }
 }

3、柯里化

柯里化是把一个多参数函数转化成一个嵌套的一元函数的过程

一个二元函数如下:

let fn = (x,y)=>x+y;

转化成柯里化函数如下:

const curry = function(fn){
	 return function(x){
		 return function(y){
			 return fn(x,y);
		 }
	 }
}
let myfn = curry(fn);
console.log( myfn(1)(2) );

上面的curry函数只能处理二元情况,下面来实现一个实现多参数的情况

// 多参数柯里化
const curry = function(fn){
	 return function curriedFn(...args){
		 if(args.length<fn.length){
			 return function(){
				 return curriedFn(...args.concat([...arguments]));
			 }
		 }
		 return fn(...args);
	 }
}
const fn = (x,y,z,a)=>x+y+z+a;
const myfn = curry(fn);
console.log(myfn(1)(2)(3)(1));

关于柯里化函数的意义如下:

  • 让纯函数更纯,每次接受一个参数,松散解耦
  • 惰性执行

4、组合与管道

组合函数,目的是将多个函数组合成一个函数
举个简单的例子:

 function afn(a){
    return a*2;
}
function bfn(b){
    return b*3;
}
const compose = (a,b)=>c=>a(b(c));
let myfn = compose(afn,bfn);
console.log( myfn(2));

compose 实现一个简单的功能:形成了一个新的函数,而这个函数就是一条从bfn->afn 的流水线

如何实现一个多函数组合:

const compose = (...fns)=>val=>fns.reverse().reduce((acc,fn)=>fn(acc),val);

compose从右边到左,而管道函数pipe从左到右执行

const pipe = (...fns)=>val=>fns.reduce((acc,fn)=>fn(acc),val);

组合函数与管道函数的意义在于:可以把很多小函数组合起来完成更复杂的逻辑

优缺点

优点:

  • 更好的管理状态:因为它的宗旨是无状态,或者说更少的状态,能最大化的减少这些未知、优化代码、减少出错情况
  • 更简单的复用:固定输入->固定输出,没有其他外部变量影响,并且无副作用。这样代码复用时,完全不需要考虑它的内部实现和外部影响
  • 更优雅的组合:往大的说,网页是各个组件组成的,往小的说,一个函数也可能是由多个小函数组成的。更强的复用性,带来更强大的组合性
  • 隐藏好处。减少代码量,提高维护性

缺点:

  • 性能:函数式编程相对于指令式编程,性能绝对是一个短板,因为它往往会对一个方法进行过度包装,从而产生上下文切换的性能开销
  • 资源占用:在JS中为了实现对象状态的不可变,往往会创建新的对象,因此,它对垃圾回收所产生的压力远远超过其他编程方式
  • 递归陷阱:在函数式编程中,为了实现迭代,通常会采用递归操作

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2015年国赛高教杯数学建模B题互联网+时代的出租车资源配置解题全过程文档及程序

2015年国赛高教杯数学建模 B题 互联网时代的出租车资源配置 出租车是市民出行的重要交通工具之一&#xff0c;“打车难”是人们关注的一个社会热点问题。随着“互联网”时代的到来&#xff0c;有多家公司依托移动互联网建立了打车软件服务平台&#xff0c;实现了乘客与出租车司…

蓝桥杯1.小蓝的漆房

样例输入 2 5 2 1 1 2 2 1 6 2 1 2 2 3 3 3样例输出 1 2 import math import os import sys tint(input())#执行的次数 for j in range(t):n,kmap(int,input().split())#n为房间数 k为一次能涂的个数alist(map(int,input().split()))#以列表的形式存放房间的颜色maxvaluemath…

如何搭建Vue脚手架

Vue 脚手架是Vue官方提供的标准化开发工具(开发平台) 官方文档: Vue CLI 第一步(仅需第一次执行): 安装nodejs环境 官网下载nodejs: https://nodejs.org/en/download/ 第二步(仅需第一次执行): 全局安装vue/cli npm install -g vue/cli 第三步:切换到你需要创建项目的目录,…

Clion使用vcpkg管理C/C++包

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、Clion安装vcpkg二、使用步骤1.切换到清单模式2.开始安装包 三、测试代码总结 前言 Linux上的库基本都可以通过apt或yum等包管理工具来在线安装包&#xff…

mariadb实现冷备份与恢复操作案例(物理冷备份,周期性备份)详解

文章目录 前置环境一、物理冷备份1.备份2.恢复检查结果 补充&#xff1a; 周期性恢复操作 前置环境 主机ipmariadb1192.168.10.11mariadb2192.168.10.12 mairadb1操作 安装mariadb yum -y install mariadb-server启动mariadb systemctl start mariadb这里只是演示备份与恢复…

cefsharp新版本OnBeforeResourceLoad 禁止http自动跳转https显示404错误解决办法 含代码

一、问题 因项目需要,域名没有ssl证书,结果http访问时被强制定向到https前缀,结果会显示404 测试版本cefsharp126.x (x64) 框架 CefSharp.WinForms.NETCore 二、代码(核心代码) 如果请求url是http,且目标是https时,则阻止请求 //判断请求变化 if (url.StartsWith(<…

初试Bootstrap前端框架

文章目录 一、Bootstrap概述二、Bootstrap实例1、创建网页2、编写代码3、代码说明4、浏览网页&#xff0c;查看结果5、登录按钮事件处理6、浏览网页&#xff0c;查看结果 三、实战小结 一、Bootstrap概述 大家好&#xff0c;今天我们将一起学习一个非常流行的前端框架——Boot…

Error: one input ui-file must be specified(问题已解决)

一、 项目场景问题描述 Error: one input ui-file must be specified pycharm IDE添加了外部工具。 QT Designer设计完成&#xff0c;生成界面ui文件&#xff0c; 3.运行pyuic5转换文件 方式一&#xff1a;选中ui文件 方式二:右击选中.ui文件。 报错&#xff1a;Error: o…

SpringCloud Alibaba五大组件之——Sentinel

SpringCloud Alibaba五大组件之——Sentinel&#xff08;文末附有完整项目GitHub链接&#xff09; 前言一、什么是Sentinel二、Sentinel控制台1.下载jar包2.自己打包3.启动控制台4.浏览器访问 三、项目中引入Sentinel1.在api-service模块的pom文件引入依赖&#xff1a;2.applic…

<Java>String类型变量的使用

两边有一个string就是连接&#xff0c;否则做加法 ‘ ’是char&#xff0c;“ ”是string&#xff0c;char能做加法&#xff0c;string只能连接

R包:ggheatmap热图

加载R包 # devtools::install_github("XiaoLuo-boy/ggheatmap")library(ggheatmap) library(tidyr)数据 set.seed(123) df <- matrix(runif(225,0,10),ncol 15) colnames(df) <- paste("sample",1:15,sep "") rownames(df) <- sapp…

NLP技术在营业选址中的实践与探索

传统营业选址面临的问题 在电信业务的服务流程中&#xff0c;用户装机地址的准确性和清晰度对于整个服务体验和运营效率起着至关重要的作用。然而&#xff0c;在实际操作中&#xff0c;装机地址的确定往往面临诸多挑战&#xff0c;这些问题不仅影响用户的服务体验&#xff0c;也…

wireshark使用要点

目录 IP过滤 端口过滤 内容过滤 过滤udp 过滤tcp IP过滤 ip.src XXX.XXX.XXX.XXX 只显示消息源地址为XXX.XXX.XXX.XXX的信息 ip.dst XXX.XXX.XXX.XXX 只显示消息目的地址为XXX.XXX.XXX.XXX的信息 ip.addr XXX.XXX.XXX.XXX显示消息源地址为XXX.XXX.XXX.XXX&#xff0…

通过 OBD Demo 体验 OceanBase 4.3 社区版

本文作者&#xff1a;马顺华 引言 OceanBase 4.3 是一个专为实时分析 AP 业务设计的重大更新版本。它基于LSM-Tree架构&#xff0c;引入了列存引擎&#xff0c;实现了行存与列存数据存储的无缝整合。这一版本不仅显著提升了AP场景的查询性能&#xff0c;同时也确保了TP业务场景…

抽象类、比较器和接口

一.抽象类 1.抽象类的概念&#xff1a;如果一个类中没有包含足够的信息来描述一个具体的对象&#xff0c;这样的类就是抽象类。&#xff08;图例说明&#xff1a;&#xff09; 2.抽象方法的概念&#xff1a;当一个方法被abstract来修饰&#xff0c;此时代表着这个方法可以不进…

leetcode-189:轮转数组

给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 示例 1: 输入: nums [1,2,3,4,5,6,7], k 3 输出: [5,6,7,1,2,3,4] 解释: 向右轮转 1 步: [7,1,2,3,4,5,6] 向右轮转 2 步: [6,7,1,2,3,4,5] 向右轮转 3 步: [5,6,7,1,2,3,4…

毕业设计选题:基于ssm+vue+uniapp的自助购药小程序

开发语言&#xff1a;Java框架&#xff1a;ssmuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;M…

828华为云征文|使用Flexus X实例集成ES搜索引擎

目录 一、应用场景 1.1 Flexus X实例概述 1.2 ES搜索引擎 二、安装相关服务 2.1 安装Elasticsearch7.17.0 2.2 安装kibana7.17.0 三、开通安全组规则 四、整体感受 4.1 Flexus X实例 4.2 使用感觉 一、应用场景 1.1 Flexus X实例概述 Flexus X实例是华为云推出的一款…

Cisco Packet Tracer的安装加汉化

这个工具学计算机网络的同学会用到 1.下载安装 网盘链接&#xff1a;https://pan.baidu.com/s/1CmnxAD9MkCtE7pc8Tjw0IA 提取码&#xff1a;frkb 点击第一个进行安装&#xff0c;按步骤来即可。 2.汉化 &#xff08;1&#xff09;复制chinese.ptl文件 &#xff08;2&…

Redisson分布式锁的概念和使用

Redisson分布式锁的概念和使用 一 简介1.1 什么是分布式锁&#xff1f;1.2 Redisson分布式锁的原理1.3 Redisson分布式锁的优势1.4 Redisson分布式锁的应用场景 二 案例2.1 锁竞争案例2.2 看门狗案例2.3 参考文章 前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff…