每天10个前端小知识 【Day 11】

news2024/12/26 2:46:38

在这里插入图片描述

前端面试基础知识题

1. 浏览器的垃圾回收机制有哪些?

JS会在创建变量时自动分配内存,在不使用的时候会自动周期性的释放内存,释放的过程就叫 “垃圾回收”。

一方面自动分配内存减轻了开发者的负担,开发者不用过多的去关注内存使用,但是另一方面,正是因为因为是自动回收,所以如果不清楚回收的机制,会很容易造成混乱,而混乱就很容易造成"内存泄漏"。

由于是自动回收,所以就存在一个 “内存是否需要被回收的” 的问题,但是这个问题的判定在程序中意味着无法通过某个算法去准确完整的解决,后面探讨的回收机制只能有限的去解决一般的问题。

垃圾回收对是否需要回收的问题主要依赖于对变量的判定是否可访问,由此衍生出两种主要的回收算法:

  • 标记清理
  • 引用计数

标记清理

标记清理是js最常用的回收策略,2012年后所有浏览器都使用了这种策略,此后的对回收策略的改进也是基于这个策略的改进。其策略是:

变量进入上下文,也可理解为作用域,会加上标记,证明其存在于该上下文;
将所有在上下文中的变量以及上下文中被访问引用的变量标记去掉,表明这些变量活跃有用;
在此之后再被加上标记的变量标记为准备删除的变量,因为上下文中的变量已经无法访问它们;
执行内存清理,销毁带标记的所有非活跃值并回收之前被占用的内存;

局限:

由于是从根对象(全局对象)开始查找,对于那些无法从根对象查询到的对象都将被清除;
回收后会形成内存碎片,影响后面申请大的连续内存空间

引用计数

引用计数策略相对而言不常用,因为弊端较多。其思路是对每个值记录它被引用的次数,通过最后对次数的判断(引用数为0)来决定是否保留,具体的规则有:

声明一个变量,赋予它一个引用值时,计数+1;
同一个值被赋予另外一个变量时,引用+1;
保存对该值引用的变量被其他值覆盖,引用-1;
引用为0,回收内存;

局限:最重要的问题就是,循环引用 的问题。

function refProblem () {
    let a = new Object();
    let b = new Object();
    a.c = b;
    b.c = a;  //互相引用
}

根据之前提到的规则,两个都互相引用了,引用计数不为0,所以两个变量都无法回收。如果频繁的调用改函数,则会造成很严重的内存泄漏。

2. 箭头函数的 this 指向哪⾥?

箭头函数不同于传统JavaScript中的函数,箭头函数并没有属于⾃⼰的this,它所谓的this是捕获其所在上下⽂的 this 值,作为⾃⼰的 this 值,并且由于没有属于⾃⼰的this,所以是不会被new调⽤的,这个所谓的this也不会被改变。

可以⽤Babel理解⼀下箭头函数:

// ES6 
const obj = { 
  getArrow() { 
    return () => { 
      console.log(this === obj); 
    }; 
  } 
}

转化后:

// ES5,由 Babel 转译
var obj = { 
   getArrow: function getArrow() { 
     var _this = this; 
     return function () { 
        console.log(_this === obj); 
     }; 
   } 
};

3. 使用Promise实现每隔1秒输出1,2,3

这道题比较简单的一种做法是可以用Promise配合着reduce不停的在promise后面叠加.then,请看下面的代码:

const arr = [1, 2, 3]
arr.reduce((p, x) => {
  return p.then(() => {
    return new Promise(r => {
      setTimeout(() => r(console.log(x)), 1000)
    })
  })
}, Promise.resolve())

还可以更简单一点写:

const arr = [1, 2, 3]
arr.reduce((p, x) => p.then(() => new Promise(r => setTimeout(() => r(console.log(x)), 1000))), Promise.resolve())

4. 如何使用js计算一个html页面有多少种标签?

这道题看似简单,但是是一个很有价值的一道题目。它包含了很多重要的知识:

  • 如何获取所有DOM节点
  • 伪数组如何转为数组
  • 去重

解题过程

  • 获取所有的DOM节点。
document.querySelectorAll('*')

此时得到的是一个NodeList集合,我们需要将其转化为数组,然后对其筛选。

  • 转化为数组
