javascript作用域

JS作用域+this指向 【JavaScript】 js作用域 this指向及关于this指向的面试题 箭头函数和普通函数的this指向区别 阅读详情

第一章 作用域是什么

作用域简单来讲就是一套规则,用来规定存储变量,并且如何方便地找到这些变量

1.1 编译原理

传统语言的编译过程

在传统语言的流程中,程序中的一段源代码在执行之前会经历三个步骤,统称为“编译”

  • 分词/词法分析

    • **这个过程会将有字符组成的字符串(一段源代码就是字符串)分解成有意义的代码块,这些代码块就叫作词法单元。**例如,考虑程序 var a = 2;。这段程序通常会被分解成为下面这些词法单元:var、a、=、2 、;。空格是否会被当作词法单元,取决于空格在

      这门语言中是否具有意义。

    • 分词(tokenizing)和词法分析(Lexing)之间的区别是非常微妙、晦涩的,主要差异在于词法单元的识别是通过有状态还是无状态的方式进行的。简单来说,如果词法单元生成器在判断 a 是一个独立的词法单元还是其他词法单元的一部分时,调用的是有状态的解析规则,那么这个过程就被称为词法分析。

  • 解析/语法分析

    • 这个过程会把词法单元流(即是上一过程生成的词法单元组成的数组)转换成一个由元素逐级嵌套所组成的代表了程序语法结构的数,这个树被称为“抽象语法树”(AST)。

    • var a = 2; 的抽象语法树中可能会有一个叫作 VariableDeclaration 的顶级节点,接下

      来是一个叫作 Identifier(它的值是 a)的子节点,以及一个叫作 AssignmentExpression

      的子节点。AssignmentExpression 节点有一个叫作 NumericLiteral(它的值是 2)的子

      节点。

  • 代码生成

    • 即为将AST转换成可执行代码的过程。简单来说就是有某种方法可以将 var a = 2; 的 AST 转化为一组机器指令,用来创建一个叫作 a 的变量(包括分配内存等),并将一个值储存在 a 中。

1.2 理解作用域(理解js编译过程)

1.2.1 参与编译的组成

js在编译的过程中,需要几个部分的参与

  • 引擎

    从头到尾负责整个js程序的编译及执行过程

  • 编译器

    负责词法分析及代码生成等

  • 作用域

    负责收集并维护由所有声明的标识符(变量)组成的一系列查询,并实施一套非常严格的规则,确定当前执行代码对这些标识符的访问权限

1.2.2 编译过程

通过 var a = 2 作为例子进行讲解

  • 首先,编译器再遇到这句代码时(未编译前),会进行编译的前2个过程,即进行词法分析与语法分析,但在代码生成这一过程中,与传统的编译语言不同
  • 第三个过程编译器会进行一下处理
    • 遇到 var a,编译器会先询问作用域中是否已经有一个改名称的变量存在于同一作用域的集合中,如果是,则会忽略该声明,否则会要求作用域在当前作用域的集合中声明一个新的变量命名为a
    • 接下来编译器将会为引擎生成运行时所需的代码,此时这些代码用来处理a = 2这个赋值操作。引擎运行时就会沿着作用域链查找改变量
    • 如果引擎最终找到了 a 变量,就会将 2 赋值给它。否则引擎就会举手示意并抛出一个异常

总结:变量的赋值操作会执行两个动作,首先编译器会在当前作用域中声明一个变量(如果之前没有声明过),然后在运行时引擎会在作用域中查找该变量,如果能够找到就会对它赋值。

1.2.3 查找过程

作用域就是一套规则,规定了查询的规则,分别为LHS查询和RHS查询,具体用哪种查询,有以下区别

LHS和RHS区别
  • 简单讲,两者的区别在于在赋值操作的左边还是右边,这里要区别赋值操作而非赋值操作符=
  • 当变量出现在赋值操作左边时,进行LHS查询,此时就是为该变量赋值,即需要找到该变量所在内存并重新赋值
  • 当变量出现在赋值操作右边时,进行RHS查询,此时只是想找到该变量的值而已
  • 举个例子
function foo(a) { 
 console.log( a ); // 2 
} 
foo( 2 );

当调用foo这个函数时,会先进行RHS查询,查询是否有foo这个值,当找到之后,会把参数 2赋值给形参 a,此时就需要LHS查询是否有这个形参a,接着会再次进行2次RHS查询,分别是查询是否有console和a的值

1.3 作用域嵌套

当一个块或者函数在另一个块或者函数中时,就发生了作用域的嵌套。所以,如果在当前作用域无法找到某变量时,引擎就会在外层嵌套的作用域中开始查找,直到找到该变量或者到了最外层,即全局作用域为止。注意,此时的查找包括LHS和RHS。

