深入javascript计划三:javascript编译器、引擎、作用域介绍

不止于修改器:用Cheat Engine(CE)的Lua脚本和D3D Hook打造你的游戏辅助界面 本文深入探讨了Cheat Engine(CE)的高级功能,包括Lua脚本自动化和D3D Hook技术,帮助用户从基础内存扫描升级到开发具有专业图形界面的游戏辅助工具。通过实战示例和优化策略,展示了如何创建高效、稳定的游戏辅助系统,并打包为独立训练器。 阅读详情

如果有问题,请大家麻烦指出来。

javascript我们通常把它归类为"动态"或"解释执行"语言,但事实上它是一门编译语言。它与传统编译语言(C语言等)不同,它不是提前编译,而且并不会产生可移植的编译结果。

(传统编译语言)编译器工作流程

通常分为三个步骤:

   1.分词/词法分析(Tokennizing/Lexing)

        这个过程会将由字符组成的字符串分解成有意义的代码块(把输入的字符串分解为一些对编程语言有意义的代码块),这些代码块被称为"词法单元"(token)。

   2.解析/语法分析(Parsing)

        这个过程是将上一步的词法单元流(数组)转换成一个由元素逐级嵌套所组成的代表了程序语法结构的树。这个树被称为"抽象语法树"(Abstract Syntax Tree,AST)。

   3.代码生成

      这个过程是将上一步的AST转换为可执行代码(机器指令)的过程被称为代码生成。

JavaScript编译器工作流程

在线调试工具jointjs

在线调试工具esprima

1.分词/词法分析(Tokennizing/Lexing)解释如上文一致,例子:

var a = 2;

小提示:空格是否会被当作词法单元,取决于空格在这门语言是否有意义。

2.解析/语法分析(Parsing)解释如上文一致,例子:

var a = 2;

 

3.代码生成 解释如上文一致

简单的描述一下就是有某种方法可以将var a  = 2; 的AST转化为一组机器指令,用来创建一个叫作a的变量(包括分配内存地址等),并将一个值存储在a中。

JavaScript编译器工作流程与(传统编译语言)编译器工作流程有什么区别?

javascript编程过程与(传统编译语言)编译过程都是分三个步骤。但是javascript引擎会在语法分析和代码生成阶段进行优化(例如针对冗余元素进行优化),还会对编译过程进行优化(如JIT,延迟编译或者重编译),目的是缩短编译过程,保证性能最佳。

JIT(Just In Time)是什么?

每当一个程序在运行时创建并运行一些新的可执行代码,而这些代码在存储于磁盘上时不属于该程序的一部分,它就是一个JIT。

JavaScript中的引擎、编译器、作用域是如何配合工作?

引擎:从头到尾负责整个javascript程序的编译及执行过程。浏览器不同,其引擎也不同,比如Chrome采用的是v8,Safari采用的是SquirrelFish Extreme。

编译器:负责词法分析、语法分析及代码生成。

作用域:负责收集并维护由所有声明的标识符(变量)组成的一系列查询,并实施一套严格的规则,确定当前执行的代码对这些标识符的访问权限。通俗来讲就是在运行时代码中的某些特定部分中变量,函数和对象的可访问性。换句话说,作用域决定了代码区块中变量和其他资源的可见性。在说明白一点:也就是变量的管家用一个事先定义好的规则(词法作用域),管理变量的查询与访问。

先讲讲作用域

作用域有两种模型:

  1. 词法作用域
  2. 动态作用域(javascript中没有)

词法作用域(静态作用域)和动态作用域

词法作用域(书写时定义):

我们将"作用域"定义了一套规则,javascript引擎根据这套规则来管理变量的查找与引用,词法作用域就是其使用的规则,在编译器进行词法化时,会根据你写代码时将,变量和块作用域写在哪里,来决定规则的内容。这其中又包含了块作用域这个概念,只要记住ES6之前没有块作用域,只有函数有作用域,即:函数内部是一个独立的块作用域。(有个特例:catch语句块内也是独立的作用域。) 通俗来讲:词法作用域是定义在词法阶段的作用域,换句话来说就是在执行之前就确定了它可以应用哪些地方的作用域(变量)。