[...document.querySelectorAll('*')]

一个拓展运算符就轻松搞定。

  • 获取数组每个元素的标签名
[...document.querySelectorAll('*')].map(ele => ele.tagName)

使用一个map方法,将我们需要的结果映射到一个新数组。

  • 去重
new Set([...document.querySelectorAll('*')].map(ele=> ele.tagName)).size

我们使用ES6中的Set对象,把数组作为构造函数的参数,就实现了去重,再使用Set对象的size方法就可以得到有多少种HTML元素了。

5. Html文档渲染过程,css文件和js文件的下载,是否会阻塞渲染?

浏览器内有多个进程,其中渲染进程被称为浏览器内核,负责页面渲染和执行 JS 脚本等。渲染进程负责浏览器的解析和渲染,内部有 JS 引擎线程、 GUI 渲染线程、事件循环管理线程、定时器线程、HTTP 线程。
JS 引擎线程负责执行 JS 脚本,GUI 渲染线程负责页面的解析和渲染,两者是互斥的,也就是执行 JS 的时候页面是停止解析和渲染的。这是因为如果在页面渲染的同时 JS 引擎修改了页面元素,比如清空页面,会造成后续页面渲染的不必要和错误。而由于 JS 经常要操作 DOM ,就要涉及 JS 引擎线程和 GUI 渲染线程的通信,而线程间通信代价是非常昂贵的,这也是造成 JS 操作 DOM 效率不高的原因。
浏览器的 HTML/CSS 的解析和渲染都属于 GUI渲染线程,所以和 JS 引擎线程是互斥、阻塞的。下面从代码实际运行的角度分析浏览器解析和渲染的顺序,以及互相间的阻塞关系。

CSS 阻塞

  • css 文件的下载和解析不会影响 DOM 的解析,但是会阻塞 DOM 的渲染。因为 CSSOM Tree 要和 DOM Tree 合成 Render Tree 才能绘制页面。下面的 test1 在 css 下载并解析完成前是默认样式, test2 在 css 下载并解析完成之前不会显示:
<button class="btn btn-primary">test1</button>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css">
<div>test2</div>
  • css 文件没下载并解析完成之前,后续的 js 脚本不能执行。下面的 alert(‘ok’) 在 css 下载并解析完成之前不会弹出来:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css">
<script>
    alert('ok')
</script>
  • css 文件的下载不会阻塞前面的 js 脚本执行。下面的 alert(‘ok’) 会在 css 下载完成前弹出:
<script>
    alert('ok')
</script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css">

所以在需要提前执行不操作 dom 元素的 js 时,不妨把 js 放到 css 文件之前。

JS 阻塞

js 文件的下载和解析会阻塞 GUI 渲染进程,也就是会阻塞 DOM 和 CSS 的解析和渲染。

js 文件没下载并解析完成之前,后续的 HTML 和 CSS 无法解析:

<script src="https://code.jquery.com/jquery-3.4.1.js"></script>
<div>test</div>

js 文件的下载不会阻塞前面 HTML 和 CSS 的解析:

<div>test</div>
<script src="https://code.jquery.com/jquery-3.4.1.js"></script>

需要注意的点

  • 第一,GUI 渲染线程会尽可能早的将内容呈现到屏幕上,并不会等到所有的 HTML 都解析完成之后再去构建和布局 Render Tree,而是解析完一部分内容就显示一部分内容,同时,可能还在通过网络下载其余内容。下面 test1 会在 js 文件下载完成前渲染完成,而 test2 则会在 js 文件下载并执行完之后渲染:
  <div>test1</div>
  <script src="https://code.jquery.com/jquery-3.4.1.js"></script>
  <div>test2</div>
  • 第二,文件的下载是不会被阻塞的,不管是 css 还是 js 文件,浏览器的主线程会在页面解析前开启下载,所以就算在外部脚本执行前删除脚本,脚本也还是会下载。
<body>
  <script>
    document.body.remove()
  </script>  
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css">
  <script src="https://code.jquery.com/jquery-3.4.1.js"></script>
</body>

6. forEach 中能否使用 await ?

function test() {
  let arr = [3, 2, 1];
  arr.forEach(async (item) => {
    const res = await fetch(item);
    console.log(res);
  });
  console.log("end");
}