1.3.1 查找不到异常

当要查找的变量还未声明时,LHS和RHS查找的行为是不一样的。简单讲,当进行LHS查找时,若沿着作用域到了最外层仍然还没用找到该变量时,就会在全局作用域中创建改变量,然后把变量给引擎;当进行RHS查找不到时,引擎就会抛出referenceerror(引用错误)异常报错

function fn1() {
     l = 1;  // 进行LHS查找,找不到就在全局作用域声明改变量
     console.log(l + r);  // RHS查找r, ReferenceError: r is not defined 
}

fn1()

console.log(l);  // 1, 就是在函数fn1中创建的·全局变量
  • 注意,ES5 中引入了“严格模式”。同正常模式,或者说宽松 / 懒惰模式相比,严格模式在行为上有很多不同。其中一个不同的行为是严格模式禁止自动或隐式地创建全局变量。因此,在严格模式中 LHS 查询失败时,并不会创建并返回一个全局变量,引擎会抛出同 RHS 查询失败时类似的 ReferenceError 异常。

  • 如果 RHS 查询找到了一个变量,但是你尝试对这个变量的值进行不合理的操作,比如试图对一个非函数类型的值进行函数调用,或者引用 null 或 undefined 类型的值中的属性,那么引擎会抛出另外一种类型的异常,叫作 TypeError。

第二章 词法作用域

作用域共有两种主要的工作模型。第一种是最为普遍的,被大多数编程语言所采用的词法作用域,我们会对这种作用域进行深入讨论。另外一种叫作动态作用域,仍有一些编程语言在使用(比如 Bash 脚本、Perl 中的一些模式等)。js使用的是词法作用域。

2.1 词法阶段

在编译器编译的第一阶段会进行词法分析。而词法作用域就是定义在词法阶段的作用域。即词法作用域是由你在写代码时将变量和块写在哪里决定的,在大部分情况下,词法分析器在处理代码时会保持作用域不变

查找

在作用域查找的过程中,有以下的注意点:

  • 作用域在查找到第一个匹配的标识符之后就会停止查找
  • 在多层的嵌套作用域中可以定义同名的标识符,叫做“遮蔽效应”
  • 全局变量会自动成为全局对象(比如浏览器的window对象)的属性,因此可以不直接通过全局对象的词法名称,而是间接地通过对全局对象属性的引用来对其进行访问。如window.a
  • 无论函数在什么时候什么位置被调用,它的词法作用域都只由函数被声明时所处的位置决定
  • 词法作用域查找只会查找一级标识符,比如 a、b 和 c。如果代码中引用了 foo.bar.baz,词法作用域查找只会试图查找 foo 标识符,找到这个变量后,对象属性访问规则会分别接管对 bar 和 baz 属性的访问。

2.2 欺骗词法

函数作用域在声明时就已经确定了作用域,但有以下方法可以修改它的词法作用域,但是欺骗词法作用域会导致性能下降

2.2.1 eval

JavaScript 中的 eval(…) 函数可以接受一个字符串为参数,并将其中的内容视为好像在书写时就存在于程序中这个位置的代码。换句话说,可以在你写的代码中用程序生成代码并运行,就好像代码是写在那个位置的一样。

在执行 eval(…) 之后的代码时,引擎并不“知道”或“在意”前面的代码是以动态形式插入进来,并对词法作用域的环境进行修改的。引擎只会如往常地进行词法作用域查找

function fn(str, a) {
    // 'use strict'
    eval(str) // 欺骗词法
    console.log(a, b); // 3, 4
}

var b = 7;

fn('var b = 4', 3)

默认情况下,如果 eval(…) 中所执行的代码包含有一个或多个声明(无论是变量还是函数),就会对 eval(…) 所处的词法作用域进行修改。

在严格模式的程序中,eval(…) 在运行时有其自己的词法作用域,意味着其中的声明无法修改所在的作用域。

function fn(str, a) {
    'use strict'
    eval(str) // 欺骗词法
    console.log(a, b); // 3, 7  即会找到全局的b
}

var b = 7;

fn('var b = 4', 3)

2.2.2 with

with 通常被当作重复引用同一个对象中的多个属性的快捷方式,可以不需要重复引用对象本身。

let obj = {
    a: 1,
    b: 2
}

with(obj) {
    a = 2,
    b = 3
}

console.log(obj); // { a: 2, b: 3 }

但是,如果使用with对该对象没有的属性赋值时,并不会给该对象创建这个属性,而是直接在全局对象中创建这个属性,如:

let obj = {
    a: 1,
    b: 2
}

with(obj) {
    a = 2,
    b = 3,
    c = 5
}