javascript引擎可以通过eval和with来改变词法作用域,但这两种会导致引擎无法在编译时对作用域查找进行优化, 因此不要使用它们。

例子:

function foo(a) {
    var b = a + 2;
    function bar(c) {
        console.log(a, b, c);
    }
    bar(b * 3);
}
foo(2); // 2, 4, 12

看图:

讲解:

1. a 会先在bar()作用域查找有没有a,有就返回,没有就继续往上查找

2. a往foo()作用域查找有没有a,有就返回,没有就继续往上查找直到全局作用域,还没有找到就抛出异常。

.....

动态作用域(运行时定义):

javascript例子(javascript是不支持的):


var value = 1;

function foo() {
    console.log(value); // 打印 1
}

function bar() {
    var value = 2;
    foo();
}

bar();

讲解:

如果javascript支持的话在foo()作用域查找value,查找不到会往bar()作用域查找 然后 打印 2。

但是javascript不支持它会在foo()作用域查找value,查找不到会往在当前函数上边查找(在例子中就是全局作用域) 然后 打印 1。

作用域范围

  1. 全局作用域
  2. 函数级作用域
  3. 块级作用域(es6)

先说一下var、let(es6)、const(es6)!

编译器将var 声明的变量提升至作用域顶部,将let或const声明的变量放到暂时性死区(temporal dead zone, TDZ)。访问暂时性死区(TDZ)中的变量会触发运行时的错误,只有执行过变量声明语句后,变量才会从时暂时性死区(TDZ)中移出,这时才可访问。

全局作用域:

var a = 1; // 全局变量

function foo() { // 全局函数

   b = 2; // 未定义却赋值(LHS)会创建一个全局变量b,然后赋值

   var name = 'an'; // 局部变量

   function bar() { // 局部函数
       console.log(name);
   }
}

console.log(name) // ReferenceError: name is not defined

函数级作用域:

function foo() {
    var name = "an";
    function sayName() {
        console.log(`hello, ${name}`);
    }
    sayName();
}
foo() // hello, an
console.log(name) // ReferenceError: name is not defined
sayName() // ReferenceError: sayName is not defined

值得注意的是, if、switch、while、for 这些条件语句或者循环语句不会创建新的作用域, 虽然它也有一对{}包裹. 能不能访问的到内部变量取决于声明方式(var 还是 let/const),因为var 会提升到当前作用域顶部!

块级作用域

JavaScript 没有块级作用域的情况,在es6 let 和 const 的出现解决了这样的情况,所声明的变量在指定块的作用域外无法被访问。

function test() {
    let name = "an"
    console.log(name) // an
    function bar() {
        console.log(name) // an
    }
    bar()
}
let name = "name" || var name = "name"
test()
console.log(name) // name
{
  let name = ""
}
console.log(name) // ReferenceError: name is not defined

作用域链

通俗来讲:当访问一个变量时,解释器会首先在当前作用域查找标示符,如果没有找到,就去父作用域找,直到找到该变量的标示符或者不在父作用域中,这就是作用域链,值得注意的是,每一个子函数都会拷贝上级的作用域,形成一个作用域的链条。

例子:

function foo(a) {
    var b = a + 2;
    function bar(c) {
        console.log(a, b, c);
    }
    bar(b * 3);
}
foo(2); // 2, 4, 12

讲解:

1. a 会先在bar()作用域查找有没有a,有就返回,没有就继续往上查找

2. a往foo()作用域查找有没有a,有就返回,没有就继续往上查找直到全局作用域,还没有找到就抛出异常。

....

先讲讲引擎的提升

大部分编程语言都是先声明变量再使用,但是在javascript中,并不是这样。