function fetch(x) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(x);
    }, 500 * x);
  });
}

test();

上面代码的输出结果是:

end
1
2
3

为什么

其实原因很简单,那就是 forEach 只支持同步代码。

我们可以参考下 Polyfill 版本的 forEach,简化以后类似就是这样的伪代码

while (index < arr.length) {
	callback(item, index)   //也就是我们传入的回调函数
}

从上述代码中我们可以发现,forEach 只是简单的执行了下回调函数而已,并不会去处理异步的情况。 并且即使你在 callback 中使用 break 也并不能结束遍历。

怎么解决

一般来说解决的办法有2种:

  • for…of
//因为 for...of 内部处理的机制和 forEach 不同,forEach 是直接调用回调函数,for...of 是通过迭代器的方式去遍历。
async function test() {
  let arr = [3, 2, 1];
  for (const item of arr) {
    const res = await fetch(item);
    console.log(res);
  }
  console.log("end");
}
  • for循环
async function test() {
  let arr = [3, 2, 1];
  for (var i = 0; i < arr.length; i++) {
    const res = await fetch(arr[i]);
    console.log(res);
  }
  console.log("end");
}

function fetch(x) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(x);
    }, 500 * x);
  });
}

test();

7. 如何中断Promise?

Promise 有个缺点就是一旦创建就无法取消,所以本质上 Promise 是无法被终止的,但我们在开发过程中可能会遇到下面两个需求:

  • 中断调用链

就是在某个 then/catch 执行之后,不想让后续的链式调用继续执行了。

somePromise
  .then(() => {})
  .then(() => {
    // 终止 Promise 链,让下面的 then、catch 和 finally 都不执行
  })
  .then(() => console.log('then'))
  .catch(() => console.log('catch'))
  .finally(() => console.log('finally'))

一种方法是在then中直接抛错, 这样就不会执行后面的then, 直接跳到catch方法打印err(但此方法并没有实际中断)。但如果链路中对错误进行了捕获,后面的then函数还是会继续执行。

Promise的then方法接收两个参数:

Promise.prototype.then(onFulfilled, onRejected)

若onFulfilled或onRejected是一个函数,当函数返回一个新Promise对象时,原Promise对象的状态将跟新对象保持一致,详见Promises/A+标准。

因此,当新对象保持“pending”状态时,原Promise链将会中止执行。

Promise.resolve().then(() => {
    console.log('then 1')
    return new Promise(() => {})
}).then(() => {
    console.log('then 2')
}).then(() => {
    console.log('then 3')
}).catch((err) => {
    console.log(err)
})
  • 中断Promise

注意这里是中断而不是终止,因为 Promise 无法终止,这个中断的意思是:在合适的时候,把 pending 状态的 promise 给 reject 掉。例如一个常见的应用场景就是希望给网络请求设置超时时间,一旦超时就就中断,我们这里用定时器模拟一个网络请求,随机 3 秒之内返回。

function timeoutWrapper(p, timeout = 2000) {
  const wait = new Promise((resolve, reject) => {
    setTimeout(() => {
      reject('请求超时')
    }, timeout)
  })
  return Promise.race([p, wait])
}

8. Object.create 和 new 有什么区别?

js中创建对象的方式一般有两种Object.create和new

const Base = function(){};
const o1 = Object.create(Base);
const o2 = new Base();

在讲述两者区别之前,我们需要知道:

  • 构造函数Foo的原型属性Foo.prototype指向了原型对象。
  • 原型对象保存着实例共享的方法,有一个指针constructor指回构造函数。
  • js中只有函数有 prototype 属性,所有的对象只有 proto 隐式属性。

那这样到底有什么不一样呢?

Object.create

先来看看 Object.create 的实现方式

Object.create =  function (o) {
    var F = function () {};
    F.prototype = o;
    return new F();
};

可以看出来。Object.create是内部定义一个对象,并且让F.prototype对象 赋值为引进的对象/函数 o,并return出一个新的对象。

new

再看看 const o2 = new Base() 的时候,new做了什么。

var o1 = new Object();
o1.[[Prototype]] = Base.prototype;
Base.call(o1);

new做法是新建一个obj对象o1,并且让o1的__proto__指向了Base.prototype对象。并且使用 call 进行强转作用环境。从而实现了实例的创建。