console.log(obj);  // { a: 2, b: 3 }
console.log(c); // 5
console.log(obj.c);  // undefined 没有的属性时会显示undefined

原因

实际上,with可以将将一个没有或有多个属性的对象处理成一个完全隔离的词法作用域,因此这个对象的属性也会被定义在这个作用域的词法标识符

尽管 with 块可以将一个对象处理为词法作用域,但是这个块内部正常的 var声明并不会被限制在这个块的作用域中,而是被添加到 with 所处的函数作用域中

所以上面的例子可以理解成,with给obj声明了一个作用域,在进行LHS查询时找不到c,便沿着作用域链寻找最后找不到就在全局声明了一个c变量,以下代码也可以验证

function fn(obj) {
    var c = 2
    with(obj) {
        c = 0
    }
    console.log(c);  // // 0, 不是 2!!!  with语句进行LHS查询时找到上一个作用域,即函数fn,里面有c并赋值
}

var obj1 = {
    a: 1,
    b: 2
}

fn(obj1)  
console.log(obj1); // { a: 1, b: 2 }

不推荐使用 eval(…) 和 with 的原因是会被严格模式所影响(限制)。with 被完全禁止,而在保留核心功能的前提下,间接或非安全地使用eval(…) 也被禁止了。

2.2.3 性能

JavaScript 引擎会在编译阶段进行数项的性能优化。其中有些优化依赖于能够根据代码的词法进行静态分析,并预先确定所有变量和函数的定义位置,才能在执行过程中快速找到标识符。

但如果引擎在代码中发现了 eval(…) 或 with,它只能简单地假设关于标识符位置的判断都是无效的,因为无法在词法分析阶段明确知道 eval(…) 会接收到什么代码,这些代码会如何对作用域进行修改,也无法知道传递给 with 用来创建新词法作用域的对象的内容到底是什么。

第三章 函数作用域和块作用域

3.1 函数中的作用域

函数作用域的含义是指,属于这个函数的全部变量都可以在整个函数的范围内使用和复用

function fn1() {
    console.log(1);
    function fn2() {
        console.log(2);
    }
    fn2()
}

fn1() // 1, 2
fn2() // ReferenceError: fn2 is not defined

上面例子中,fn2定义在函数fn1的作用域中,就无法从全局作用域或其他的作用域中去调用他,否则会报错

3.1.1 隐藏内部实现

对于一部分代码,用函数进行封装,就可以把这部分代码放在这个函数的作用域中,把它们“隐藏”起来

隐藏代码有下列的好处:

有很多原因促成了这种基于作用域的隐藏方法。它们大都是从最小特权原则中引申出来的,也叫最小授或最小暴露原则。这个原则是指在软件设计中,应该最小限度地暴露必要内容,而将其他内容都藏”起来,比如某个模块或对象的 API 设计

  • 如果把所有的变量和函数都写在全局作用域中,就会违背最小授权原则,对于有一些代码,只在特定的作用域中使用,就可以将这些代码私有化

    function doSomething(a) { 
     b = a + doSomethingElse( a * 2 ); 
     console.log( b * 3 ); 
    } 
    function doSomethingElse(a) { 
     return a - 1; 
    } 
    var b; 
    doSomething( 2 ); // 15
    

    上面的代码写成下面这种会更好,即把变量b,跟函数doSomethingElse私有化,放在函数doSomething的作用域中

    function doSomething(a) { 
     function doSomethingElse(a) { 
     return a - 1; 
     } 
     var b; 
     b = a + doSomethingElse( a * 2 ); 
     console.log( b * 3 ); 
    } 
    doSomething( 2 ); //
    
  • 可以避免同名标识符的冲突

3.2 函数作用域

虽然我们用函数声明的方式可以让一部分代码添加到其他的作用域中,但这种方法必须声明一个具名的函数,意味着这个函数名本身就“污染”了全局作用域,其次必须显示地通过这个函数名调用这个函数才能运行其中的代码

js提供了函数表达式来解决这个问题

3.2.1 函数声明与函数表达式

js中创建函数的方法有2中,为函数声明式和函数表达式

函数声明

函数声明可以定义命名的函数变量,而无需给变量赋值。函数声明是一种独立的结构,不能嵌套在非功能模块中。可以将它类比为 变量声明。就像变量声明必须以“var”开头一样,变量声明必须以“function”开头。函数名在自身作用域和父作用域内是可获取的。

函数表达式

函数表达式将函数定义为表达式语句(通常是变量赋值)的一部分。通过函数表达式定义的函数可以是命名的,也可以是匿名的。函数表达式不能以“function”开头。函数名在作用域外是不可获取的。