因为javascript引擎拿到代码的时候,编译器已经做了一些转换,编译器为什么要作这个事情?

因为它要在第一步就找到所有的声明,并且用合适的作用域将他们关联起来,这也正是词法作用域的核心。表现为:包括变量和函数在内的所有声明都会在当前块作用域内被首先处理,即类似于提升到最前面声明,但是复制处理操作因为是在执行阶段,因此编译阶段他们原地待命等待执行。换句话说,就是编译阶段的一部分工作就是找到所有的声明,并且使用合适的作用域将它们串联起来,变量和函数在内的所有声明都会在代码执行前被处理。

变量提升

看下面代码:

console.log(a); // undefined
var a = 1;

javascript引擎会拆分成

var a;
console.log(a);
a = 2;

javascript引擎会将var a = 2; 拆分成 var a; a = 2;当作两个单独的声明,第一个是在编译阶段的任务,第二个是在执行阶段的任务。

换句话说, 这个过程将会把变量和函数声明放到其作用域的顶部,这个过程就叫做提升。

可能你会有疑问,为什么 let 和 const 不存在变量提升呢?

这是因为在编译阶段, 当遇到变量声明时,编译器要么将它提升至作用域顶部(var 声明),要么将它放到暂时性死区(temporal dead zone, TDZ),也就是用 let 或 const 声明的变量。访问暂时性死区(TDZ)中的变量会触发运行时的错误,只有执行过变量声明语句后,变量才会从时死区(TDZ)中移出,这时才可访问。

例子:

console.log(a) // ReferenceError: Cannot access 'a' before initialization
let a = "a";

// 分割线

console.log(a) // ReferenceError: Cannot access 'a' before initialization
const a = "a";

函数提升

函数声明和变量声明都会被提升,但值得注意的是,函数首先被提升,然后才是变量。

定义一个函数有两种方式:函数声明(function definition/declaration/statement)和函数表达式( function expression)。

foo(); // 1
var foo;
function foo() {
  console.log(1);
}
foo = function() {
  console.log(2);
}

javascript引擎会理解成

function foo() {
   console.log(1);
}
foo(); // 1
foo = function() {
   console.log(2);
}

注意,var foo尽管出现在function foo() 声明之前,但是它是重复的声明(会忽略),因为函数声明会被提升到普通变量之前。

函数表达式不可提升

a();  // TypeError: a is not a function
var a = function f1() {
  console.log("a");
}

先讲讲引擎的LHS、RHS

LHS:赋值操作的目标是谁(对变量进行赋值所执行的查询)

RHS:谁是赋值操作的源头(找到并使用变量所执行的查询)

例子:

var a; // LHS 寻找a,未找到,通知作用域声明一个新变量,命名为a
a = 2; // LHS 找到a并给其赋值为2
console.log(a); // RHS 找到a的值2,并将其输出

例子:

function test(a) {
   // 这里隐式包含了 a = 2 这个赋值,所以对 a 进行了 LHS 查询
   var b = a;
   // 这里对 a 进行了 RHS 查询,找到 a 的值,然后对 b 进行 LHS 查询,把 2 赋值给 b
   return a + b; 
   // 这里包含了对 a 和 b 进行的 RHS 查询
}
var a = test(2)
// 这里首先对 test() 进行 RHS 查询,找到它是一个函数,然后对 a 进行 LHS 查询把 test 赋值给 a 

区分LHS、RHS很重要!

因为在变量还没有声明(在任何作用域中都无法找到该变量)情况下,这两种查询行为是不一样的。

function test(a) {
   console.log(a + b)
   b = a
}
test(2)

以上代码对b进行RHS的时候无法找到该变量的值,则会抛出ReferenceError异常。

如果是LHS找不到变量:

非严格模式下,会在全局作用域中,创建一个具有该名称的变量,

严格模式下,会抛出与RHS类似的异常。

看例子:

function test() {
    a = 100
    console.log(a) // 100
}
test()
console.log(a) // 100
console.log(c) // ReferenceError: c is not defined