区别

//看似是一样的。我们对原来的代码进行改进一下。
var Base = function () {
    this.a = 2
}
var o1 = new Base();
var o2 = Object.create(Base);
console.log(o1.a); // 2
console.log(o2.a); // undefined

可以看到Object.create 失去了原来对象的属性的访问。

再进行下改造:

var Base = function () {
    this.a = 2
}
Base.prototype.a = 3;
var o1 = new Base();
var o2 = Object.create(Base);
console.log(o1.a); // 2
console.log(o2.a); // undefined

小结
在这里插入图片描述

9. 箭头函数和普通函数有啥区别?箭头函数能当构造函数吗?

什么是箭头函数?
ES6中允许使用箭头=>来定义箭头函数,具体语法,我们来看一个简单的例子:

// 箭头函数
let fun = (name) => {
    // 函数体
    return `Hello ${name} !`;
};

// 等同于
let fun = function (name) {
    // 函数体
    return `Hello ${name} !`;
};

可以看出,定义箭头函在数语法上要比普通函数简洁得多。箭头函数省去了function关键字,采用箭头=>来定义函数。函数的参数放在=>前面的括号中,函数体跟在=>后的花括号中。

箭头函数与普通函数的区别

1、语法更加简洁、清晰
从上面的基本语法示例中可以看出,箭头函数的定义要比普通函数定义简洁、清晰得多,很快捷。

2、箭头函数不会创建自己的this(重要!!深入理解!!)
我们先来看看MDN上对箭头函数this的解释。

箭头函数不会创建自己的this,所以它没有自己的this,它只会从自己的作用域链的上一层继承this。

箭头函数没有自己的this,它会捕获自己在定义时(注意,是定义时,不是调用时)所处的外层执行环境的this,并继承这个this值。所以,箭头函数中this的指向在它被定义的时候就已经确定了,之后永远不会改变。

3、箭头函数继承而来的this指向永远不变(重要!!深入理解!!)
上面的例子,就完全可以说明箭头函数继承而来的this指向永远不变。对象obj的方法b是使用箭头函数定义的,这个函数中的this就永远指向它定义时所处的全局执行环境中的this,即便这个函数是作为对象obj的方法调用,this依旧指向Window对象。

4、.call()/.apply()/.bind()无法改变箭头函数中this的指向
.call()/.apply()/.bind()方法可以用来动态修改函数执行时this的指向,但由于箭头函数的this定义时就已经确定且永远不会改变。所以使用这些方法永远也改变不了箭头函数this的指向,虽然这么做代码不会报错。

5、箭头函数不能作为构造函数使用
我们先了解一下构造函数的new都做了些什么?简单来说,分为四步:
① JS内部首先会先生成一个对象;
② 再把函数中的this指向该对象;
③ 然后执行构造函数中的语句;
④ 最终返回该对象实例。
但是!!因为箭头函数没有自己的this,它的this其实是继承了外层执行环境中的this,且this指向永远不会随在哪里调用、被谁调用而改变,所以箭头函数不能作为构造函数使用,或者说构造函数不能定义成箭头函数,否则用new调用时会报错!

6、箭头函数没有自己的arguments
箭头函数没有自己的arguments对象。在箭头函数中访问arguments实际上获得的是外层局部(函数)执行环境中的值。

7、箭头函数没有原型prototype

let sayHi = () => {
    console.log('Hello World !')
};
console.log(sayHi.prototype); // undefined

8、箭头函数不能用作Generator函数,不能使用yeild关键字

10. async/await 和 Promise 有什么关系?

Promise

Promise 对象是一个代理对象(代理一个值),被代理的值在Promise对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers)。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的promise对象

async/await

es2017的新语法,async/await就是generator + promise的语法糖

async/await 和 Promise 的关系非常的巧妙,await必须在async内使用,并装饰一个Promise对象,async返回的也是一个Promise对象。

async/await中的return/throw会代理自己返回的Promise的resolve/reject,而一个Promise的resolve/reject会使得await得到返回值或抛出异常。

  • 如果方法内无await节点

return 一个字面量则会得到一个{PromiseStatus: resolved}的Promise。
throw 一个Error则会得到一个{PromiseStatus: rejected}的Promise。

  • 如果方法内有await节点