function fn1() {
    // 这种是函数声明式
}

let fn2 = function() {
    // 这种是函数表达式
}

它们有以下的区别:

  • 函数声明和函数表达式之间最重要的区别是它们的名称标识符将会绑定在何处。

    var a = 2; 
    (function foo(){ // <-- 函数表达式的一种
     var a = 3; 
     console.log( a ); // 3 
    })(); // <-- 以及这一行
    console.log( a ); // 2
    

    foo 被绑定在函数表达式自身的函数中而不是所在作用域中。换句话说,(function foo(){ … }) 作为函数表达式意味着 foo 只能在 … 所代表的位置中被访问,外部作用域则不行。foo 变量名被隐藏在自身中意味着不会非必要地污染外部作用域。

  • 以函数声明的方法定义的函数,函数名是必须的,而函数表达式的函数名是可选的。(函数声明整体会被提升到当前作用域的顶部,函数表达式也提升到顶部但是只有其变量名提升)。故函数声明式的函数可以在函数声明之前调用,而函数表达式的不可以

  • 以函数声明的方法定义的函数并不是真正的声明,它们仅仅可以出现在全局中,或者嵌套在其他的函数中,但是它们不能出现在循环,条件或者try/catch/finally中,而函数表达式可以在任何地方声明。换句话说,函数声明不是一个完整的语句,所以不能出现在if-else,for循环,finally,try catch语句以及with语句中。

    • 但是,在普通的块级作用域中的函数声明会被提升到当前所在作用域的顶部(此处就是全局作用域),因此后面执行foo()的时候可以正常的输出。

      if(true) {
          function foo() {
              console.log(111);
          }
          foo()  // 111    
      }
      
      try {
          function fn() {
              console.log(11);
          }
          fn()  // 11
      }catch(e) {
          console.log(e);
      }
      

3.2.2 函数表达式

匿名函数表达式
setTimeout( function() { 
 console.log("I waited 1 second!"); 
}, 1000 );

对于一般的回调函数,没有名称标识符的,就是函数表达式,叫做匿名函数表达式

匿名函数表达式有以下的缺点:

  • 匿名函数在栈追踪中不会显示有意义的函数名,使得调试困难
  • 如果没有函数名,当函数需要引用自身时只能使用已经过期的 arguments.callee 引用,比如在递归中。另一个函数需要引用自身的例子,是在事件触发后事件监听器需要解绑自身。
  • 匿名函数省略了对于代码可读性 / 可理解性很重要的函数名。一个描述性的名称可以让代码不言自明。

行内函数表达式非常强大且有用——匿名和具名之间的区别并不会对这点有任何影响。给函数表达式指定一个函数名可以有效解决以上问题。始终给函数表达式命名是一个最佳实践:

setTimeout( function timeoutHandler() { // <-- 快看,我有名字了!
 console.log( "I waited 1 second!" ); 
}, 1000 );
立即执行函数表达式IIFE
var a = 2; 
(function foo() { 
 var a = 3; 
 console.log( a ); // 3 
})(); 
console.log( a ); // 2

由于函数被包含在一对 ( ) 括号内部,因此成为了一个表达式,通过在末尾加上另外一个( ) 可以立即执行这个函数,比如 (function foo(){ … })()。第一个 ( ) 将函数变成表达式,第二个 ( ) 执行了这个函数。

相较于传统的 IIFE 形式,很多人都更喜欢另一个改进的形式:(function(){ … }())。仔细观察其中的区别。第一种形式中函数表达式被包含在 ( ) 中,然后在后面用另一个 () 括号来调用。第二种形式中用来调用的 () 括号被移进了用来包装的 ( ) 括号中。

IIFE 的另一个非常普遍的进阶用法是把它们当作函数调用并传递参数进去。例如:

var a = 2; 
(function IIFE( global ) { 
 var a = 3; 
 console.log( a ); // 3 
 console.log( global.a ); // 2 
})( window ); 
console.log( a ); // 2

3.3 块作用域

块作用域是一个用来对之前的最小授权原则进行扩展的工具,将代码从在函数中隐藏信息扩展为在块中隐藏信息。

var没有块作用域

3.3.1 let

let 关键字可以将变量绑定到所在的任意作用域中(通常是 { … } 内部)。换句话说,let为其声明的变量隐式地劫持了所在的块作用域。

使用 let 进行的声明不会在块作用域中进行提升。声明的代码被运行之前,声明并不“存在”。

{ 
 console.log( bar ); // ReferenceError! 
 let bar = 2; 
}
垃圾回收

考虑以下代码:

