闭包(闭包使用场景,闭包内存泄漏,js内存管理及垃圾回收)

2023-11-02

1.什么是闭包:

在认识闭包之前,我们先简单了解两个知识点:JavaScript 中的作用域和作用域链,JavaScript 中的垃圾回收,目的就是为了方便我们更容易理解闭包

(1)JavaScript 中的作用域和作用域链
作用域就是一个独立的地盘,让变量不会外泄、暴露出去,不同作用域下同名变量不会有冲突。如果在当前作用域中没有查到值,就会向上级作用域去查,直到查到全局作用域,这么一个查找过程形成的链条就叫做作用域链。

可以看一个简单的例子:

var a = 100
function F1() {
    var b = 200
    function F2() {
        var c = 300
        console.log(a) // 顺作用域链向父作用域找
        console.log(b) // 顺作用域链向父作用域找
        console.log(c) // 本作用域的变量
    }
    F2()
}
F1()

(2)JavaScript 中的垃圾回收
Javascript 执行环境会负责管理代码执行过程中使用的内存,其中就涉及到一个垃圾回收机制。垃圾收集器会定期(周期性)找出那些不再继续使用的变量,只要该变量不再使用了,就会被垃圾收集器回收,然后释放其内存。如果该变量还在使用,那么就不会被回收。

有了以上两点铺垫,接下来我们再来看什么是闭包:

刚刚接触闭包的时候,实在搞不清楚这个东西的概念,看了好多地方对闭包概念的描述,像JS 忍者秘籍中对闭包的定义是闭包允许函数访问并操作函数外部的变量。红宝书上对于闭包的定义是闭包是有权访问另外一个函数作用域中的变量的函数。MDN 对闭包的定义是闭包是那些能够访问自由变量的函数。这里的自由变量是外部函数作用域中的变量。

其实总结下来,闭包不是一个具体的技术,而是一种现象,是指在定义函数时,周围环境中的信息可以在函数中使用。换句话说,执行函数时,只要在函数中使用了外部的数据,就创建了闭包,而作用域链,正是实现闭包的手段。

只要在函数中使用了外部的数据,就创建了闭包?真的是这样么?我们举个简单的例子可以证明一下:

在这里插入图片描述

在上面的代码中,我们在函数 a 中定义了一个变量 i,然后打印这个 i 变量。对于 a 这个函数来讲,自己的函数作用域中存在 i 这个变量,所以我们在调试时可以看到 Local局部变量中存在变量 i。

我们将上面的代码稍作修改,如下图:

在这里插入图片描述

在上面的代码中,我们将声明 i 这个变量的动作放到了 a 函数外面,也就是说 a 函数在自己的作用域已经找不到这个 i 变量了,它会怎么办?学习了作用域链之后肯定知道,它会顺着作用域链一层一层往外找,也就是函数使用了外部的数据的情况,就会创建闭包。仔细观察调试区域,我们会发现此时的 i 就放在 Closure 里面的,从而证实了我们前面的说法。

其实“闭”可以理解为“封闭,闭环”,“包”可以理解为“一个类似于包裹的空间”,因此闭包实际上可以看作是一个封闭的空间,那么这个空间用来干啥呢?实际上就是用来存储变量的。

(3)那么一个函数下所有的变量声明都会被放入到闭包这个封闭的空间里面么?

当然不是,放不放入到闭包中,要看其他地方有没有对这个变量进行引用,举个例子:
在这里插入图片描述
在上面的代码中,函数 c 中一个变量都没有创建,却要打印 i、j、k 和 x,这些变量分别存在于 a、b 函数以及全局作用域中,因此创建了 3 个闭包,全局闭包里面存储了 i 的值,闭包 a 中存储了变量 j 和 k 的值,闭包 b 中存储了变量 x 的值。但是仔细观察,就会发现函数 b 中的 y 变量并没有被放在闭包中,所以要不要放入闭包取决于该变量有没有被引用。

2.自动生成闭包和手动制造闭包:

从上面我们发现一个新问题,那么多闭包,岂不是占用内存空间么?

实际上,如果是自动形成的闭包,是会被销毁掉的。例如:
在这里插入图片描述
运行结果如图:
在这里插入图片描述