async会返回一个{PromiseStatus: pending}的Promise(发生切换,异步等待Promise的执行结果)。
Promise的resolve会使得await的代码节点获得相应的返回结果,并继续向下执行。
Promise的reject 会使得await的代码节点自动抛出相应的异常,终止向下继续执行。

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

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

相关文章

单链表--C语言版(从0开始,超详细解析,小白一看就会)

目录 一、前言 &#x1f34e; 为什么要学习链表 &#x1f4a6;顺序表有缺陷 &#x1f4a6; 优化方案&#xff1a;链表 二、链表详解 &#x1f350;链表的概念 &#x1f349;链表的结构组成&#xff1a;节点 &#x1f353;链表节点的连接&#xff08;逻辑结构与物理结构的区…

java spring注解方式 实现基本类型属性注入

之前 我们看了几个注入属性的注解 但他们都是注入对象类型的 那么 下面我们就看一个 给基本属性注入值的注解 value 我们直接代码快速演示一下 创建一个项目 然后引入 spring 所需要的依赖 然后在src下创建包 Bean 在 Bean目录下创建一个包 叫 UserData 然后在src下创建 bean…

leaflet 上传geojson文件,在地图上显示图形(示例代码053)

第053个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet示例中上传geojson文件,通过L.geojson解析,在地图上显示图形。 直接复制下面的 vue+openlayers源代码,操作2分钟即可运行实现效果 文章目录 示例效果配置方式示例源代码(共97行)相关API参考:专栏目标…

微服务项目【mybatis-plus与微服务注册】

Mybatis与微服务注册 一、SpringBoot整合MybatisPlus 创建自动生成代码子模块 基于maven方式创建子模块zmall-generator&#xff0c;用于结合mybatis-plus生成代码。 在公共模块zmall-common中注释掉mybatis的依赖引入&#xff0c;改换成mybatis-plus依赖引入 <!-- myba…

【大数据Hadoop】Hadoop 3.x 新特性总览

Hadoop 3.x 新特性剖析系列11. 概述2. 内容2.1 JDK2.2 EC技术2.3 YARN的时间线V.2服务2.3.1 伸缩性2.3.2 可用性2.3.3 架构体系2.4 优化Hadoop Shell脚本2.5 重构Hadoop Client Jar包2.6 支持等待容器和分布式调度2.7 支持多个NameNode节点2.8 默认的服务端口被修改2.9 支持文件…

MAC Pro 安装 VS Code 配置 C/C++ 开发环境

目录 文章目录目录安装 VS Code配置 C/C 开发环境Hello World1、创建项目和源码2、编译运行3、调试C/C configuration安装 VS Code 下载安装包&#xff1a;https://code.visualstudio.com/Download解压并将文件放入 “应用程序"。 配置 C/C 开发环境 官方文档&#xff1…

linux 服务器线上问题故障排查

一 线上故障排查概述 1.1 概述 线上故障排查一般从cpu,磁盘,内存,网络这4个方面入手; 二 磁盘的排查 2.1 磁盘排查 1.使用 df -hl 命令来查看磁盘使用情况 2.从读写性能排查:iostat -d -k -x命令来进行分析 最后一列%util可以看到每块磁盘写入的程度,而rrqpm/s以及…

C语言 | 预处理知识详解 #预处理指令有哪些?他们如何使用?宏和函数有哪些区别?...#

文章目录前言预定义符号介绍预处理指令#define#define替换规则预处理指令 #undef宏和函数的对比宏和函数的对比图命名约定命令行定义条件编译预处理指令 #include嵌套文件包含其他预处理指令写在最后前言 上篇文章介绍了一个程序运行的 编译与链接 &#xff0c;其中编译阶段有个…

python+django在线教学网上授课系统vue

随着科技的进步&#xff0c;互联网已经开始慢慢渗透到我们的生活和学习中&#xff0c;并且在各个领域占据着越来越重要的部分&#xff0c;很多传统的行业都将面临着巨大的挑战&#xff0c;包括学习也不例外。现在学习竞争越来越激烈&#xff0c;人才的需求量越来越大&#xff0…

Java高级-集合-Collection部分