function process(data) { 
 // 在这里做点有趣的事情
} 
var someReallyBigData = { .. }; 
process( someReallyBigData ); 
var btn = document.getElementById( "my_button" ); 
btn.addEventListener( "click", function click(evt) { 
 console.log("button clicked"); 
}, /*capturingPhase=*/false );

click 函数的点击回调并不需要 someReallyBigData 变量。理论上这意味着当 process(…) 执行后,在内存中占用大量空间的数据结构就可以被垃圾回收了。但是,由于 click 函数形成了一个覆盖整个作用域的闭包,JavaScript 引擎极有可能依然保存着这个结构(取决于具体实现)。

块作用域可以打消这种顾虑,可以让引擎清楚地知道没有必要继续保存 someReallyBigData 了:

function process(data) { 
 // 在这里做点有趣的事情
} 
// 在这个块中定义的内容完事可以销毁!
{ 
 let someReallyBigData = { .. }; 
 process( someReallyBigData ); 
} 
var btn = document.getElementById( "my_button" ); 
btn.addEventListener( "click", function click(evt){ 
 console.log("button clicked"); 
}, /*capturingPhase=*/false );

为变量显式声明块作用域,并对变量进行本地绑定是非常有用的工具,可以把它添加到你的代码工具箱中了。

let循环

一个 let 可以发挥优势的典型例子就是之前讨论的 for 循环。

for (let i=0; i<10; i++) { 
 console.log( i ); 
} 
console.log( i ); // ReferenceError
let与var区别
for(let i = 0; i < 3; i++) {
    setTimeout(() => {
        console.log(i);   // 0, 1, 2
    })
}

for(var i = 0; i < 3; i++) {
    setTimeout(() => {
        console.log(i); // 3, 3, 3
    })
}
  • 由于var定义变量时,变量是被定义在当前作用域里的,setTimeout是异步,要在for循环后执行,所以当settineout函数执行的时候,输出变量i时,会从当时作用域里面去找变量i,总共进行了5次查找,这5次查找都是在当前作用域执行的,所以它们找到的是当时作用域下的同一个i,这个i是3,所以结果是3个3
  • let是块级作用域,每执行一次setTimeout就向每个块中寻找i值,执行了5次,每个块中分别是0 1 2 3 4,所以结果为0 1 2 3

3.3.2 const

除了 let 以外,ES6 还引入了 const,同样可以用来创建块作用域变量,但其值是固定的(常量)。之后任何试图修改值的操作都会引起错误。

第四章 提升

4.1 先声明,后赋值

引擎会在解释 JavaScript 代码之前首先对其进行编译。编译阶段中的一部分工作就是找到所有的声明,并用合适的作用域将它们关联起来。第 2 章中展示了这个机制,也正是词法作用域的核心内容。

因此,正确的思考思路是,包括变量和函数在内的所有声明都会在任何代码被执行前首先被处理

当你看到 var a = 2; 时,可能会认为这是一个声明。但 JavaScript 实际上会将其看成两个声明:var a; 和 a = 2;。第一个定义声明是在编译阶段进行的。第二个赋值声明会被留在原地等待执行阶段。

提升

这个过程就好像变量和函数声明从它们在代码中出现的位置被“移动”到了最上面。这个过程就叫作提升。

注意,函数声明会被提升,但函数表达式不会被提升

foo(); // 不是 ReferenceError, 而是 TypeError! 因为此时foo的值为undefined
var foo = function bar() { 
 // ... 
}

4.2 函数优先

函数优先的意思是在同时有函数跟变量声明时,会先提升函数,再是变量

j() // 11  函数声明提升之后才是变量提升

function j() {
    console.log(11);
}
 
var j;  // 由于j已经在函数声明中被声明了,所以会忽略这次声明

//无论 var j 和 function j 的先后顺序是怎么样的,结果j()都是输出 11

后面的函数声明可以把前面的覆盖掉

fn() // 222  即后面的声明会替换之前的声明

function fn() {
    console.log('111');
}

function fn() {
    console.log('222');
}

一个普通块内部的函数声明通常会被提升到所在作用域的顶部,这个过程不会像下面的代码暗示的那样可以被条件判断所控制:

foo(); // "b" 
var a = true; 
if (a) { 
 function foo() { console.log("a"); } 
}
else { 
 function foo() { console.log("b"); } 
}
kaggle注册以及数据集下载全流程 kaggle注册,数据集下载及常见问题 阅读详情

相关推荐

如何利用Arcgis进行地统计学分析(三):空间插值方法选择与优化

本文深入探讨了在Arcgis中进行地统计学分析时,如何根据探索性数据分析(EDA)结果科学选择与优化空间插值方法。文章对比了IDW、RBF、克里金等主流方法的适用场景与核心参数,并通过实战案例详解了从数据诊断到模型调优的完整流程,强调结合半变异函数与趋势分析进行“对症下药”,以提升插值结果的精度与可靠性。

