js预编译(与C预处理区别)

2023-11-17

目录

1.函数体内

2.全局

注:window 属性和  imply global属性

3.全局和函数体内结合,优先顺序

例1:

例2:

例3(重要提示)


第一次学的时候以为和C预处理差不多,看了下才发现区别还蛮大的;

例1:

test();//打印出 a
function test(){
    console.log("a");
}

例2:

console.log(a); //打印undefined
var a = 10;
console.log(a); //直接报错

这里可以发现,跟C预处理不一样,js的预编译会先把全局变量先声明,所以才会有undefined;而C的预处理包括

  1.  宏定义指令(#define删除);
  2. 条件编译指令:处理所有的条件预编译指令。
  3. 头文件包含指令:处理#include 预编译指令。
  4. 特殊符号指令(比如注释符号)
  5. 等等

跟js差别蛮大的,我们这里来看预编译的例子。

1.函数体内

如下:

function fn(a){
    console.log(a);
    
    var a = 123;

    console.log(a);

    function a(){}

    console.log(a);

    var b = function(){}

    console.log(b);

    function d(){}
}
fn(1);

这里存在以a为名的变量,函数,赋值等操作,如果不懂预编译,可能会直接懵了,我们需要看预编译的顺序:

首先预编译发生在函数执行前一刻,一共四步:

  1. 创建AO对象Activation Object(执行期上下文);
  2. 找形参和变量声明,将变量和形参名作为AO属性名,值为undefined;
  3. 将实参值和形参统一;
  4. 在函数体中找函数声明,值赋予函数体;

所以我们可以把这个例子过一遍

1.首先创建AO对象

AO{

}

2.找形参和变量声明,将变量和形参名作为AO属性名,值为undefined

AO{
    a:undefined
    b:undefined
}

3.将实参值和形参统一

AO{
    a:1
    b:undefined
}

4.在函数体中找函数声明,值赋予函数体

AO{
    a:function(){}
    b:undefined //var b = function(){}不是函数声明,是赋值
    d:function(){}
}

四步完后,创建完AO对象,执行函数 fn(a),

  1. 执行第一句 console.log(a);AO对象的 a 为 function(){},即打印 function(){};
  2. 执行第二句,因为var已经在预编译处理过,所以变量声明不看,但是 a = 123没有走过,所以 a 赋值为123;AO里 a = 123;
  3. 执行第三句,a已经赋值为123,所以打印123;
  4. 执行第四句,function a(){} 在预编译已经处理过,所以不看,a 仍为123;
  5. 执行第五句,继续打印123;
  6. 执行第六句,function b 不看,已经执行过了。所以执行 b = function(){};AO里 b = function(){};
  7. 执行第七句,打印机 function (){};
  8. 执行第八句,预编译处理过,不处理跳过;

所以结果为:

ƒ a(){}
123
123
ƒ (){}

 

2.全局

全局预编译和函数体内大致相同,但全局没有形参实参,所以省略第三步

  1. 创建GO对象Global Object(执行期上下文);
  2. 找变量声明,将变量作为AO属性名,值为undefined;
  3. 在函数体中找函数声明,值赋予函数体;

 

注:window 属性和  imply global属性

1.任何全局变量都是 window 的属性,我们可以这么调用

console.log(window.a); //打印 a(){},跟写console.log(a)结果相同
function a(){}

所以这里的 GO实际上跟 window是一样的。

2.所有未经声明就赋值的变量都在 imply global 属性中,实际上也就是在 GO中

例如:

function test(){
    var a = b = 123;
    console.log(window.a); //undefined
    console.log(window.b); //打印123
}
test();
//生成 AO 对象,AO对象中含有 a,而 b 因为没有声明,属于 GO 对象

 

3.全局和函数体内结合,优先顺序

例1:

console.log(test);
function test(test){
    console.log(test);
    var test = 234;
    console.log(test);
    function test(){};
}
test(1);
var test = 123;

预编译顺序:

1.首先找全局变量

GO{
    test:undefined   
}

2.找函数声明

GO{
    function test(){ ... }   
}

3.开始执行,console.log(test),即打印function(){...}

4.function test 在预编译已经声明了,所以跳过,走到 test(1) 这一句,开始执行,生成 AO;

AO{

    //test:undefined; 这句最后被 实参1 覆盖

    //test:1; 这句最后被 function(){}覆盖

    test:function(){}

}

5.所以走到函数内第一句console.log(test),打印 function(){}

6.后面的几句跟上述相同,赋值,打印234,跳过函数声明;

:如果AO上没有要打印的变量,去GO继续找;

 

例2:

global = 100;
function fn(){
    console.log(global);
    global = 200;
    console.log(global);
    var global = 300;
}
fn();
var global;

首先预编译,找变量声明,var global放入 GO 对象,然后继续放入 fn函数;

然后执行程序,GO中 global = 100,执行 fn();

进入函数后,进行预编译,生成 AO对象,加入 var global ,所以第一个打印是 undefined;(先 AO没有的话,再是GO)

后面那个打印即200;

 

例3(重要提示)

function test(){
    console.log(b);
    if(a){
        var b = 100;
    }
    console.log(b);
    c = 234;
    console.log(c);
}
var a;
test();
a = 10;
console.log(c);

这里 GO 和 AO 的执行顺序按照之前写的一样,遇到 if 或者其他比如 for等等,都不需要管,直接拿出变量声明即可;

所以这里的执行顺序,

  1. GO对象,加入 var a,加入 function test();
  2. 运行程序,在 test() 进入函数,然后创建 AO 对象;
  3. AO 对象 加入 变量声明 var b;所以打印 undefined
  4. 然后执行程序;由于 a 还是 undefined,所以 if 不执行,打印 undefined
  5. c = 234,未声明变量赋值,所以在 GO 中加入,打印 c 的时候,AO中没有,但是 GO 中存在,打印234
  6. 然后跳出函数,console.log(c),由于 c 在 GO 中,所以打印234

 

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

js预编译(与C预处理区别) 的相关文章

随机推荐

  • 【图像处理】 常用边缘检测算法对比分析

    边缘的定义 首先介绍什么是边缘 在数字图像中 边缘是指图像局部变化最显著的部分 边缘主要存在于目标与目标 目标与背景之间 是图像局部特性的不连续性 如灰度的突变 纹理结构的图标 颜色的图标等 尽管图像的边缘点产生的原因各不相同 但他们都是图
  • [操作系统] 分页存储管理中的页表项长度

    看到很多人有疑问 读到这里的时候我也有疑问的 在操作系统的分页存储管理方式中 写道 将页表始址与页号和页表项长度的乘积相加 便得到该表项在页表中的位置 于是可从中得到该页的物理块号 将之装入物理地址寄存器中 列出式子出来 页表始址 页号x页
  • Java excel poi 下载模板功能无法在Microsoft Excel 打开,但是可以WPS Excel打开

    问题 并且只显示前几个字段 后面的几个字段不显示 版本使用
  • 我的 Android 求职简历

    昨晚在Diycode的微信交流群里面 有位在校的童鞋想要找一份开发的实习工作 他把简历做好后在群上共享了一份 我看到后便下载了一份 看了看简历内容 我在想如果我是招聘单位看简历的 这份简历可以说是基本没戏的 因为内容基本和开发没有多大关系
  • Qt5Error:msvc-version.conf loaded but QMAKE_MSC_VER ins‘t set

    错误描述 msvc version conf loaded but QMAKE MSC VER ins t set 解决方案 这种情况一般都是修改了项目的配置之后出现的 也就是 qmake stash文件出错 删除这个文件再进行重新编译即可
  • 基于python的布尔盲注爆破脚本(sqli-libs第八关)

    写这个脚本的原因是因为布尔爆破步骤的繁琐 因此写下这个半自动化脚本来提升效率 只需输入url和标志词便可开始爆破 下面结合sqli libs第八关来详细说明 这一关是布尔盲注 布尔盲注用于页面没有回显的情况下 但是心细的同学会发现当我们注入
  • 使用Microsoft.Reporting. WebForms中ReportViewer报表查看器(Server方式)

    添加Web Reference http
  • Flex程序编译

    Makefile三要素 目标 依赖 命令 详解可见makefile 编写 周北 CSDN博客 makefile 编写 Makefile中常用函数和自动化变量 wildcard 扩展通配符 例 OBJECTS wildcard o 该找到目标
  • C++构造函数中不调用虚函数的原因

    今天在看网上一篇帖子的时候看到这个问题 试讲关于C 对象虚函数表和类型信息的 RTTI 的 正好看到了如下内容 这个是为什么在构造函数中不能调用虚函数的原因 因为任何时候在基类中的虚函数调用 都不可能到达子类的实现 因为子类的虚表初始化是在
  • [docker]搭建elasticsearch服务

    1 拉取镜像 docker pull elasticsearch 8 7 0 如果需要其他版本的话 访问 Dockerhttps hub docker com ela
  • QT从入门到入土(四)——文件的读写操作

    引言 文件的读写是很多应用程序具有的功能 甚至某些应用程序就是围绕着某一种格式文件的处理而开发的 所以文件读写是应用程序开发的一个基本功能 Qt 提供了两种读写纯文本文件的基本方法 用 QFile 类的 IODevice 读写功能直接进行读
  • uniapp中的分享功能实现(APP,小程序,公众号)

    uniapp中的分享功能实现 APP 小程序 公众号 1 APP端的分享 app端的分享可以直接使用uniapp封装的方法uni share uni app的App引擎已经封装了微信 QQ 微博的分享SDK 开发者可以直接调用相关功能 可以
  • Android交叉编译OpenCV+FFmpeg+x264的艰难历程

    前言 如果你没有兴趣看完本文 只想获得可编译的代码或编译后的产物 可以直接点击下面的链接 跟随步骤编译代码或直接下载我编译好的产物 注 编译顺序要按照 x264 gt FFmpeg gt OpenCV 这样来 x264 FFmpeg Ope
  • 使用less处理重复性background-image定位问题

    1 问题描述 使用angular的列表循环解释问题 其他框架类似 css上面使用flex布局 index html代码 div class container div class item div class div p class ite
  • CH3-HarmonyOS开发基础

    文章目录 背景 目标 一 APP 1 1 APP包组成 1 2 APP和HAP结构 二 Ability 2 1 Ability 2 2 pack info 三 libs库文件 3 1 HAR 四 resources资源文件 4 1 reso
  • shiro框架---关于用户登录退出接口的介绍

    接上一篇文章shiro框架 shiro配置用户名和密码的注意 项目已分享到GitHub上 如果需要的可以看下 springboot shiro项目Git下载地址 在我前几篇文章里有shiro配置的文件下载包 下载后里边有四个配置文件Shir
  • 618省心凑背后的新算法——个性化凑单商品打包购推荐

    作为购物导购链路的一个重要环节 凑单旨在快速帮助用户找到达成某个满减门槛 比如满300减50 的商品 完成性价比最高的跨店组合结算 前言 背景 凑单是一个历史悠久的场景 伴随着长期优化并不断升级 为用户决策提供了便捷通道 作为购物导购链路的
  • Nginx部署前端,并转发2个后台,实现负载均衡

    一 vue打包 cmd进入项目目录 执行 npm run build 会在改目录生成dist文件 假设dist目录是 D dist 二 部署 下载nginx 修改nginx conf 在http 中加入 upstream myapp1 se
  • 在SQL中直接使用存储过程查询返回的结果集

    在实际使用存储过程是 有时我们希望先判断存储过程的返回结果集是否有记录 然后走不同的业务逻辑 这是就需要在SQL语句中直接读取到存储过程的返回结果集 方式如下 先按照存储过程结果集定义一个变量 declare tbl table 门诊号 v
  • js预编译(与C预处理区别)

    目录 1 函数体内 例 2 全局 注 window 属性和 imply global属性 3 全局和函数体内结合 优先顺序 例1 例2 例3 重要提示 第一次学的时候以为和C预处理差不多 看了下才发现区别还蛮大的 例1 test 打印出 a