在上面的代码中,我们在第 16 行尝试打印输出变量 x,显然这个时候是会报错的,在第 16 行打一个断点调试就可以清楚的看到,此时已经没有任何闭包存在,垃圾回收器会自动回收没有引用的变量,不会有任何内存占用的情况。

当然,这里指的是自动产生闭包的情况,关于闭包,有时需要根据需求手动的来制造一个闭包。来看下面的例子:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        function eat(){
            var food = "食物";
            console.log(food);
        }
        eat(); // 食物
        console.log(food); // 报错
    </script>
</body>
</html>

运行结果如图:
在这里插入图片描述

在上面的例子中,声明了一个名为 eat 的函数,并对它进行调用。JavaScript 引擎会创建一个 eat 函数的执行上下文,其中声明 food 变量并赋值。当该方法执行完后,上下文被销毁,food 变量也会跟着消失。这是因为 food 变量属于 eat 函数的局部变量,它作用于 eat 函数中,会随着 eat 的执行上下文创建而创建,销毁而销毁。所以当我们再次打印 food 变量时,就会报错,告诉我们该变量不存在。

但是我们将此代码稍作修改:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        function eat(){
            var food = '食物';
            return function(){
                console.log(food);
            }
        }
        var look = eat();
        look(); // 食物
    </script>
</body>
</html>

运行结果如图:

在这里插入图片描述

在这个例子中,eat 函数返回一个函数,并在这个内部函数中访问 food 这个局部变量。调用 eat 函数并将结果赋给 look 变量,这个 look 指向了 eat 函数中的内部函数,然后调用它,最终输出 food 的值。

为什么能访问到 food,是因为垃圾回收器只会回收没有被引用到的变量,只要该变量还被引用着的,垃圾回收器就不会回收此变量。在上面的示例中,照理说 eat 调用完毕 food 就应该被销毁掉,但是我们向外部返回了 eat 内部的匿名函数,而这个匿名函数有引用了 food,所以垃圾回收器是不会对其进行回收的,这也是为什么在外面调用这个匿名函数时,仍然能够打印出 food 变量的值。

至此,闭包的一个优点或者特点也就体现出来了,那就是:

  • 通过闭包可以让外部环境访问到函数内部的局部变量。
  • 通过闭包可以让局部变量持续保存下来,不随着它的上下文环境一起销毁。

通过此特性,可以解决一个全局变量污染的问题。早期在 JavaScript 还无法进行模块化的时候,在多人协作时,如果定义过多的全局变量 有可能造成全局变量命名冲突,使用闭包来解决功能对变量的调用将变量写到一个独立的空间里面,从而能够一定程度上解决全局变量污染的问题。

3.闭包经典使用场景:

(1) 函数作为返回值(最常用)

timeClouse5(){
  function fn(){
	var name="hello";
	return function(){
	  return name;
	}
  }
	var fnc = fn();
	console.log(fnc())     //hello
},

运行结果如图:

在这里插入图片描述

fn()的返回值是一个匿名函数,这个函数在fn()作用域内部,,所以它可以获取fn()作用域下变量name的值,将这个值作为返回值赋值给全局作用域下的变量fnc,实现了在全局变量下获取局部变量中变量的值