weixin_29281915的博客 121

js使用心得——避免全局变量冲突的小技巧

在写js代码的时候,经常会因为这样或者那样的原因用到全局变量,如果全局变量只在一个js里使用,那就没问题,但如果变量在不同的js文件里出现,这时隐藏的问题就会开始暴露,也许你能很快修复出现的BUG,又或许全无头绪。          先看下边的js文件test1.js var a = 1, b = 2, c = a + b;//此时c的值为3html代码如下: a

敲键盘的猫 1320

ChatGPT Plus账号被降智?3个实用检测方法+终极解决方案(附国内支付指南)

本文针对ChatGPT Plus账号性能下降问题,提供了3个科学检测方法和系统级解决方案。通过详细分析症状、专业诊断技巧和优化策略,帮助用户有效应对GPT-4o等高级功能失效、响应质量下降等问题,特别包含国内用户关心的支付方案和账号管理建议。

weixin_42639633的博客 473

JS函数作用域提升

当你看到var a=2;时,可能会认为这是一个声明。但js实际上回将其看成两个声明:var a;和a=2;。第一个定义声明是在编译阶段进行的。第二个赋值声明会被留在原地等待执行阶段。 ? 1 2 3 a=2; var a; console.log(a);//2 ? 1 2 cons...

仗剑天涯,从摘要开始 479

ads传统功放设计笔记(3)

传统功放设计的流程一般包括以下这些步骤: 1、明确设计目标 2、选择功放管子 3、确定静态工作点 4、设计偏置电路 5、判断稳定性 6、负载与源牵引 7、输入输出阻抗匹配 8、原理图优化 9、大信号仿真 10、版图设计 11、版图联合仿真 12、pcb设计 第二节我们设计仿真了功放的原理图。之后我们需要对版图进行设计和仿真。 10、版图设计 首先将S参数控件都打叉,还要去掉电源、源负载阻抗、地、芯片、电容。在原先电容和芯片的位置加上gap,设置好长度和间隔。之后在电源引脚、输入输出引脚和隔离的两端加上端口。

qq_40995480的博客 6029

【YOLO多模态检测顶刊】TGRS 2025范文解读,RGFNet 可见光-红外图像融合目标检测,2026年基于YOLO多模态融合属于发文热点,小论文和大论文通用,通读顶刊了解做实验和论文写作的全流程

🔥本文提出了一种反射率引导的渐进特征对齐网络(RGFNet)用于全天候无人机目标检测。该方法利用Retinex理论从可见光图像中提取光照不变的反射率特征,设计了反射率引导协同对齐模块(RCAM)实现跨模态双向特征对齐,并通过光照感知选择性融合模块(LSFM)在共享状态空间中进行高效特征交互。在DroneVehicle和DVTOD数据集上的实验表明,RGFNet分别达到81.4%和88.5%的mAP,显著优于现有方法。该方法有效解决了低光照条件下可见光-红外图像特征错位问题,为全天候无人机检测提供了新思路。

Ai缝合怪、助力小伙伴高效发论文 1079

前端js入门——JavaScript 作用域

在MDN或者其他权威教程上,对于作用域的解释无一例外是与可见性和生命周期相关。 作为最重要的概念之一,初学者往往会惑于上述高大上的理论阐述。 所以从浅显处入手,可能更有助于对于概念的入门和深入理解。 作用域通俗的讲就是变量或者函数的“势力范围”,在此范围内,变量可以被引用,函数可以被调用。 JavaScript具有两种作用域: (1).全局作用域。 (2).函数作用域。 特别说明:ES2015新增...

fenghulun的博客 7403

微信小程序 - 获取当前日期时间(函数封装)