好了就讲这里。回到原文!

var a = 2;

这段程序的工作流程:

当你看见 var a = 2; 这段程序时,很可能认为这是一句声明,事实上javascript引擎认为(这个是提升)把它们拆成 var a; a = 2;有两个完全不同的声明,一个由编译器在编译时处理,另一个在引擎运行时处理。

    因为javascript引擎拿到代码的时候,编译器已经做了一些转换,编译器为什么要作这个事情?

    因为它要在第一步就找到所有的声明,并且用合适的作用域将他们关联起来,这也正是词法作用域的核心。

代码执行前会对其进行编译,首先编译器会词法分析,然后词法单元流(数组)解析成语法树,最后进行代码生成,别忘了代码生成就是将语法树转化为一组机器指令。

  1. 生成代码前编译器会询问作用域是否有该名称的变量(LHS),如果有,忽略该声明,如果没有,会要求作用域在当前作用域的集合中声明一个新变量,并命名为a。
  2. 接下来为引擎生成运行时所需要的代码,这些代码用来处理a = 2;这个赋值操作(LHS),运行时引擎首先会问作用域,在当前作用域集合中是否有一个叫作a的变量,如果找到就会对他赋值(如果没有就继续往上级作用域查找,如果到根作用域仍然找不到javascript引擎就会抛出一个异常)。

继续往下看!LHS、RHS版:

var a = 2;
console.log(a);

1 .编译器:作用域,我需要对a进行LHS查找,你见过么?

2 .作用域:我这找到根都没看到啊,要不咱声明一个吧!

3. 编译器:好,建好了,那我生成代码了,引擎,给你你要的代码。

4 .引擎:收到,咦,需要一个a啊,作用域,帮我LHS找一下有没有?

5. 作用域: 找到了,编译器已经帮忙声明了。

6. 引擎:好的,那我对它赋值。

7. 引擎:作用域,不要意思,我碰到一个console,需要RHS引用

8 .作用域: 找到了,是个内置对象,拿走不谢。

9 .引擎: 好的作用域,对了能在帮我确认一下a的RHS么?

10 .作用域:确认好了,没变,拿去用吧,他的值是2

11. 引擎:好咧,我把2传递给log(..)

谈谈闭包

我们上文以及讲了作用域以及作用域链,然后在来看看面试多数问到的闭包。

什么是闭包?

红宝书(p178)上对于闭包的定义:闭包是指有权访问另外一个函数作用域中的变量的函数。

闭包产生的原因?

首先要明白作用域链的概念(上文也讲过),其实很简单,在ES5中只存在两种作用域————全局作用域和函数作用域,当访问一个变量时,解释器会首先在当前作用域查找标示符,如果没有找到,就去父作用域找,直到找到该变量的标示符或者不在父作用域中,这就是作用域链,值得注意的是,每一个子函数都会拷贝上级的作用域,形成一个作用域的链条。 比如:

var a = 1;
function f1() {
  var a = 2
  function f2() {
    var a = 3;
    console.log(a);//3
  }
}
f1();

讲解:f2(),console.log(a)的时候会先查找自身作用域看看有没有a这个变量,如果没有就会查找f1()作用域,如果没有会查找全局作用域。不过f2查找自身的时候就找了 所以就 直接 输出 3。

闭包产生的本质就是,当前环境中存在指向父级作用域的引用。例子:

var name = "an";
function f1() {
    var a = 2
    function f2() {
      a++;
      console.log(a);
      console.log(name);
    }
    return f2;
  }
  var x = f1();
  x(); // 3 an
  x(); // 4 an
  x(); // 5 an
  // console.log(name); // an
  // console.log(a); // ReferenceError: a is not defined

讲解:这里x()会拿到f1()作用域和全局作用域中的变量,输出 3 an ....。因为在当前环境中,含有对f2()作用域的引用,f2()恰恰引用了全局作用域、f1()作用域。因此f2()作用域可以访问到f1()的作用域和全局作用域的变量。

