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"); } 
}
STM32L476低功耗实战:LPTIM精准定时唤醒STOP2模式与系统级功耗优化 本文深入探讨了STM32L476低功耗实战技巧,重点解析了LPTIM精准定时唤醒STOP2模式的配置与优化。通过详细的步骤指南和实战经验分享,帮助开发者实现系统级功耗优化,特别适合电池供电设备开发。文章涵盖LPTIM1定时器配置、STOP2模式进入流程及常见问题排查,助力将整机功耗降至8.2uA级别。 阅读详情

相关推荐

【嵌入式原理系列-第七篇】ld脚本实战:从零构建MCU内存布局

本文是一篇针对嵌入式开发者的实战指南,详细讲解了如何从零开始为MCU编写ld链接器脚本以构建自定义内存布局。文章以STM32F103C8T6为例,深入剖析了MEMORY和SECTIONS指令的用法,并提供了OTA分区、非易失数据存储等高级定制案例,帮助开发者解决实际工程中的Flash与RAM管理难题,实现对程序运行的深度掌控。

weixin_29271263的博客 249

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

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

敲键盘的猫 1320

k8s重装1.28.2+calico+踩坑收集+InPlacePodVerticalScaling

它提供了从镜像构建(通过 Dockerfile)、镜像管理(上传、下载、存储等)、容器创建、运行、网络配置(可以为容器分配自定义的网络,如 bridge 网络、host 网络等)到容器编排(通过 Docker Compose 可以简单地编排多个容器的启动和关联关系)等一整套完整的解决方案。它的核心功能是启动和管理容器的生命周期。sudo apt update这个可以经常用,是来更新软件包的,它不下载,所以没风险,但是经常会报错,别问,问就是某种强大的力量,所以用镜像或者代理或者巴拉巴拉。

SsjjsS2019的博客 2553

JS函数作用域提升

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

仗剑天涯,从摘要开始 479

Time-Interleaved Analog-to-Digital Converters

  这篇论文提供了时间交错模数转换器的教程回顾。在解释了偏置、增益、定时和其他不匹配对变换器性能的影响后,给出了目前解决不匹配问题的方法。论文最后总结了时间交错模数转换器的现状。 1.简介   时间交错模数转换器(ADC)将多个子ADC组合成一个ADC系统,可以实现比单独的子ADC[1]更快的采样速率。历史上,时间交错adc的主要缺点是需要紧密匹配子adc[2]的特性。近年来,由于应用需要非常宽带信号的数字化、功率高效子adc的可用性以及由深亚微米互补金属氧化物硅(CMOS)技术实现的微调技术,使得时间交错

weixin_44537056的博客 6732

【Zephyr电源与功耗专题】13_PMU电源驱动介绍

本文介绍的PMU芯片包含2路DCDC和6路LDO,在Zephyr实时操作系统下实现了完整的电源管理解决方案。

zero的博客 843

前端js入门——JavaScript 作用域

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

fenghulun的博客 7403

AHB—SRAMC项目(结构图,核心代码、Testbench架构)

文章目录一、AHB_SRAMC项目介绍1.1.AHB总线控制单元(ahb_slv_if.v)1.2.SRAM控制单元(sramc_top.v)1.3.主要的传输路径二、结构框图2.1.AHB_SRAMC结构图(重点)2.2.总线控制单元与SRAM控制单元结构图三、部分核心代码(重点理解)四、SystemVerilog Testbench架构(重点)五、目录结构 一、AHB_SRAMC项目介绍 本项...

Mr.翟的博客 3万+

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

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

weixin_44486539的博客 301

【STM32系统】基于STM32设计的锂电池电量/电压检测报警器系统

本设计旨在研究一个基于STM32F103C8T6微控制器的锂电池电量/电压检测报警器系统,应用于便携式电子设备电池管理。系统通过STM32的ADC模块对18650锂电池电压进行采集,利用LCD1602显示模块实时显示电池电压,当检测到电池电量不足或电压异常时,蜂鸣器报警模块会发出警报提醒用户。系统采用简单的硬件结构和优化的软件架构,通过对实际电池电压数据的检测、处理和显示,实现了低功耗、实时监测的锂电池管理功能。本文将介绍系统的设计原理、硬件电路、软件实现以及调试测试过程。

嵌入式阿齐Archie 1万+

Linux 设置双网卡通信,外网网卡和内网网卡

背景,Linux 主机已经安装了内网、外网 2 张网卡,目前外网网络已通,需要设置内网网卡转发通内网 内网需要通信的设备的网段,如果 10.99.0.0 代表 10.99 网段的所有 IP 表示 10.xx 网段走 10.xx.xx.xx 这个网关转发 :内网网卡设备示例 2、设置启动自动生效 打开 文件,如果没有则创建该文件,然后在文件内写入如下的内容修改上面的语句 为 即可 示例...

简简单单Onlinezuozuo 6605

【Js】JavaScript作用域

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

m0_57135756的博客 307

通过Python实现物联网金橙子自动打标

对于自家公司使用金橙子打标卡时,为了与生产线或者PLC联动等,往往需要对金橙子打标卡进行二次开发,而在二次开发中不得不涉及到MarkEzd.dll这个文件,而这个dll文件网上版本多不说,一般都没法直接使用,最后还不得不花大价钱购买专用库。而本文针对这个问题,涉法通过python来绕过MarkEzd.dll文件,直接进行自动化控制EzCad来实现联动,可应用于实际生产。文章最后拓展一下以物联网的形式,实现手机平台等登录网页,输入想要的印字内容后,远程打印的案例。

lylelo的博客 3365

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

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

阿发狗伪原创 132

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

【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

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

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

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

【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、付费专栏及课程。

余额充值