效果图 前言 摘自微信小程序demo程序中utils.js方法。 普通newDate()出来的日期时间,并不是我们想要的格式,所以要进行格式整理。 解决方案 打开utils.js文件(随意),复制以下代码: /** *获取当前时间 *@description自定义日期分钟秒数 *@param{Object}date-newData()对象 *@returnString */ functionformatTime(date){ //年月日

🏆 前端领域优质创作者 2844

JavaScript-什么是作用域,作用域和作用域链,js没有块级作用域

作用域概述 在任何编程语言中都有作用域的概念,简单来说,所谓的作用域就是变量可作用的范围(可被访问到的区域) 在 JavaScript 中有两种作用域类型,一种是全局作用域另一种是局部作用域 想要理解作用域就必须要理解全局变量和局部变量 全局变量 在网页的所有脚本和函数都能够访问到的变量就是全局变量 如何定义全局变量: 在函数外部定义的变量,就是 全局变量 在函数内部,省略关键字 var ...

weixin_44486539的博客 301

QT西游回合制源码+java后台管理系统

这是一套回合制游戏源码,很适合学习。

renkai721的专栏 2536

边缘AI工业落地:YOLO26-Seg + RK3588 NPU 极致部署(低功耗+实时实例分割,工业场景全覆盖)

本次实战汇总了「YOLO26-Seg+RK3588 NPU」工业边缘部署中最常见、最致命的8个坑点,所有坑点均来自真实工业项目,解决方案均为零代码/一键操作,无需复杂配置,能让你少走90%的弯路,节省大量时间,必看必记!❌ RKNN转换报错「算子不支持/模型加载失败」→ ✅ 导出ONNX时必须指定opset=12,重新导出即可,RK3588唯一兼容版本;❌ 分割mask错位/轮廓模糊 → ✅ 导出ONNX时加,并保证RKNN的归一化参数与YOLO26一致,零代码修复;

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1719

【Js】JavaScript作用域

JavaScript作用域 1. 什么是作用域 作用域是代码中的某些特定部分中变量,函数和对象的可访问性。 换句话说,作用域决定了代码区块中变量和其他资源的生命周期和可见性。变量在作用域之外是不可见的。 JavaScript 的作用域包括: 全局作用域 模块作用域 函数作用域 块作用域 词法作用域 2. 全局作用域 在任何函数、块或模块范围之外定义的变量具有全局作用域。具有全局作用域的变量可以在程序的任意位置访问。 创建全局作用域, 这里分两种情况来说: 一种是在具有模块系统的情况

m0_57135756的博客 307

RK3576 调试ov2735 mipi-csi摄像头

摘要:本文记录了基于RK3576平台调试OV2735 MIPI摄像头的全过程。开发环境采用Linux 6.1内核和Buildroot文件系统。调试步骤包括:1)硬件检查(电源、晶振和引脚连接);2)驱动配置(设备树节点、ISP通道设置);3)驱动验证(通过ID检测和I2C工具测试);4)推流测试(使用v4l2和gstreamer工具)。重点解决了复位引脚配置、时钟命名匹配等关键问题,并通过寄存器检查确保初始化正常。最终实现了摄像头数据流的成功输出,为嵌入式视觉应用开发提供了完整参考方案。

qq_45147279的博客 1062

javascript作用域有几种,js 作用域、作用域链

和全局作用域相反,局部作用域一般只在固定的代码片段内可访问到,最常见的例如函数内部,所有在一些地方也会看到有人把这种作用域称为函数作用域,例如下列代码中的blogName和函数innerSay都只拥有局部作用域。let/const 声明并不会被提升到当前代码块的顶部,因此你需要手动将 let/const 声明放置到顶部,以便让变量在整个代码块内部可用。在JavaScript中,作用域为可访问变量,对象,函数的集合,它分为局部作用域和全局作用域。块级作用域所声明的变量在指定块的作用域外无法被访问。

阿发狗伪原创 132

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

【JavaScript】JS中变量的作用域

前几天在项目开发过程中发现两个if语句当中定义相同的变量,居然会相互影响。代码大概如下所示: if (1 == 1){ var obj = {name: "hello"}; $("body").click(function () { alert(obj.name) }) } if (2 == 2){ var obj = {name: "Hi"} } 点击事件触发后,发现输出的是Hi。我当时就考虑到应该和JS变量的作用域有关,所以就去学习了一下,并写下

心生的小鱼专栏 847

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

JavaScript Js作用域精解。什么是Js作用域,有什么用?

文章目录详解作用域与作用域链1 JS代码执行步骤2 JS预编译2.1 AO对象2.2 GO对象2.3 [[scope]]作用域2.4 scope chain作用域链3 函数执行时作用域及数据变化3.1 第一步:定义外层函数a3.2 第二步:执行函数a3.3 第三步:定义内层函数b3.4 第四步:执行函数b3.5 解析:函数执行前后的AO、GO变化闭包1 闭包定义2 闭包的主要作用3 闭包应用4 缺点4 缺点 详解作用域与作用域链 友情链接渡一教育 首先,再要搞明白什么是作用域什么是作用域链之前,先要明白几

SillyBoy的博客 311

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

【JavaScript】js中说说你对作用域链的理解

引擎会尝试在当前作用域下去寻找该变量,如果没找到,再到它的上层作用域寻找,以此类推直到找到该变量或是已经到了全局作用域。可见上述代码中在函数内部声明的变量或函数,在函数外部是无法访问的,这说明在函数内部定义的变量或者方法只是函数作用域。任何不在函数中或是大括号中声明的变量,都是在全局作用域下,全局作用域下声明的变量可以在程序的任意位置访问。把作用域比喻成一个建筑,这份建筑代表程序中的嵌套作用域链,第一层代表当前的执行作用域,顶层代表全局作用域。变量,当我们在全局访问这个变量的时候,系统会报错。