来个难一点的例子:

var f3;
function f1() {
  var a = 2
  console.log("---f1---")
  f3 = function() {
    console.log(a);
  }
}
f1(); // ---f1---
console.log(f3) // [Function: f3]
f3(); // 2

// 如果直接访问
// console.log(f3) // undefined

讲解:让f1()执行,给f3赋值一个函数,f3拥有全局、f1()、本身作用域的访问权限,f3()打印a,会先查找自身作用域,没有就查找f1的作用域(还没有就查找全局作用域),找到之后返回打印 2。

经典的面试题

for ( var i=1; i<=5; i++) {
	setTimeout( function timer() {
		console.log( i );
	}, i*1000 );
}

为什么会全部输出6?如何改进,让它输出1,2,3,4,5?(方法越多越好)

因为setTimeout为宏任务,由于JS中单线程eventLoop机制,在主线程同步任务执行完后才去执行宏任务,因此循环结束后setTimeout中的回调才依次执行,但输出i的时候当前作用域没有,往上一级再找,发现了i,此时循环已经结束,i变成了6。因此会全部输出6。

解决方法:

1、利用IIFE(立即执行函数表达式)当每次for循环时,把此时的i变量传递到定时器中

for(var i = 1;i <= 5;i++){
  (function(j){
    setTimeout(function timer(){
      console.log(j)
    }, 0)
  })(i)
}

2、给定时器传入第三个参数, 作为timer函数的第一个函数参数

for(var i=1;i<=5;i++){
  setTimeout(function timer(j){
    console.log(j)
  }, 0, i)
}

3.使用es6的let

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

参考:

《你不知道的javascript》上卷

http://47.98.159.95/my_blog/js-base/004.html

https://github.com/creeperyang/blog/issues/16

https://www.jianshu.com/p/5ebf2ad6def2

https://juejin.im/post/5ca995626fb9a05e1a7aabd8#heading-7

普冉PY32F003定时器实战:从HSE时钟配置到500ms精准闪烁LED(附完整代码) 本文详细解析了普冉PY32F003单片机定时器的实战应用,从HSE时钟配置到实现500ms精准LED闪烁。通过完整的代码示例和深入的技术分析,帮助开发者掌握定时器参数计算、中断优先级管理及调试技巧,适用于各类嵌入式开发项目。 阅读详情

相关推荐

CMOS 半加器和全加器&&数字集成电路&& Cadence Virtuoso

数字集成电路——半加器和全加器

计科小学生的博客 1万+

javascript编译器、引擎、作用域

几乎所有的编程语言最基本的功能之一,就是能够存储变量当中的值,并且能够在之后对这个值进行访问或修改。事实上,正是这种存储和访问变量的值的能力将状态带给了程序。 我们需要考虑几个问题:变量存储在哪里?最重要的是,程序需要如何找到它们?这些问题需要一套设计良好的规则来存储变量,并且之后可以方便地找到这些变量。这套规则被称为作用域。 javascript编译器、引擎、作用域 编译器负责语法分析以及代码...

qq_37149397的博客 290

CANoe_Demo_下载以及安装教程

CANoe Demo下载安装流程

Jar_Lee的博客 1万+

JavaScript编译原理:编译器,引擎,作用域

首先,JavaScript确实是一门编译型语言,与C等典型编译型语言相比,区别在于JavaScript的编译过程(通常)是在实际执行前进行的,而且并不会产生可移植的编译结果。

曹定栓的博客 826

模型检测--工具KeYmaera

论文:KeYmaera: A Hybrid Theorem Prover for Hybrid Systems 作者:Andre Platzer and JanKeYmaera摘要1 介绍2用于混合系统的KeYmaera验证工具3混合系统,混合自动机和混合程序 摘要 KeYmaera是一种用于混合系统的混合验证工具,它结合了演绎,实数代数和计算机代数证明者技术。它是自然的自动和交互式定理证明器 混合系统的规范和验证逻辑。 KeYmaera支持差分动态逻辑,它是用于混合程序的实值一阶动态逻辑,是混合自动机的程