(2) IIFE(自执行函数)

	var n = '张三';
	(function p(){
	   console.log(n)
	})()
	/* 输出
	*   张三
	/ 

运行结果如图:

在这里插入图片描述

同样也是产生了闭包p(),存在 window下的引用 n。

(3) 定时器与闭包

写一个循环,让它按顺序打印出每次循环i的值

timeClouse1(){
        for(var i = 0; i < 5; i++){                             
            setTimeout(function(){
              console.log(i)
            }, 1000) 
        }       
      },

运行结果如图:

在这里插入图片描述

分析:按照预期它应该输出0 1 2 3 4,而结果它输出了5,这是为什么呢?由于js是单线程的,在执行for循环的时候定时器setTimeout被安排到任务队列中排队等待执行,而在等待过程中for循环就已经在执行,等到setTimeout可以执行的时候 ,for循环已经结束,所以打印出来五个5,那么我们为了实现预期效果应该怎么改这段代码呢?

方案一:利用ES6中的let,将var改成let,也可以实现预期效果

timeClouse1(){
        for(let i = 0; i < 5; i++){                             
            setTimeout(function(){
              console.log(i)
            }, 1000) 
        }       
      },

运行结果如图:

在这里插入图片描述
方案二: 引入闭包来保存变量i,将setTimeout放入到立即执行函数中

// 采用自执行函数解决
timeClouse2(){
  for(var i = 0; i < 5; i++){
    (function(j){                  //存在自执行函数
       setTimeout(function(){
         console.log(j)
       }, 1000) 
     })(i)
   }       
 },

运行结果如图:

在这里插入图片描述

(4) 防抖函数(业务场景中常用)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <input type="text" id="inputId" />
    <script>
        // 1.先定义一个业务处理函数
        function func(){
          console.log("接口请求");
        }

        // 2. 再定义一个防抖函数  (事件触发每次执行防抖函数,但不一定执行业务处理函数)
        // 2.1 防抖函数设置1秒延迟执行业务处理函数
        function fn(){
           setTimeout(func,1000)
        }



        // 2.2 每次事件发生都要触发防抖函数,防抖函数每次执行,这个timer都是新的,无法实现我想要的清除上一次的触发。
         function fn () {
           // timer 定义在哪里?
           let timer = null
           clearTimeout(timer)
           timer = setTimeout(func, 1000)
         }

        
        // 2.3关键点:这个timer如何维护?
        // 如果维护在fn()函数内部,则每次fn()函数执行(创建函数执行上下文),timer都是一个新的变量,则无法完成清除的逻辑操作
        // 需求:函数在第一次执行时就创建好这个timer,下次(以后)执行时一直都用这个“旧”的,这样就可以完成每次清除的逻辑了。
        // 实现这个需求就是使用闭包,在防抖函数外部继续包一个函数,叫防抖生成函数,在这个函数内定义timer,并且返回防抖函数。这样在防抖函数第一次创建的时候内部就有了timer变量。并且每次执行都是访问这个变量。不是创建新的变量。
        // 确认防抖函数在每次输入值时都会执行

        // 防抖生成函数
        function debounce() {
            let timer = null
            return function fn () {
                console.log('防抖函数执行')
                clearTimeout(timer)
	            timer = setTimeout(search, 1000)
            }
        }



        // 2.4 最终代码
        function debounce() {
            let timer = null
            return function () {
                console.log('防抖函数执行,清除旧的', timer)
                clearTimeout(timer)
	            timer = setTimeout(func, 1000)
                console.log('防抖函数执行,生成新的', timer)
            }
        }

        document.getElementById("inputId").oninput = debounce();
    </script>
</body>
</html>

运行效果如图:

在这里插入图片描述

4.Javascript的内存管理和垃圾回收:

为什么要学习内存管理以及垃圾回收算法?

JavaScript中的内存释放是自动的,释放的时机就是某些值(内存地址)不在使用了,JavaScript就会自动释放其占用的内存。其实大多数内存管理的问题都在这个阶段,在这里最艰难的任务就是找到那些不需要的变量。现在打高级语言都有自己垃圾回收机制,虽然现在的垃圾回收算法很多,但是也无法智能的回收所有的极端情况。

4.1 内存管理

不论什么样的编程语言,在代码执行的过程中都是需要给他分配内存的,有些编程语言(C、C++)需要我们自己手动管理内存,例如C语言,他们提供了内存管理的接口,比如malloc()用于分配所需的内存空间,free()用于释放之前所分配的内存空间。有的编程语言(Java、JavaScript)会自动帮我们管理内存

不论是手动还是自动,内存的管理都会有如下生命周期:
第一步:内存分配:例如当我们定义变量时,系统会自动为其分配内存
第二步:内存使用:在对变量进行读写时发生,(存放一些东西,比如对象,变量)
第三步:内存回收不需要使用时,对其进行释放

注意:后续画内存图补充相关原理

我们可以看一下内存泄漏的例子:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button class="create">创建一系列数组对象</button>
    <button class="destroy">销毁一系列数组对象</button>
    <script>
        function createArray() {
        	// V8引擎中小的数字占4个字节
            var arr = new Array(1024 * 1024).fill(100)

            function test() {
                console.log(arr);
            }

            return test
        }

        // 点击按钮
        var totalArr = []

        var createBtnE1 = document.querySelector(".create")
        var destroyBtnE1 = document.querySelector(".destroy")
        createBtnE1.onclick = function() {
            for(i = 0; i < 100; i++) {
                totalArr.push(createArray())
            }
        }

        destroyBtnE1.onclick = function() {
            totalArr = null
            // totalArr = []

        }

    </script>
</body>
</html>

第一步,我们先看用户未经过任何操作,内存的快照如下图:
在这里插入图片描述

此时未经过任何操作,发现js heap size中几乎保持平稳的趋势

第二步,我们点击按钮,创建数组,观察内存的快照如下图:

在这里插入图片描述
在这里插入图片描述

可以看到内存飙升,从大约一兆上升到四百多兆,很明显内存泄露了。

最后,我们点击销毁按钮,对没有进行自动释放的内存进行手动释放,效果图如下:

在这里插入图片描述

很明显,此时的内存经过我们手动释放后回到最初时的内存大小

4.2 垃圾回收及算法

JavaScript中的内存管理是自动的,在创建对象时会自动分配内存,当对象不在被引用或者不能从根上访问时,就会被当做垃圾给回收掉。

注意:JavaScript中的可达对象简单的说就是可以访问到的对象,不管是通过引用还是作用域链的方式,只要能访问到的就称之为可达对象。可达对象的可达是有一个标准的,就是必须从根上出发是否能被找到;这里的根可以理解为JavaScript中的全局变量对象,在浏览器环境中就是window、在Node环境中就是global

(1)为了更好的理解引用的概念,看下面这一段代码:

let person = {
  name: '一碗周',
}
let man = person
person = null

如下图:

在这里插入图片描述
根据上面那个图我们可以看到,最终这个{ name: ‘一碗周’ }是不会被当做垃圾给回收掉的,因为还具有一个引用。

(2)现在我们来理解一下可达对象,代码如下:

function groupObj(obj1, obj2) {
  obj1.next = obj2
  obj2.prev = obj1

  return {
    obj1,
    obj2,
  }
}
let obj = groupObj({ name: '大明' }, { name: '小明' })

调用groupObj()函数的的结果obj是一个包含两个对象的一个对象,其中obj.obj1的next属性指向obj.obj2;而obj.obj2的prev属性又指向obj.obj1。最终形成了一个无限套娃。

如下图:
在这里插入图片描述
(3)现在来看下面这段代码:

delete obj.obj1
delete obj.obj2.prev

如下图:
在这里插入图片描述

此时的obj1就被当做垃圾给回收了。

注意:GC是怎么知道哪些对象不再使用呢?

这里就要用到GC的实现以及对应的算法

常见的GC算法

(1)引用计数

引用计数算法的核心就是引用计数器 ,由于引用计数器的存在,也就导致该算法与其他GC算法有所差别。引用计数器的改变是在引用关系发生改变时就会发生变化,当引用计数器变为0的时候,该对象就会被当做垃圾回收。

  • 当一个对象有一个引用指向它时,那么这个对象的引用就+1
  • 当一个对象的引用为0时,这个对象就可以被销毁掉

我们通过一段代码来看一下:

// { name: '一碗周' } 的引用计数器 + 1
let person = {
  name: '一碗周',
}
// 又增加了一个引用,引用计数器 + 1
let man = person
// 取消一个引用,引用计数器 - 1
person = null
// 取消一个引用,引用计数器 - 1。此时 { name: '一碗周' } 的内存就会被当做垃圾回收
man = null

引用计数算法的优点如下:

  • 最大限度减少程序暂停,这里因为发现垃圾就立刻回收了,减少了程序因内存爆满而被迫停止的现象。
  • 发现垃圾时立即回收;

引用计数算法的缺点如下:

  • 无法回收循环引用的对象

就比如下面这段代码,就无法解决循环引用的问题

function fun() {
  const obj1 = {}
  const obj2 = {}
  obj1.next = obj2
  obj2.prev = obj1
  return '一碗周'
}
fun()

上面的代码中,当函数执行完成之后函数体的内容已经是没有作用的了,但是由于obj1和obj2都存在不止1个引用,导致两种都无法被回收,就造成了空间内存的浪费。并且时间开销大,这是因为引用计数算法需要时刻的去监控引用计数器的变化。

(2)标记清除

标记清除算法解决了引用计数算法的⼀些问题, 并且实现较为简单, 在V8引擎中会有被⼤量的使⽤到。

标记清除的核心思路就是可达性,这个算法是设置一个根对象,垃圾回收器会定时从这个根开始,找所有从根开始有引用到的对象,对于哪些没有引用到的对象,就认为是不可用的对象,这个算法可以很好的解决循环引用的问题

在这里插入图片描述
**注意:**对于上图的M、N就会被认为不可用的对象,就会被清除掉


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

闭包(闭包使用场景,闭包内存泄漏,js内存管理及垃圾回收) 的相关文章

  • 页面在 Google Adwords 转化跟踪上重定向

    我有一个表单 人们可以在其中提交数据 然后使用 ajax 将数据发送到服务器 我已将其设置为 Google Adwords 中的转化 下面是我使用过的代码 问题是 当用户提交表单时 在收到响应后 它会重定向回我给出的 URL 我不想重定向
  • 如何检测被覆盖的 CSS 属性?

    I can get all css properties for an element with document stylesheets but some of those are not active because those pro
  • javascript:全局变量泄漏

    每当我向 Firefox 提交插件时 我都会收到一封电子邮件 告诉我我的一些变量正在泄漏到全局范围内 一旦他们告诉我我解决了问题 但在那之前有什么方法 程序 来检查变量是否泄漏到全局范围内 Thanks Both JSLint http w
  • 如何检查是否存在可能的路径?

    我正在开发一个基于 javascript 的实验性游戏 玩家必须在二维平铺地图上移动才能退出 请随意检查这个小提琴并演奏 http jsfiddle net moonlife 74vLd 我只是随机放置障碍物 但有时障碍物会挡住玩家和出口之
  • Visual Studio 改变 Ctrl-K-D 的工作方式

    In Visual Studio I m using 2012 is there any way of editing the way that Ctrl K D combinations handles its Auto Formatti
  • 在自动完成上添加 jQuery 延迟

    我正在尝试为应用程序创建 jQuery 自动完成 search input on keyup function search this val autocomplete div autocomplete get ajax search se
  • Chrome 开发工具命中代码但未命中断点

    我在 chrome 开发工具上启用了断点 并且在一行上有一个断点 我知道 chrome 正在运行 因为我将断点放在具有以下语句的行上 alert why is this not breaking 如果我在本地主机中找到该文件 则断点有效 断
  • “require(...)”是常见的 JavaScript 模式还是库函数?

    我通常发现这是 node js 脚本 模块以及 phantomJS casperJS 等中的第一行 我很好奇 这是否是服务器端 javascript SSJS 的常见模式 类似于 include在 C C 中或import在 Java 中
  • 如何设置必须输入特定数字的字段?

    我想知道如何创建一个需要输入特定数字或文本的字段 例如 激活码 以及在输入的确认答案的情况下移动到 网页 并且在未确认的情况下移动到 另一页面 的按钮 使用必需的属性
  • fadeOut() 和slideUp() 同时进行?

    我已经发现jQuery 淡出然后滑动 https stackoverflow com questions 734554 jquery fadeout then slideup这很好 但不是那个 我怎么能够fadeOut and slideU
  • 如何调试超时等待异步 Angular 任务?无法在角度页面上找到元素

    编辑 请注意 在 ernst zwingli 的帮助下 我找到了问题的根源 因此 如果您遇到相同的错误 他指出的修复之一可能会帮助您 我的问题是量角器本身的一个已知问题 如果您认为这可能是您 我已经扩展了我的步骤 以在我最初的问题之后查明问
  • Riak 在 MapReduce 查询中失败。使用哪种配置?

    我正在与 riak riak js 结合开发一个 nodejs 应用程序 并遇到以下问题 运行此请求 db mapreduce add logs run 正确返回存储在存储桶日志中的所有 155 000 个项目及其 ID logs 1GXt
  • Aurelia 中的角度服务?

    我还没有找到详细说明如何从 Angular 1 x 迁移到 Aurelia 的详细文档 到目前为止 我只看到人们详细介绍了 Angular 的概念directive可以在 Aurelia 中使用重制 customElement 好吧 足够简
  • D3 向对象添加超链接?

    我正在尝试制作 D3 图 它将代表我网站的菜单 我尝试按照此处的其他指南添加超链接 但它们都不起作用 每个对象都会有一个不同的 URL 指向 主页 关于 联系方式等 如果添加超链接 我可以拖动对象吗 这意味着如果我按住单击 如果我单击该对象
  • 在 Nodejs 中,如何停止 FOR 循环直到 MongoDB 调用返回

    我正在研究下面的代码片段 我有一个名为 stuObjList 的 JSON 对象数组 我想循环遍历数组以查找具有特定标志集的特定 JSON 对象 然后进行数据库调用以检索更多数据 当然 FOR 循环不会等待数据库调用返回并到达 j leng
  • 如何使用 javascript 更改文件扩展名

    有谁知道在 Javascript 中更改文件扩展名的简单方法吗 例如 我有一个带有 first docx 的变量 但我需要将其更改为 first html 这将改变字符串包含文件名 let file first docx file file
  • 将 JSON 属性绑定到表单

    我有一个 JSON 对象和一个
  • 如何为 jQuery 插件设置私有变量?

    我想创建一个简单的插件 它使用元素的文本作为默认值 或者您可以在调用插件时设置此值 但是 如果我不设置该值 并为多个元素调用插件 则默认值会成倍增加 function fn reText function options var setti
  • Jquery 以编程方式更改

    文本

    编辑 解决方案是将其添加到个人资料页面而不是性别页面 profile live pageinit function event p pTest text localStorage getItem gender 我在列表视图中有一个带有一些文
  • 如何通过点击复制 folium 地图上的标记位置?

    I am able to print the location of a given marker on the map using folium plugins MousePosition class GeoMap def update

随机推荐

  • 精选30道Java多线程面试题

    1 线程和进程的区别 2 实现线程有哪几种方式 3 线程有哪几种状态 它们之间如何流转的 4 线程中的start 和run 方法有什么区别 5 怎么终止一个线程 如何优雅地终止线程 6 ThreadLocal在多线程中扮演什么角色 7 线程
  • WEB API 中HTTP的get、post、put,delete 请求方式

    一 WEB API 中HTTP 请求方式的四个主要方法 GET PUT POST DELETE 按照下列方式映射为 CURD 操作 1 POST 用于新建资源 服务端在指定的URI 上创建一个新的对象 将新资源的地址作为响应消息的一部分返回
  • 空间转录组共定位分析的一种方法

    主要是利用了Seurat 里面AddModuleScore函数 View project A33 meta data AddModuleScore ILC1 feature lt list c IL7R CCR6 KLRB1 IFNG IF
  • Dataframe 多行合并为一行

    原表数据 最后4行合并为1行 def ab df return join df values df df groupby 股票代码 股票简称 所属概念 apply ab df df reset index 效果如下 转载于 https ww
  • Qt编译后添加依赖文件到输出目录

    QMAKE POST LINK cp rf PWD lab const 1 xml OUT PWD lab const 1 xml cp rf PWD experiment1 xml OUT PWD experiment1 xml 这个是L
  • Python爬虫必知必会:BeautifulSoup之find_all参数速览

    find all 方法搜索当前tag的所有tag子节点 并判断是否符合过滤器的条件 find all name attrs class recursive string kwargs name 标签名搜索 attrs class 属性 类名
  • *** FATAL ERROR L232: APPLICATION CONTAINS TOO MANY RECURSIONS错误的解决方案

    最近一直在用KEIL写一个单片机的程序 遇到了一个很棘手的无法正常链接的问题 FATAL ERROR L232 APPLICATION CONTAINS TOO MANY RECURSIONS 在网上搜索了大量的文章 以及网页也没找到什么有
  • Redis介绍与使用

    文章目录 一 概念 1 什么是NOSQL 1 1 NOSQL和关系型数据库比较 1 2 非关系型数据库的优势 1 3 关系型数据库的优势 1 4 小结 2 主流的NOSQL产品 3 什么是Redis redis的应用场景 二 下载安装 三
  • rosbag commandline常用命令之filter

    可以实现对已有rosbag文件中的某些topic去除或者保留 rosbag filter input bag output bag topic tf or topic tf and m transforms 0 header frame i
  • 详解.NET实现OAuth2.0四种模式(6)RefreshToken

    我们知道 为了安全起见 AccessToken的有效时间一般是比较短的 如30分钟 在AccessToken超出有效期之后 它就不能再用于访问资源 必须重新获得 但如果每30分钟 就要让用户登录一次 那必定会让用户感到厌烦 于是就产生了Re
  • 公共命名空间,于2022年底

    公共命名空间的想法出现自2019年 到现在有三年了 在2022年底 总结一下这三年来的想法 就像字符集 字体 公共命名空间 新编译原理也是这么一对儿 字符集用来收集所有符号 字体用来显示字符集中的符号 公共命名空间用来收集所有的句子 新编译
  • java里的输入与输出

    一 概述 输入输出可以说是计算机的基本功能 作为一种语言体系 java中主要按照流 stream 的模式来实现 其中数据的流向是按照计算机的方向确定的 流入计算机的数据流叫做输入流 inputStream 由计算机发出的数据流叫做输出流 o
  • 想了很久的算法

    文章目录 1 求字符串中不重复的最长子串 2 斐波那契数列多种实现方式 1 求字符串中不重复的最长子串 var lengthOfLongestSubstring function s let setArr new Set result ma
  • 贺中国信通院“星火·链网”数字原生资产(DNA)服务网络隆重发布

    5月20日 中国信通院 星火 链网 数字原生资产 DNA 服务网络发布会在云端圆满举办 中国信通院院长 中关村区块链产业联盟理事长余晓晖出席会议并为 星火 链网 数字原生资产 DNA 服务网络上线发表寄语 中国信通院总工程师敖立 新华网首席
  • 识别图像模板旋转角度_基于视觉的焊缝识别与定位技术

    为了实现焊前引导 必须首先通过视觉传感系统识别工件和焊缝 确定焊接的关键点位置 建立关键点的二维或三维坐标 发送给机器人 将机器人的末端执行器运动到焊接起始点 自动完成焊前导引 焊缝识别的准确率与识别精度直接影响焊缝跟踪的精度 因此 焊缝识
  • 通过nginx代理拦截请求,进行全局访问限制

    声明 本博文用于学习总结及工作心得 运行环境 Ubantu 14 0 tomcat7 nginx 1 4 6 更新后1 5 6 项目中经常会用到权限管理 必然的就会存在权限的设定和验证 对于登陆或者模块的权限设定验证 在项目中直接实现 那么
  • 地图服务标注显示乱码问题

    版本 ArcGIS 10 1 在Catalog中发布了一个地图服务 直接切了图 切图后发现标注有乱码 操作系统是win7 不会涉及Server对字体库的访问权限问题 排查了一下 发现了原因 标注字体不能使用不支持中文的英文或者其他非中文字体
  • Golang基础 变量与常量

    Golang基础 变量与常量 01 变量声明 02 常量声明 03 变量初始化 04 常量初始化 参考资料 01 变量声明 变量就是内存堆栈区的一块地址空间用于存储数据 Go语言在使用变量时需要先声明变量 常用的声明方式有两种 使用var关
  • 用python最新版本安装web3后调试错误原因和解决方法

    由于调试web3 安装了最新版本的python3 11 用命令安装 pip install web3 提示安装错误 无法完成 仔细观察根据错误提示发现是 VC 14没有安装的原因 根据提示从微软官方下载vs BuildTools并单独安装V
  • 闭包(闭包使用场景,闭包内存泄漏,js内存管理及垃圾回收)

    1 什么是闭包 在认识闭包之前 我们先简单了解两个知识点 JavaScript 中的作用域和作用域链 JavaScript 中的垃圾回收 目的就是为了方便我们更容易理解闭包 1 JavaScript 中的作用域和作用域链 作用域就是一个独立