本篇讲解java集合 集合 集合框架的概述 集合、数组都是对多个数据进行存储操作的结构&#xff0c;简称Java容器。 说明&#xff1a;此时的存储&#xff0c;主要指的是内存层面的存储&#xff0c;不涉及到持久化的存储&#xff08;.txt,.jpg,.avi&#xff0c;数据库中&#xf…

Java面试——MyBatis相关知识

目录 1.什么是MyBatis 2.MyBatis优缺点 3.MyBatis工作原理 4.MyBatis缓存模式 5.MyBatis代码相关问题 6.MyBatis和hibernate区别 1.什么是MyBatis MyBatis是一个半ORM持久层框架&#xff08;对象关系映射&#xff09;&#xff0c;基于JDBC进行封装&#xff0c;使得开发者…

【Python实战案例】Python3网络爬虫:“可惜你不看火影,也不明白这个视频的分量......”m3u8视频下载,那些事儿~

前言 哈喽&#xff01;上午好嘞&#xff0c;各位小可爱们&#xff01;有没有等着急了呀~ 由于最近一直在学习新的内容&#xff0c;所以耽搁了一下下&#xff0c;抱歉.jpg 双手合十。 所有文章完整的素材源码都在&#x1f447;&#x1f447; 粉丝白嫖源码福利&#xff0c;请移…

蓝海创意云获苏州电信2022年度“云业务优秀合作方”表彰

2月8日&#xff0c;中国电信苏州分公司召开产业数字化生态合作峰会&#xff0c;围绕“力量源于团结 奋斗创造奇迹”主题&#xff0c;凝聚合作伙伴合力&#xff0c;构建共生共赢的产业生态&#xff0c;蓝海创意云作为合作企业代表应邀出席峰会。会上&#xff0c;蓝海创意云荣获峰…

在阿里干了8年测试的表哥放假回来了,聊完之后大彻大悟

表哥是阿里某个项目组的测试开发&#xff0c;今年过年提前半个月放假回来了&#xff0c;一见面就给我们几个弟弟妹妹一人拿了部iPhone13pm。这一出手属实是阔绰&#xff0c;想想他的工作单位&#xff0c;也许对于他来说三四万也就是半个月工资而已。想想我那个小公司&#xff0…

第七节 平台设备驱动

在之前的字符设备程序中驱动程序&#xff0c;我们只要调用open() 函数打开了相应的设备文件&#xff0c;就可以使用read()/write() 函数&#xff0c;通过file_operations 这个文件操作接口来进行硬件的控制。这种驱动开发方式简单直观&#xff0c;但是从软件设计的角度看&#…

【Linux】操作系统进程概念

文章目录1. 冯诺依曼体系结构2. 操作系统3. 进程进程的基本概念查看进程和杀死进程父进程和子进程通过系统调用创建子进程1. 冯诺依曼体系结构 冯诺依曼结构也称普林斯顿结构&#xff0c;是一种将程序指令存储器和数据存储器合并在一起的存储器结构。数学家冯诺依曼提出了计算…

适配器模式(Adapter Pattern)

1.什么是适配器模式&#xff1f; 适配器模式&#xff08;Adapter Pattern&#xff09;是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式&#xff0c;它结合了两个独立接口的功能。 这种模式涉及到一个单一的类&#xff0c;该类负责加入独立的或不兼容的接…

浅谈现代GNSS模拟中的软件定义架构

随着技术的迭代更新&#xff0c;GPS/GNSS模拟技术也在不断发展进步。在过去&#xff0c;想要进行GNSS仿真基本上只有一种选择&#xff1a;使用固定式或分配式的硬件进行模拟。而如今&#xff0c;带来颠覆性创新的新型软件定义架构正在迅速取代传统的定制架构&#xff0c;这种独…

7款应用最广泛的 Linux 桌面环境

多样性应该是 Linux 最好的特性之一&#xff0c;用户可以不断尝试各种喜欢和新鲜玩法与花样&#xff0c;并从中找出最适合自己的应用。无论你是 Linux 新人还是老鸟&#xff0c;层出不穷的应用和桌面环境可能都会让我们应接不暇&#xff0c;特别是尝试不同的 Linux 桌面环境&am…

基于微信小程序的国产动漫论坛小程序

文末联系获取源码 开发语言&#xff1a;Java 框架&#xff1a;ssm JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7/8.0 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.3.9 浏览器…