上下文详解(持续更新)

提醒:执行上下文和作用域是完完全全不同的两个概念,请勿混淆视听,请勿混淆视听,请勿混淆视听。请看下面?

JavaScript代码的整个执行过程,分为两个阶段,代码编译阶段与代码执行阶段。编译阶段由编译器完成,将代码翻译成可执行代码,这个阶段(编译阶段)作用域规则会确定。执行阶段由引擎完成,主要任务是执行可执行代码,执行上下文在这个阶段(执行阶段)创建。不过,作用域链是在上下文生命周期的创建阶段被确定。唔。。。。

何为上下文?简单地说,就是代码在其内部中执行的对象,不是作用域!请看上面?。JavaScript编码中我们通常会使用函数创建一个上下文,函数执行的时候,上下文被激活为执行上下文。

上下文特点

  1. 类似于栈的读取方式,具有“先进后出,后进先出”的特点。在A上下文执行中激活B上下文,执行上下文变成B进入栈顶,B上下文执行完毕后跳出栈,继续A上下文执行。以此类推。
  2. 同步执行,栈顶的上下文执行中,其他上下文等待。(理解特点1)
  3. 上下文执行完毕跳出栈。
  4. 底层永远是全局上下文,窗口关闭全局上下文跳出栈(这里需要指出全局上下文的变量对象,以浏览器中为例,全局对象为window。它的变量对象,就是window对象。而这个特殊,在this指向上也同样适用,this也是指向window。)
  5. (按照我现在的理解)在浏览器中,全局上下文的生命周期等同于程序的生命周期,只要程序不结束(关掉窗口),那么全局上下文永远存在,在其他的所有上下文环境中,都可以访问全局上下文的属性。

上下文生命周期

一、创建周期及其流程
  1. 创建arguments对象,检查上下文参数,并将上下文参数建立为arguments对象下的属性和属性值
  2. 检查上下文中的函数声明(function关键字申明),如果上下文中不存在该函数的函数名这样一个属性,则在上下文中以函数名建立一个属性,属性值指向该函数所在内存的引用地址,如果上下文中已经存在该函数名这样一个属性,那么该属性的属性值则会被覆盖为新的引用地址(即该函数所在内存的引用地址)。
  3. 检查上下文中的变量申明,检查到之后,就会在上下文中创建一个属性,属性名就是变量申明的名字,属性值则是 undifinded ,注意:检查到以后,会先判断该属性值是否存在,如果存在,为了以防同名函数被修改为undefined,那么则会被跳过
二、执行阶段

执行阶段就很简单啦,就是变量赋值、函数引用和执行代码咯。

栗子一
function test (){
    var a = 'string'
    function foo (){
        return 'this is a foo'
    },
    a;
    foo()
}
test() 
复制代码
  1. 创建阶段(创建arguments => 检查函数声明 => 检查变量声明)
variableObject = {
    arguments:[],
    foo:<foo reference>,//函数引用地址
    a:undefinded
}
复制代码
  1. 执行阶段(变量赋值、函数引用、执行代码)
variableObject = {
    arguments:[],
    foo:'this is a foo',//执行函数引用
    a:'string',//变量赋值
}

复制代码

从上面的例子我们可以看出,变量赋值其实是在执行阶段,而不是在创建阶段,理解好这一点,在创建过程,若非是函数声明,可以成功的变量声明全部是undefined。这样,下面的例子也就可以十分轻松地理解透彻

栗子二
function foo() { console.log('function foo') }
var foo = 20;

console.log(foo); // 20
复制代码

下面我们来对这个栗子进行分解

  1. 创建阶段
variableObject = {
    arguments:[],
    foo:<foo reference>
}
复制代码
  1. 执行阶段
variableObject = {
    argumrnts:[],
    foo:20,//变量赋值
}
复制代码

上面例子,上下文创建阶段,在检查函数声明阶段的时候检测到函数声明foo,所以创建foo属性,并且foo的属性值指向函数foo所在内存的引用地址,然后检查变量声明的时候检测到变量声明foo,不过这个时候JS解析器检查到上下文已经存在属性undefined,所以跳过,在上下文创建阶段周期内,foo的值始终指向函数foo所在内存的引用地址。接下来就是上下文的执行阶段,这个时候执行变量赋值,所以foo被赋值为20。

从上面这个栗子我们也从侧面发现,声明具有提升性,并且函数声明的优先级大于变量声明。但是并不是浅显的理解为foo先被函数声明为函数foo所在内存引用地址,再次被覆盖为20,整个上下文创建周期,foo值,未被覆盖。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值