ziigea的博客 1077

Android开发Intent详解

本文详解Android开发Intent。

qq_30725967的博客 2414

编译器(Compiler)及c/c++编译器安装(c+安装)、开发环境

文中主要讲述了常用编程语言的编译器的特点,GCC、MinGW、MinGW-w64 、TDM-GCC、Cygwin、MSYS、MSYS2的区别,MinGW-w64编译器套件下载及安装,安装后的环境变量配置(设置),编译器的运行及其与集成开发环境的关系、编译器的来源。

Python基础详解教程,让编程变得简单! 1万+

基于Java+SpringBoot+Vue的中小企业设备管理系统的设计与开发(源码+lw+部署文档+讲解等)

💗博主介绍:✌新人博主,工作经验两年+、专注于Java、小程序技术领域和毕业项目实战✌💗🌟文末获取源码+数据库🌟

2301_76502068的博客 1383

静态编译和动态编译,java与javascript区别总结

1.静态编译和动态编译        静态编译是程序在编译时就已经确定好了所有类之间的关系,要运行程序所有类 都缺一不可,若在开始运行时就把其中的某类文件丢失,就会产生 NoClassDefFoundError错误,程序会终止,在程序运行前的装载期间就把要用到 的类加入到内存当中,它的特征是new关键字 再加上类构造器,这个类构造器的 命名在程序编译后就不可更改了          ...

naruto_Mr的专栏 526

openclaw 保姆级部署与核心玩法解析:国产DeepSeek模型 + 飞书

OpenClaw是一款功能强大的开源AI个人助理,支持全平台私有化部署,数据完全本地掌控。它不仅可通过聊天窗口直接操控电脑(安装软件、创建项目),还支持接入飞书等主流通讯工具,化身24小时在线的智能助理。本文提供了从零开始的详细部署教程,涵盖基础安装、模型配置(如GLM-4、DeepSeek)到飞书集成的完整实战指南,助你将这款“核动力”AI助手快速融入日常工作流。

甘蓝的专栏 2998

AutoSAR EcuM系列01- EcuM模块的功能概述和变体类型

在【ECU的软硬件架构】文章中我们了解ECU的功能和组成,那么ECU具体是怎么启动的呢?我们知道,AutoSAR标准架构有三层,即APPL应用层、RTE层和BSW层。而这些层又被进一步划分为更多单独的组件,如BSW层可能有80多个组件。在ECU启动时,这些组件必须相互交互,有时也必须以某种顺序交互。这些组件的启动顺序由ECU管理器模块或EcuM处理。EcuM负责整个ECU的初始化和去初始化,包括对一些系统模块如。......

1766

编译器(Compiler)及C/C++编译器安装(c+安装)

机器语言是二进制在计算机中的表达,通过高低电平(高电压叫高电平,低电压叫低电平)来表示1和0的二进制。1和0的二进制构成机器指令(instruction),也称为机器码或计算机指令,计算机按照二进制的机器码执行。一条机器指令(机器码)必须包括操作码和地址码(或操作数)两部分。操作码指出该指令完成操作的类型,比如:加、减、乘、除、传送等。地址码指出参与操作的数据和操作结果存放的位置。机器指令在CPU中会进一步翻译为具体的操作,以便计算机按具体的操作执行。

zmbaliqq的专栏 4646

AE 与 ISP 参数联动机制解析:自动曝光系统与图像信号处理模块协同设计实践

AE(自动曝光)并不是一个独立的图像控制模块,而是与 ISP(Image Signal Processor)深度耦合运作的系统协同体。其输出的曝光参数直接决定了图像处理链路中 Gamma 曲线选择、黑电平补偿、去噪级别、边缘增强等一系列关键参数的取值。本文基于主流平台(如高通、MTK、海思)的工程实战经验,详细剖析 AE 与 ISP 在曝光驱动、调节优先级、图像还原逻辑等环节的联动机制,并结合拍照与视频等不同场景,给出可落地的联调方法。

