JavaScript:作用域变量回收

JavaScript:作用域&变量回收

    • 局部作用域
      • 函数作用域
      • 块作用域
    • 全局作用域
    • 作用域链
    • 变量在浏览器模型中的位置
      • 浏览器模型
      • 全局变量的产生情况
      • 直接赋值全局对象与var全局对象的区别
    • 垃圾回收机制
      • 引用计数法
      • 标记清除法
    • 闭包
    • 变量提升&函数提升


作用域规定了变量能够被访问的范围,离开这个范围后,变量就无法访问。
在JavaScript中,作用域被分为局部作用域与全局作用域,本博客会简单为大家讲解作用域的基本规则后,深入拓展作用域的机制以及技巧。

局部作用域

函数作用域

函数作用域就是指:只能在函数内部访问的变量,外部无法直接访问的变量。
比如:

  function counter(x, y) {const a = x + yconsole.log(a) // 18}counter(10, 8)console.log(a)// 报错

在以上代码中,a变量在函数内部声明,等到出了函数再访问这个a,那么a就无法被找到了,最后会发生报错。
这是因为:
当一个函数被调用,其会创建自己的变量,当这个函数执行结束,其会销毁内部产生的变量,避免浪费内存

那么在函数内部声明的变量,出了函数就一定无法访问吗?
答案是不一定的,首先变量有三种定义形式:let/const/var,前两者是局部变量,var则是全局变量。:但是在函数中,let/const/var三者声明的变量在外部都不能访问
在函数中,还有一种声明变量的方式,就是直接使用没有声明的过的变量:

  function counter(x, y) {a = x + yconsole.log(a) // 18}counter(10, 8)console.log(a)// 正常

在上述代码中,a变量没有使用let/const/var三者之一声明,而且外部也没有a这个变量。此时,a变量不仅可以正常使用,而且可以被函数的外部访问,不会被销毁。
其根本原因是:如果一个变量不声明直接赋值(外部作用域也没有声明过),那么这个变量就会被直接挂在window对象下面,作为window对象的属性之一,根据标记清除法,这个变量不会被回收。如果你看不懂这段话也没关系,我们后面会说明标记清除法的机制。

到此,我们应该知晓以下重点:

  1. 函数内部声明的变量,在函数外部无法被访问
  2. 函数内部没有声明直接使用的变量,可以在外部访问
  3. 函数的参数也是函数内部的局部变量
  4. 不同函数内部声明的变量无法互相访问
  5. 函数执行完毕后,函数内部的变量实际被清空了

块作用域

JavaScript中使用{}包裹的代码称为代码块,代码内部声明的变量外部有可能无法访问。

  • 直接创建块级作用域
  {let age = 18;console.log(age); // 正常}// 超出了 age 的作用域console.log(age) // 报错
  • if 内部的块级作用域
  let flag = true;if(flag) {let str = 'hello world!'console.log(str); // 正常}// 超出了 age 的作用域console.log(str); // 报错
  • for内部的块级作用域
  for(let t = 1; t <= 6; t++) {console.log(t); // 正常}// 超出了 t 的作用域console.log(t); // 报错

还有非常多种方式会创建块级作用域,这里就不一一列举了。
那么我刚刚标红了有可能两个字,什么情况下在块级作用域声明的变量在外部可以访问呢?
其中一种情况函数作用域是一样的:没有声明就直接赋值的变量
这里不再做展示了,本博客后续会深入了解这个问题。

还有一种情况就是,在块级作用域内用var声明的变量

在早期的JavaScript中,并不存在letconst,也不存在块级作用域。当时的变量统一用var声明,所以后续推出的块作用域对var并没有影响。但是函数作用域是JavaScript早期就存在的概念,所以在上述函数作用域中,var定义的变量在函数外部也不能访问。
这也是此处要将块级作用域和函数作用域区分讲解的重要原因。有不少人认为函数也有{},所以其和块级作用域是一致的,但实际上并不是。由于历史问题,var同一时期的函数作用域会限制var,而后续出现的块级作用域并不会限制var

至此,块级作用域我们应知晓以下重点:

  1. let / const 声明的变量会产生块作用域,var 不会产生块作用域
  2. 不同块级作用域之间的变量无法互相访问
  3. 在块级作用域中没有声明直接赋值的变量,外部可以访问

全局作用域

<script> 标签和 .js 文件的【最外层】就是所谓的全局作用域,在此声明的变量在函数内部也可以被访问。

<script>// 此处是全局作用域function fn() {// 此处为局部作用域}// 此处为全局作用域
</script>

全局作用域中声明的变量,任何其它作用域都可以被访问,如下代码所示:

<script>// 全局变量 nameconst name = '小明'// 函数作用域中访问全局function sayHi() {// 此处为局部console.log('你好' + name)}// 全局变量 flag 和 xconst flag = truelet x = 10// 块作用域中访问全局if(flag) {let y = 5console.log(x + y) // x 是全局的}
</script>

那么什么情况会产生全局作用域呢?

  1. 在全局作用域let/const/var三者之一声明的变量
  2. 在块级作用域var声明的变量
  3. 未使用任何关键字声明的变量

注意标红的作用域范围:(超级大总结)

在第一条中:在函数作用域与块级作用域用let/const/var三者之一声明的变量不一定是全局变量,只有在全局作用域声明的才是。


在第二条中:块级作用域用var声明的变量是全局变量,注意不包括函数作用域


在第三条中:未使用任何关键字声明的变量,在任何地方都是全局变量。即在全局/块级/函数作用域中,未声明直接赋值的变量也是全局变量。


作用域链

在解释什么是作用域链前先来看一段代码:

<script>// 全局作用域let a = 1let b = 2function f() {let c// 局部作用域function g() {let d = 'yo'//局部作用域}}
</script>

函数内部允许创建新的函数,f 函数内部创建的新函数 g,会产生新的函数作用域,由此可知作用域产生了嵌套的关系。

如下图所示,父子关系的作用域关联在一起形成了链状的结构,作用域链的名字也由此而来。
在这里插入图片描述

作用域链本质上是底层的变量查找机制,在函数被执行时,会优先查找当前函数作用域中查找变量,如果当前作用域查找不到则会依次逐级查找父级作用域直到全局作用域,如下代码所示:

<script>// 全局作用域let a = 1;let b = 2;// 局部作用域function f() {let c = 9;let a = 10;console.log(a); // 10console.log(d); // 报错// 局部作用域function g() {let d = 6;console.log(b); // 2 或 20}// 调用 g 函数g();}f();
</script>

上述代码中有三个输出语句,解析:

console.log(a)在输出a时,处于函数f()环境下,此时函数f()作用域中存在a = 10,于是输出了10


console.log(d)在输出d时,处于函数f()环境下,此时函数f()作用域中不存在d,于是其向上一级作用域找,即全局作用域;全局作用域中只存在ab,不存在d,所以最后找不到d,发生报错


console.log(b)在输出b时,处于函数g()环境下,此时函数g()作用域中不存在b,于是其向上一级作用域找,即f()函数作用域;f()函数作用域中不存在b = 2,于是其向上一级作用域找,即全局作用域;全局作用域中只存在b,于是最后输出2。

总结:

  1. 嵌套关系的作用域串联起来形成了作用域链
  2. 相同作用域链中按着从小到大的规则查找变量
  3. 子作用域能够访问父作用域,父级作用域无法访问子级作用域

变量在浏览器模型中的位置

现在就是揭晓前面留下的疑惑的时间了,理解这一块后,你就可以理解前面的全局变量的产生原因了。

浏览器模型

浏览器对象模型 (BrowserObjectModel) BOM (Browser Object Model) 是指浏览器对象模型,是用于描述这种对象与对象之间层次关系的模型,浏览器对象模型提供了独立于内容的、可以与浏览器窗口进行互动的对象结构。 BOM由多个对象组成,其中代表浏览器窗口的Window对象是BOM的顶层对象,其他对象都是该对象的子对象。

在JavaScript中,一切都是对象,包括你创建的变量,都会被包装为对象。而在JavaScript中,window是最顶级的对象,它处于对象的顶点。
在这里插入图片描述
documentJavaScript中最常用的对象,因为其是文档树的根节点,其分支包含着所有HTML的元素。但是document并不是JavaScript中最高级的对象,而是windowwindow有多高级呢?
由于window是浏览器对象模型(BOM)的根节点,所以所有的对象都是window的后代节点,甚至你创建的变量,也会放在window对象里。
所以window作为一切的根,那么就可以默认存在,于是它就省略了。就好比你在填写地址的时候,绝对不会从地球开始:地球,中国,xx省…,因为人类都是默认处于地球环境中,所以我们会把地球省略。

也许你知道,var创建的变量是全局变量,letconst创建的变量是局部变量,这又是为什么?

这是因为,var创建的对象,会被直接放在window下面,在任何页面都能通过window对象拿到该变量
证明:
在这里插入图片描述
可以看到,我们用var创建的变量直接处于window对象下了,而letconst创建的变量没有。


全局变量的产生情况

还记得我之前总结的产生全局变量的情况吗:

  1. 在全局作用域let/const/var三者之一声明的变量
  2. 在块级作用域var声明的变量
  3. 未使用任何关键字声明的变量

接下来我我们分别检测以下哪一些情况下,变量会被放在window下方,作为window的亲儿子。
检测方法:一个变量a,如果a === window.a那么说明这个变量是直接处于window下方作为window的亲儿子。
测试代码:

        let a = 1;//在全局范围用let声明的全局变量const b = 2;//在全局范围用const声明的全局变量var c = 3;//在全局范围用var声明的全局变量{var d = 4;//块作用域内通过var声明的全局变量e = 5//块作用域内不声明的全局变量}function fn(){f = 6;//函数作用域内不声明的全局变量var g = 7;///函数作用域内通过var声明的局部变量console.log("函数作用域内通过var声明的局部变量",g === window.g);}fn();console.log("在全局范围用let声明的全局变量",a === window.a);console.log("在全局范围用const声明的全局变量",b === window.b);console.log("在全局范围用var声明的全局变量",c === window.c);console.log("块作用域内通过var声明的全局变量",d === window.d);console.log("块作用域内不声明的全局变量",e === window.e);console.log("函数作用域内不声明的全局变量",f === window.f);

测试结果:
在这里插入图片描述
注意,我在此额外塞入了一个局部变量,来说明在函数作用域内部,为什么var定义的变量不是全局变量。

首先看到三条var定义的变量:

其中,在块作用域内和在全局范围内,其声明的变量都被直接放在了window下方,即输出结果为true。而当var声明的变量处于函数作用域中时,变量就不处于window下方了,所以此时的var在函数内部声明的变量不是全局变量

再看到最后两条,即不声明的变量

当我们不声明一个变量直接使用,不论其处于何处,都会挂在window底下,由于window可以省略,所以你在写出a = 1这样的语句的时候,相当于写的是:window.a = 1。这样一来,没有声明的变量的赋值过程,就相当于是window对象添加了一个属性的过程,所以是符合语法的,而window是顶级对象,所以最后得到的变量也是全局变量

最后看到由letconst创建的全局变量:

它们创建的变量不会作为window的对象和属性,在MDN解释中:letconst会将作用域限制在当前变量所处的作用域中。
也就是说letconst定义变量时就在全局环境中定义,那么此时这些变量也就是全局变量了。为什么呢?
还记得我们之前讲的作用域链吗,通过var定义的全局变量,或者是不声明直接定义的变量,它们的访问都是通过window这个顶级对象。
而通过letcosnt定义的全局对象,它们由于本身就处于全局作用域中,当其他的块级/函数作用域找不到变量时,就会一层层往上查找,直到找到全局作用域。通过作用域链,在全局定义的变量也可以被任何地方查找到,所以此时letconst创建的也是全局变量了。


直接赋值全局对象与var全局对象的区别

  • 区别一

全局变量不能通过delete删除,而window属性上定义的变量可以通过delete删除:

var num1=123;
window.num2=456;
//删除num2可以,但是不可以删除第一个
delete num1;
delete num2;
console.log(num1);  //123
console.log(num2);  //num2 is not defined


全局变量num1之所以不能通过delete删除,是因为通过var语句添加的全局变量有一个configurable属性,其默认值为false,如下,所以这样定义的属性不可以通过delete删除。

var num1=123;
window.num2=456;
//打印对象中属性的详情
var t1 = Object.getOwnPropertyDescriptor(window, "num1");
console.log(t1)
//Object {value: 123, writable: true, enumerable: true, configurable: false}
var t2 = Object.getOwnPropertyDescriptor(window, 'num2');
console.log(t2)
//Object {value: 456, writable: true, enumerable: true, configurable: true}

  • 区别二

尝试访问未声明的变量会报错,xxx is not defined。 但是通过查询window查询,可以知道某个可能未声明的变量是否存在,不会报错,只会显示undefined。

console.log(num1); // undefined ,因为var会提升声明
var num1=123;
console.log(num2); // ReferenceError: a is not defined 因为无这个变量存在
window.num2=456;

这一点可以用预解析解释,var声明的变量会提升声明到顶部。(本博客后面细讲)

  • 区别三

在函数中使用var定义的变量是局部变量。 有时想要在外部也访问到函数里面的变量,就需要定义window对象属性。

function () {var num1 = 123;window.num2 = 456;
}
console.log(num1); //num1 is not defined
console.log(num2); //456

垃圾回收机制

什么是垃圾回收机制
JavaScript中内存的分配和回收都是自动完成的,内存在不使用时会被垃圾回收器自动回收,正因为垃圾回收器的存在,许多人并不关心JavaScript的内存问题。但是如果不了解这个问题,就容易导致内存泄漏,不使用的内存无法立即释放。
内存生命周期
JavaScript环境中的分配的内存,有如下生命周期:

  1. 内存分配: 当我们声明变量,函数,对象的时候,系统会自动为它们分配内存
  2. 内存使用: 即读写内存,比如调用函数,读取数据,变量赋值等等
  3. 内存回收: 当JavaScript检测到某一个变量不再被使用,垃圾回收器就会自动回收掉这一块内存

全局变量:在关闭网页之前不会被回收掉的内存。
局部变量:在关闭网页前,有可能被垃圾回收器自动回收的内存。

那么JavaScript是如何检测一块内存是否有用,从而判断是否要将其回收的呢?
在这方面,不同的浏览器有不同的处理方式,主要为以下两种:

引用计数法

这是IE浏览器采用的方法,其会对对象检测是否有指向它的引用,没有引用就回收对象。

这里的引用是指:有几个变量指向这个对象。
比如以下代码:

let arr1 = [1, 3, 5, 7, 9];
let arr2 = arr1;
arr1 = null;
arr2 = null;

当我们写出arr1 = [1, 3, 5, 7, 9]时,此时数组[1, 3, 5, 7, 9]就被一个名为arr1的变量引用了,此时数组[1, 3, 5, 7, 9]引用次数为1。


当执行到第二条语句:let arr2 = arr1相当于数组[1, 3, 5, 7, 9]同时被arr1arr2引用了,此时数组[1, 3, 5, 7, 9]引用次数为2。


当执行到第三条语句:arr1 = null,此时数组[1, 3, 5, 7, 9]的引用次数减少了一个,但是引用次数不为0,JavaScript不会将其回收。


当执行到第四条语句:arr2 = null,此时数组[1, 3, 5, 7, 9]的引用次数减少了一个,引用次数不为0,JavaScript将其回收。

可以看出,这是一个简单有效的方法,但是其有一个非常大的缺陷,那就是对象的相互引用:
分析代码:

let person1 = {name: "小明",gender: "man"
}let person2 = {name: "张三",gender: "man"
}person1.friend = person2;
person2.friend = person1;person1 = null;
person2 = null;

请问通过引用计数法,以上person1person2被回收了吗?
答案是没有的,解析一下:

创建了person1person2{name: "小明",gender: "man"}person1引用了,引用次数为1;{name: "张三",gender: "man"}person2引用了,引用次数为1。


当执行person1.friend = person2; person2.friend = person1;语句后,{name: "小明",gender: "man"}person1person2.friend引用了,引用次数为2;{name: "张三",gender: "man"}person2person1.friend引用了,引用次数为2;


当执行person1 = null; person2 = null;语句后,{name: "小明",gender: "man"}person2.friend引用了,引用次数为1;{name: "张三",gender: "man"}person1.friend引用了,引用次数为1;

可以发现,此时他们两个对象互相保留了一个引用,导致引用次数不为0。而此时person1只能通过person2访问,而person2只能通过person1访问,形成一个死循环,用户已经无法使用这两块内存了,按理来说应该被释放掉,但是这个方法任务其被引用了,就是还有用,所以没有将其释放。

所以现代浏览器已经不采用这种方法了,下面一种方法解决了这个问题:


标记清除法

标记清除法从全局出发,即JavaScript的顶级对象window向下查找节点,只要这个对象可以被查找到,那么它就是可以访问的;如果这个对象不能从window出发找到,那么它就是不再使用的内存,JavaScript会将其释放掉。(如果你不知道什么是window对象,可以参考这个博客:[JavaScript:BOM操作])

如下图所示:
在这里插入图片描述
此处的gobal(全局对象)即window对象。它从根节点出发查找,寻找所有节点,只要某个对象不在这个window下方,就将其回收。

我们分析同一段代码:

let person1 = {name: "小明",gender: "man"
}let person2 = {name: "张三",gender: "man"
}person1.friend = person2;
person2.friend = person1;person1 = null;
person2 = null;

在创建person1person2其是window下的全局变量(因为直接在全局作用域中使用let定义),它会被挂在window底下,在将两个person置空之前,其指向如下:
在这里插入图片描述

在上图中,由于两个对象被person指向了,而person在window内部,所以从window出发可以查找到两个对象的内存空间,不会清除这两块内存。


当执行person1 = null; person2 = null;语句后,其标记图如下:

在这里插入图片描述
此时虽然两个内存相互指向了,但是从window出发无法找到,两块空间就会被销毁。

更形象的如下图:
在这里插入图片描述


闭包

定义:

一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域。在 JavaScript 中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。

重点:闭包让你可以在一个内层函数中访问到其外层函数的作用域

如果你无法理解以上语句也没有关系,接下来我为大家解析一段代码:

function outer(){let a = 0;function inner() {a++;console.log(a);}return inner;
}let fun = outer();
fun();//输出1
fun();//输出2

以上代码中,出现了三个函数,分别是:outer()inner()fun()接下来我为大家解析闭包的详细机制:

首先,我们需要一个外层函数:function outer()


然后创建一个内层函数:function inner()


内层函数需要调用外层函数的变量a++;


给外层函数设置返回值,返回值为内层函数的函数名return inner;


调用外层函数,并用一个变量接收这个外层函数的返回值let fun = outer();


闭包完成!

我们调用这个函数试试:
在这里插入图片描述
可以看到,我们居然可以在没有调用outer函数的情况下使用到outer函数内部的a变量。而且从每次a的值都增加1可以看出,a从始至终没有被销毁过,按理来说一个变量出了函数就应该被销毁了,这是为什么?
这就是闭包的效果。
我们来分析一下闭包的结构:

为什么外层函数的返回值是内层函数名:
外层函数的返回值是内层函数的函数名inner,那么此时fun接收到的是什么呢?
此时fun === inner,也就是说fun() === inner(),所以我们调用fun()其实就是在调用inner()。因为inner在outer函数的内部,被限制在了函数作用域中,此时我们无法通过外部调用inner函数,所以我们讲inner作为返回值返回给了外部,让外部可以调用inner这个函数。


为什么要在内层函数调用外层函数的变量:
这就涉及到刚才讲的垃圾回收机制了。
按理来说,a这个变量会在outer函数调用完毕时销毁,但是它没有。根据标记清除法,说明此时window对象是可以找到a变量的,我带大家还原一下路线:
fun是指向inner函数的,而inner函数内部有a变量,那么此时a变量就会指向外层函数outer的a变量。即:
window->... -> fun -> inner -> a(innre的a) -> a(outer的a)
就是这一条线路,保证了a不会被销毁,每次调用,a都会保留上一次的值。


为什么不能在内层函数定义这个变量:
如果我们讲a这个变量定义在inner内部,那么当每次inner调用结束时,没有inner以外的区域调用a这个值,a就会被销毁。
而当我们利用内层函数调用外层函数的变量,当外层函数outer想要销毁a这个变量,就会发现a变量居然被另外一个函数使用了,也就是被自己以外的区域调用了,此时a就不满足被销毁的要求。

此处我们只通过作用域讲解闭包的原理,不讲解具体使用方法了。
关于闭包的使用,可以参考这一篇博客:[闭包的作用]


变量提升&函数提升

变量提升是JavaScript中比较奇怪的现象,它允许变量在声明之前访问(仅限于var定义的变量)。
请问以下代码输出结果是什么:

console.log(str + " world!");var str = "hello";

此代码的输出结果为:undefined world!
那么第一个问题就是:为什么没有报错???
这就涉及到了变量提升:
JavaScript在编译代码时,会把var定义的变量提到当前作用域的最顶端。但是其只提升声明过程,不提提升赋值过程
相当于刚刚的代码应该是这样运行的:

var str;
console.log(str + " world!");str = "hello";

而当定义一个变量但不给他赋值,其值就为undefined,所以最后输出结果为undefined world!
这就是变量提升。

此外,函数也有提升,函数在编译阶段,也会被提到当前作用域的最顶端
在变量提升时,只有声明会被提升,而函数也是如此,函数也只提升声明过程但是函数在声明过程就已经决定了其内部的语句,所以函数可以在作用域内的任何地方调用!!
比如以下代码:

fn(2, 3);function fn(x, y){return x + y;}

由于函数提升,其相当于如下代码:

function fn(x, y){return x + y;}
fn(2, 3);

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Zookeeper之Java客户端实战

ZooKeeper应用的开发主要通过Java客户端API去连接和操作ZooKeeper集群。可供选择的Java客户端API有&#xff1a; ZooKeeper官方的Java客户端API。第三方的Java客户端API&#xff0c;比如Curator。 接下来我们将逐一学习一下这两个java客户端是如何操作zookeeper的。 1. ZooKe…

[DAU-FI Net开源 | Dual Attention UNet+特征融合+Sobel和Canny等算子解决语义分割痛点]

文章目录 概要I Introduction小结 概要 提出的架构&#xff0c;双注意力U-Net与特征融合&#xff08;DAU-FI Net&#xff09;&#xff0c;解决了语义分割中的挑战&#xff0c;特别是在多类不平衡数据集上&#xff0c;这些数据集具有有限的样本。DAU-FI Net 整合了多尺度空间-通…

C#使用 OpenHardwareMonitor获取CPU或显卡温度、使用率、时钟频率相关方式

C# 去获取电脑相关的基础信息&#xff0c;还是需要借助 外部的库&#xff0c;我这边尝试了自己去实现它 网上有一些信息&#xff0c;但不太完整&#xff0c;都比较零碎&#xff0c;这边尽量将代码完整的去展示出来 OpenHardwareMonitor获取CPU的温度和频率需要管理员权限 在没…

opencv003图像裁剪(应用NumPy矩阵的切片)

这一部分相对于马上要学习的二值化是要更更更简单一些的&#xff0c;只需三行&#xff0c;便能在opencv上裁剪图像啦&#xff08;顺便云吸猫&#xff0c;太可爱了&#xff01;&#xff09; 出处见水印&#xff01; 1、复习图像的显示 前几天期末考试&#xff0c;太久没有看…

Unity中Shader的Reversed-Z(DirectX平台)

文章目录 前言一、在对裁剪坐标归一化设置NDC时&#xff0c;DirectX平台Z的特殊二、在图形计算器中&#xff0c;看一下Z值反转前后变化1、在图形计算器创建两个变量 n 和 f 分别 控制近裁剪面 和 远裁剪面2、带入公式得到齐次裁剪空间下Z值3、进行透视除法4、用 1 - Z 得出Z值反…

是否需要跟上鸿蒙(OpenHarmony)开发岗位热潮?

前言 自打华为2019年发布鸿蒙操作系统以来&#xff0c;网上各种声音百家争鸣。尤其是2023年发布会公布的鸿蒙4.0宣称不再支持Android&#xff0c;更激烈的讨论随之而来。 本文没有宏大的叙事&#xff0c;只有基于现实的考量。 通过本文&#xff0c;你将了解到&#xff1a; Har…

电脑如何屏幕录制?轻松录制高清视频

在当今信息化的时代&#xff0c;电脑已经成为工作和生活的重要工具。无论是在进行演示、教学还是记录重要操作步骤时&#xff0c;屏幕录制都是非常有用的。可是电脑如何屏幕录制呢&#xff1f;本篇文章将介绍三种常见的电脑屏幕录制方法&#xff0c;通过学习这些方法&#xff0…

【Pytorch】学习记录分享10——PyTorchTextCNN用于文本分类处理

【Pytorch】学习记录分享10——PyTorchTextCNN用于文本分类处理 1. TextCNN用于文本分类2. 代码实现 1. TextCNN用于文本分类 具体流程&#xff1a; 2. 代码实现 # coding: UTF-8 import torch import torch.nn as nn import torch.nn.functional as F import numpy as np…

《异常检测——从经典算法到深度学习》25 基于深度隔离林的异常检测算法

《异常检测——从经典算法到深度学习》 0 概论1 基于隔离森林的异常检测算法 2 基于LOF的异常检测算法3 基于One-Class SVM的异常检测算法4 基于高斯概率密度异常检测算法5 Opprentice——异常检测经典算法最终篇6 基于重构概率的 VAE 异常检测7 基于条件VAE异常检测8 Donut: …

案例086:基于微信小程序的影院选座系统

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;SSM JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder X 小程序…

【数字图像处理技术与应用】2023-2024上图像处理期中-云南农业大学

一、填空题&#xff08;每空2 分&#xff0c;共 30 分&#xff09; 1、图像就是3D 场景在 二维 平面上的影像&#xff0c;根据其存储方式和表现形式&#xff0c;可以将图像分为 模拟 图像和数字图像两大类&#xff1b; 2、在用计算机对数字图像处理中&#xff0c;常用一个 二…

计算机专业个人简历范文(8篇)

HR浏览一份简历也就25秒左右&#xff0c;如果你连「好简历」都没有&#xff0c;怎么能找到好工作呢&#xff1f; 如果你不懂得如何在简历上展示自己&#xff0c;或者觉得怎么改简历都不出彩&#xff0c;那请你一定仔细读完。 互联网运营个人简历范文> 男 22 本科 AI简历…

【JVM】一文掌握JVM垃圾回收机制

作为Java程序员,除了业务逻辑以外,随着更深入的了解,都无法避免的会接触到JVM以及垃圾回收相关知识。JVM调优是一个听起来很可怕,实际上很简单的事。 感到可怕,是因为垃圾回收相关机制都在JVM的C++层实现,我们在Java开发中看不见摸不着;而实际很简单,是因为它说到底,也…

分类预测 | Matlab实现DBO-SVM蜣螂算法优化支持向量机多特征分类预测

分类预测 | Matlab实现DBO-SVM蜣螂算法优化支持向量机多特征分类预测 目录 分类预测 | Matlab实现DBO-SVM蜣螂算法优化支持向量机多特征分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现DBO-SVM蜣螂算法优化支持向量机多特征分类预测&#xff08;完整…

wordpress在界面将站点地址直接修改为https导致上不去问题的解决办法

wordpress在界面将站点地址直接修改为https导致上不去问题的解决办法 #修改数据库yz_options

C#使用纯OpenCvSharp部署yolov8-pose姿态识别

【源码地址】 github地址&#xff1a;https://github.com/ultralytics/ultralytics 【算法介绍】 Yolov8-Pose算法是一种基于深度神经网络的目标检测算法&#xff0c;用于对人体姿势进行准确检测。该算法在Yolov8的基础上引入了姿势估计模块&#xff0c;通过联合检测和姿势…

C# Image Caption

目录 介绍 效果 模型 decoder_fc_nsc.onnx encoder.onnx 项目 代码 下载 C# Image Caption 介绍 地址&#xff1a;https://github.com/ruotianluo/ImageCaptioning.pytorch I decide to sync up this repo and self-critical.pytorch. (The old master is in old ma…

有道翻译web端 爬虫, js

以下内容写于2023-12-28, 原链接为:https://fanyi.youdao.com/index.html#/ 1 在输入框内输入hello world进行翻译,通过检查发出的网络请求可以看到翻译文字的http接口应该是: 2 复制下链接最后的路径,去js文件中搜索下: 可以看到这里是定义了一个函数B来做文字的翻译接口函数…

PHP序列化总结2--常见的魔术方法

魔术方法的概念 PHP的魔术方法是一种特殊的方法&#xff0c;用于覆盖PHP的默认操作。它们以双下划线&#xff08;__&#xff09;开头&#xff0c;后面跟着一些特定的字符串&#xff0c;如__construct()、__destruct()、__get()等。这些魔术方法在对象执行特定操作时被自动调用…

idea配置docker推送本地镜像到远程私有仓库

目录 1&#xff0c;搭建远程Docker 私有仓库 Docker registry 2&#xff0c;Windows10/11系统上安装Docker Desktop 3&#xff0c;idea 配置远程私有仓库地址 4&#xff0c;idea 配置Docker 5&#xff0c;idea在本地构建镜像 6&#xff0c;推送本地Docker镜像到远程 Dock…