sqlcommand 执行多个储存过程是报错_JS执行流程简述(一)

b23f2128ecdf9270ba8b747305587961.png

前言

我们都知道JS是按顺序执行的,那好的,我们来看下面这一段代码。

print();
console.log(str);
var str = 'hello world!';
function print() {
    console.log(str)
}

如果你写过js,那就知道,这段代码不会报错,会正常输出

1c7028c14d672637b5fa5d50957ee6d3.png


如果你不能理解,不要着急,我们删除var str = 'hello world',再执行:

print();
console.log(str);
function print() {
    console.log(str)
}

a5f9dfb4f145e860c16dc8da08d4adc2.png


报错,说好的顺序执行呢?不要着急,要了解js的运行方式,我们要先了解变量提升。

变量提升(Hosting)

在介绍变量提升之前,我们先通过以下两个例子来讲解JS中的声明和赋值。
在es6之前,JS都是通过var来声明变量。

var str = 'hello world!';

这一句等价于

var str; // 变量声明
str = 'hello world!'; // 赋值

接下来我们在看一下函数声明

function print() {
    console.log(str)
}

这个是一个完整的函数声明,没毛病。

var print = function () {
  console.log(str)  
}

这段代码是一个声明变量和赋值的过程,相当于

var print; // 变量声明
print = function () { // 赋值
    console.log(str)
}

所谓的变量提升,是指JavaScript在执行的过程中,JavaScript引擎把变量提升和函数的声明部分提升到代码开头的“行为”。变量被提升后,会给变量设置值为undefined。

模拟变量提升

3272c8a9d7913ee62df2a111449a78f2.png

JS 执行流程

从概念的字面上来看,“变量提升”意味着变量和函数的声明会在物理层移动到代码的最前面,正如我们所模拟的那样。但其实是:变量和函数声明在代码里的位置是不会改变的,而且在编译阶段被JavaScript引擎放入内存中。JS代码编译完成之后才会进入执行阶段。
大致流程如下图:

b51e3aca1d9f5a90fa1ac7def2c7b02a.png


接下来详细介绍一下流程,还是以刚刚的例子为例:

  • 变量提升阶段的代码
var str = undefined;
function print() {
    console.log(str);
}
  • 执行阶段的代码
print();
console.log(str);
str = 'hello world!';

JavaScript执行流程图

b3ef88d7237e5ca0a6d3f29be0f256c0.png


从上图可以看出,输入一段JS代码,经过编译后,会生成两部分内容:执行上下文(Execution context)和可执行代码。

执行上下文

是指JS执行一段代码时的运行环境,比如调用一个函数,就会进入这个函数的执行上下文,确定该函数在执行期间的用到变量如this、变量、对象、函数等。

在执行上下文中存在一个变量环境的对象(Variable Environment),该对象中保存了变量提升的内容,比如上面代码中变量str和函数print都保存在该对象中。

类似这样:

Variable Environment:
    str -> undefined,
    print -> function () { console.log(str) };

接下来逐行分析代码:

print(); // 1
console.log(str); // 2
var str = 'hello world!'; // 3
function print() { // 4
    console.log(str)
}

编译阶段

  • 1和2,不是声明操作,JS引擎不做任何处理
  • 3,通过var 声明变量,所以JS引擎在环境对象中创建一个名为str的属性,并初始化为undefined
  • 4,这是一个函数声明。JS引擎发现了一个通过function定义的函数,所以JS引擎会将函数定义部分存到堆(HEAP)中,并在环境对象中创建一个print属性,并将print的值指向堆中函数的位置。

这样就生成了变量环境对象,接着JS引擎会把声明之外的代码编译成字节码(可执行代码),也就是下面这一段模拟代码:

print();
console.log(str);
str = 'hello world!';

执行阶段

JS引擎开始执行“可执行代码”,按照顺序一行一行的执行,过程如下:

  • 执行到print函数时,JS引擎变开始在变量环境对象中寻找该函数,由于变量环境对象中print存在该函数的引用,所以JS引擎便开始执行该函数,在执行过程发现,函数用了str变量,所以JS引擎继续在变量环境中寻找str变量,此时str在变量环境对象中的值为undefined, 所以输出undefined.(这里细节,后续再补充)
  • console.log(str), JS引擎继续在变量环境对象中查找str,此时str在变量环境对象中的值为undefined, 所以输出undefined.
  • str = 'hello world!'; 这是一个赋值操作,把'hello world!'赋值给str, 赋值结束后变量环境对象变成:
Variable Environment:
    str -> 'hello world!',
    print -> function () { console.log(str) };

整个流程大致差不多这样,但是其实细节还是很复杂的,后续有空再继续补充。

有个问题,如果代码中存在多个相同的变量和函数时怎么办

如下面这段代码,建议小伙伴自己先分析一下。

a(); // 1
var a = 'hello world'; //2
console.log(a); // 3
function a() { // 4
    console.log('inner a function 1')
}

var a = 'hello, tomorrow'; // 5

console.log(a); // 6
function a() { // 7
    console.log('inner a function 2')
}
a(); // 8

abb021dce6119522abda175658f7d063.png


编译阶段:

  • 1,函数调用不做处理
  • 2, 有var声明变量,在执行环境中变量环境对象上创建a变量并赋值为undefined.
Variable Environent:
    a -> undefined;
  • 3, 函数调用,不做处理
  • 4, JS引擎发现有同过function 定义的函数a,把函数定义存储到堆中,并且在变量环境对象中查找是否有a属性,有a,然后把a的值指向该函数的在堆中的位置。此时变量环境对象变成(类似这样):
Variable Environent:
    a -> function () { console.log ('inner a function 1')};
  • 5, 有var声明变量,在执行环境中变量环境对象上查找是否存在a属性,发现存在并y有值,不做处理。
  • 6, 不做处理
  • 7, JS引擎发现有同过function 定义的函数a,把函数定义存储到堆中,并且在变量环境对象中查找是否有a属性,有a,然后把a的值指向该函数的在堆中的位置。此时变量环境对象变成(类似这样):
Variable Environent:
    a -> function () { console.log ('inner a function 2')};

然后执行可执行代码:

a(); // 1
a = 'hello world'; //2
console.log(a); // 3
a = 'hello, tomorrow'; // 4
console.log(a); // 5
a(); // 6
  • 1,JS引擎变开始在变量环境对象中寻找该函数,由于变量环境对象中a存在该函数的引用,所以JS引擎便开始执行该函数,输出
inner a function 2
  • 2,赋值操作,把'hello world'赋值给a,此时变量环境对象变更为:
Variable Environent:
    a -> 'hello world';
  • 3,打印a的信息。
hello world
  • 4, 赋值操作,把'hello, tomorrow'赋值给a,此时变量环境对象变更为:
Variable Environent:
    a -> 'hello, tomorrow';
  • 5,函数调用,但是在变量环境对象中,a 的值为'hello, tomorrow',并没有指向函数的位置,所以报错,没毛病。

这就是整个过程啦,大家可能在在编译阶段的第5步会有疑虑,为什么没有覆盖,我专门验证了这个问题,截图如下:

4fa3915caa3be74b5e80f1a8211ab311.png

扩展,有参数时怎么办

function c(a, b) {
    var a = 'hello, world';
    console.log(a, b);
}
c(1, 2)

f33c163086acd6b3b3032f5f1595af27.png


相信大家都知道答案,但是具体流程大家清楚嘛,欢迎留言分析或者自己分析。

最后

欢迎大家关注我的微信公众号:匿名程序媛
一起挖坑、填坑

bb5a354a4bd0641015ea88a511c24ea2.png

技术交流qq群:936183824

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值