努力分享一些人工智能、计算机视觉、影像等相关的知识干货! 1527

深入理解 JavaScript 三大作用域:全局作用域、函数作用域、块级作用域

对于多数编程语言,最基本的功能就是能够存储变量当中的值、并且允许我们对这个变量的值进行访问和修改。那么有了变量之后,应该把它放在哪里、程序如何找到它们?是否需要提前约定好一套存储变量、访问变量的规则?答案是肯定的,这套规则就是作用域。说到作用域那就不得不先说一说编译原理(由于编译原理是一个比较底层的内容,这里只简单介绍,后面会有一篇文章专门介绍 JS 编译原理)。JavaScript 引擎进行编译的步骤和传统的编译语言非常相似,在传统的编译语言中,程序中的代码在执行之后会经历三个步骤:词法分析、语法分析、代

前端梦工厂 2030

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

(一)编译器+引擎+作用域的关系

文章目录要知道的传统编译语言的流程分词/词法分析解析/语法分析代码生成js引擎中的编译器三个搭档引擎编译器作用域var a = 2 发生了什么编译器的小术语 要知道的 我们通常将JavaScript归类为“动态”或“解释执行”语言,但事实上它是一门编译语言 与传统的编译语言不同,js不是提前编译的,编译结果也不可以在分布式系统中进行移植,尽管如此,js引擎进行编译的步骤和传统的编译语言还是非常的相似,但他在某些环节可能会更复杂 传统编译语言的流程 在传统编译语言的流程中,如果程序中的一段源代码需要执行,

qq_43952245的博客 684

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

JavaScript深度理解——作用域

正确理解JS作用域有助你更好的理解这门语言的精髓。存储和访问变量,是任何一种编程语言最基本的功能之一,变量存在哪里?程序需要时如何找到它?这些问题需要一套良好的规则来规范,这套规则,就叫做作用域。

qq_41497756的博客 2344

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

你不知道的javascript:作用域,编译器,js引擎的关系