一个前端开发者 298

JS - 关于改变Javascript的作用域链

关于Javascript静态作用域的一些心得。 之前在看JS大牛BYVoid的>时, 学习到了最能说明Javascript静态作用域特性的代码, 如下: var scope = "global"; function f1() { console.log(scope); } f1() // output: global function f2() { scope = "f2"

evan2916的专栏 2304

html js什么作用域,什么是javascript的作用域链?

JavaScript里一切都是对象,包括函数。函数对象和其它对象一样,拥有可以通过代码访问的属性和一系列仅供JavaScript引擎访问的内部属性。其中一个内部属性是作用域,包含了函数被创建的作用域中对象的集合,称为函数的作用域链。作用域:作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。可以说,变量和函数在什么时候可以用,什么时候被摧毁,这都与作用域有关。JavaSc...

weixin_39958100的博客 156

js--高级JavaScript之作用域

前言 前面的博客基本上已经将JavaScript的基础知识介绍完毕,现在开始总结一些更高端一点的JavaScript技术。这篇博客就从作用域、作用域链这方面来介绍。 内容 所谓作用域就是指代码有效的区域 常常使用某些设计模式起到封装作用,因为变量容易被替换,所以我们的js代码就不安全,在我们实际使用的时候,应该杜绝使用全局变量,这个时候就用到了设计模式,大家统称沙箱模式 Ja...

罗俊 324

php js函数作用域,javascript 作用域详解

作用域理解:定义的变量、函数生效的范围。javascript 有全局作用域和函数作用域两种。注:es6实现let 块级作用域不是js原生的,底层同样是通过var实现的。如果想了解具体细节,请访问babel官方 对es6中let 进行解析。执行上下文范围:一段内或者一个函数内;全局:函数声明、变量声明 。范围:;函数:函数声明、变量声明、this、arguments。范围:一个函数内部;函数、变量声...

weixin_31572321的博客 185

JavaScript作用域与闭包

一、作用域 二、闭包

qq_48113035的博客 3378

前端基础-JavaScript作用域与JS代码的运行

第8章 作用域与JS代码的运行 * 作用域:变量可以起作用的范围和区域 8.1 全局变量和局部变量 * 全局变量与全局作用域 在任何地方都可以访问到的变量就是全局变量,全局变量所在的区域就是全局作用域 局部变量 只在固定的代码片段内可访问到的变量,最常见的例如函数内部的变量,就是局部变量。局部变量所在的区域就是局部作用域(函数作用域) 不使用var声明的变量是全局变量,不推荐使用。...

逍遥云恋 569

【JS】JavaScript作用域总结

一:在JavaScript中变量的作用域分为: 全局作用域 和 局部作用域(函数作用域) 1:所有window的属性和方法都属于全局作用域 2:只有函数有局部作用域,对象等其他是没有作用域的 例如: var x = 11; var obj = { x: 22, methods: { x: 33, say: func...

Y.Cheng的博客 1380

JS----JavaScript中的作用域和作用域链

作用域(Scope) 1.什么是作用域 作用域是在运行时代码中的某些特定部分中变量,函数和对象的可访问性。 作用域(scope):一个变量的可用范围 作用域的类型 Javascript中有三种作用域: 全局作用域; 函数作用域; 块级作用域; 2. 全局作用域 任何不在函数中或是大括号中声明的变量,都是在全局作用域下,全局作用域下声明的变量可以在程序的任意位置访问。 例如: // 全局变量 var greeting = 'Hello World!'; function greet() { cons

bugQueen的博客 260

【JavaScript】一文理解JS作用域的问题

这个列表的顶端是当前执行的上下文(即当前的变量对象),下面是外部函数的变量对象,再下面是外部函数的外部函数的变量对象,以此类推,一直到全局执行上下文。变量在函数内声明,变量为局部变量,具有局部作用域。局部的变量只能在函数内部访问。局部变量在函数开始执行的时候创建,函数执行完毕之后局部变量会自动销毁。因为局部变量只能作用在函数内,所以不同的函数可以使用相同名称的变量。在JavaScript中,对象和函数同样也是变量;变量在函数外定义,就是全局变量;函数参数只在函数内起作用,也是局部变量。

一条有梦想的咸鱼 1178
上一篇: js执行机制(event loop)
下一篇: this指向问题全面解析
Lin__hr
博客等级 码龄6年 5粉丝 25原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值