一,作用域概念: 我的理解是:js引擎或编译器对变量的操作可以起作用的一块空间,脱离了这个空间,变量就“无效”了。 专业的解释是:作用域是 根据名称查找变量的一套规则。(现实中,通常需要同时顾及几个作用域) 二,常规的编译过程:三步:对 var a =2;的编译步骤 1,分词/词法分析:将字符串分解成代码块,又称词法单元。var 、a、=、2、; 2,解析/语法解析:词法单元流(数组)生成AST抽象语法树 3,代码生成:将AST转换成可执行的代码。(将AST转化为一组机器指令,用来创建一个叫做a的变量

yudianvictor的博客 171

javascript引擎、编辑器、作用域之间的合作

引擎:从头到尾负责js程序编译以及执行过程 编辑器:负责语法分析以及代码生成 作用域:负责收集维护所有声明的变量​ 是一套规则,用于管理引擎如何确定在何处以及如何查找变量实例 如果我们写一段程序 var a =2; 编译器询问作用域是否存在变量a 有,忽略 没有,生成一个叫做a的代码,并生成引擎运行的代码 引擎询问作用域,是否存在a变量 有,赋值 没有,抛出异常(undefined)

Efficiency9的博客 447

JavaScript的作用域与闭包

存储变量的值,并且之后可以对这个值进行访问或修改, 是几乎所有变成语言最基本的功能之一. 但是这些变量存在哪里, 如何快速找到他们, 这需要设计一套良好的规则来存储变量, 这套规则被称为作用域。(— 《你所不知道的JavaScript(上卷) 》)在MDN作用域是当前的执行上下文,在其中的值和表达式“可见”(可被访问)。如果一个变量或表达式不在当前的作用域中,那么它是不可用的。作用域也可以堆叠成层次结构,子作用域可以访问父作用域,反过来则不行。简单来说: js 的作用域是变量或表达式的作用范围。

Angel_Tears_的博客 1037

【JavaScript高级】JavaScript的运行原理:V8引擎,JS代码执行原理,作用域和作用域链面试题

JavaScript的运行原理:V8引擎,JS代码执行原理,作用域和作用域链面试题

karshey的博客 736

你不知道的js作用域

想象一下,变量就像是住在一个个小房子里,而作用域就是管理这些房子的规则,告诉我们去哪里找到想要的变量,以及如何把东西放进变量的“小房子”里。如果没有作用域这个概念,程序就会变得像一个没有秩序的小镇,虽然也能运行,但会失去很多乐趣,发展也会受到限制。引擎从当前执行作用域开始找,如果找不到,就按照作用域链上的指示,去外层作用域找,一直找到全局作用域。假设你在一个大派对场地(全局作用域)里,进入了一个小房间(函数作用域),在小房间里找不到你想要的东西(变量),你就会回到大房间找,这就是作用域嵌套的概念。

qq_66118130的博客 774

Javascript 的编译器和作用域查找规则

一、编译器介绍 对于常见编译型语言(例如:Java)来说,编译步骤分为:词法分析->语法分析->语义检查->代码优化和字节码生成。 对于解释型语言(例如 JavaScript)来说,通过词法分析 -> 语法分析 -> 语法树,就可以开始解释执行了。 1 传统的编译步骤: 1、分词/词法分析 将字符组成的字符串分解成有意义的代码块(词法单元) 例: var a = 2 => var、a、=、2 2、解析/语法分析 将词法单元流(数组)转换成抽象语法树 3、代码生成 将 A

Dreamy_LIN的博客 649

js的函数作用域跟块级作用域

一,js中的作用域     js中除了全局作用域,还有函数作用域。     嗯,还有块级作用域。 二,函数作用域跟块级作用域的区别     当将代码看成一个IIFE时,全局作用域其实就是一个函数作用域。     那么函数作用域跟块级作用域的区别是什么呢?           函数作用域:变量在定义的函数内及嵌套的子函数内处处可见;           块级函数域:变量在离开定义的块级

huangjq36SYSU的博客 1万+

java javascript引擎_JavaScript解释引擎

看完本文,你就可以理解下面两个实例的原理。fun()console.log(num)function fun() {num = 20}// output: 20var num = 10fun()function fun() {console.log(num)var num = 20}// output: undefined一、背景1、 什么是JavaScript解析引擎?就是能够“读懂”JavaS...

weixin_31693157的博客 1198

你不知道的JavaScript之作用域

什么是作用域 编译原理 分词/词法分析 这个过程会将由字符组成的字符串分解成(对编程语言来说)有意义的代码块,这些代 码块被称为词法单元(token) 解析/语法分析 这个过程是将词法单元流(数组)转换成一个由元素逐级嵌套所组成的代表了程序语法 结构的树。这个树被称为“抽象语法树”(Abstract Syntax Tree,AST)。 什么是抽象树呢?在这个网站上可以在线的看到js源代码,也就是抽象树在线生成抽象树 代码生成 将..

fhw10204130的专栏 3322

JavaScript 作用域详解

本文首发于贝壳社区FE专栏,欢迎关注! 一、什么是作用域 编译原理 分词/词法分析(Tokenizing/Lexing) 这个过程会将由字符组成的字符串分解成(对编程语言来说)有意义的代码块,这些代 码块被称为词法单元(token)。例如,考虑程序var a = 2;。这段程序通常会被分解成 为下面这些词法单元:var、a、=、2 、;。空格是否会被当作词法单元,取决于空格在 这门语言中是...

weixin_33734785的博客 3872
上一篇: 深入javascript计划二:数据类型检测与数据类型抽象转换
下一篇: 深入javascript计划四:深入浅出this
An_s
博客等级 码龄10年 665粉丝 363原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

An_s

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值