JavaScript运行原理

概念

  • Execute Context:执行上下文
  • Execute Context Stack:执行上下文栈(或 Call Stack 调用栈),存储代码运行期间创建的所以上下文
  • Event Loop:引擎运行 js 线程的方式
  • 引擎:从头到尾负责整个 JavaScript 程序的编译及执行过程
  • 编译器:负责语法分析及代码生成等
  • 作用域:负责收集并维护由所有声明的标识符(变量)组成的一系列查询,并实施一套非常严格的规则,确定当前执行的代码对这些标识符的访问权限

JavaScript 的运行分为两部分:编译、执行

一些问题

  • 为什么使用栈结构存储运行时的执行上下文?
    function second() {
      console.log(name);
    }
    
    function first() {
      var name = '2';
      second();
    }
    
    var name = '1';
    first();
    // 输出:1
    
  • 进程与线程
    进程:资源分配的最小单位;进程拥有独立的堆栈空间数据段,每当启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段堆栈段数据段
    线程:程序执行的最小单位;线程拥有独立的堆栈空间,但是共享数据段,它们彼此之间使用相同的地址空间,共享大部分数据,比进程更节俭,开销比较小,切换速度也比进程快,效率高

JavaScript 的执行分为两个阶段:1. 创建执行上下文;2. 执行代码;

执行上下文

执行上下文有三种类型:全局执行上下文、函数执行上下文、Eval 函数执行上下文

执行上下文的数据结构:

// ES3 例:
function foo(i) {
    var a = 'hello';
    var b = function bar() {

    };
    function c() {

    }
}

foo(22);

创建阶段

fooExecutionContext = {
    scopeChain: { ... },
    variableObject: {
        arguments: {
            0: 22,
            length: 1
        },
        i: 22,
        c: pointer to function c()
        a: undefined,
        b: undefined
    },
    this: { ... }
}

ES3 的函数执行上下文包括:

  • scopeChain:指向上一个作用域(新概念)
  • variableObject:包含函数的参数 arguments 和函数内声明的变量
  • this:执行函数的调用者

在创建阶段函数内声明的变量都初始化为 undefined,在执行阶段将在栈中存储(数据段?)或堆中存储的值赋给变量(说明有一个收集值的过程,但在创建阶段为什么就初始化了参数的值?)
函数每调用一次,都会产生一个新的执行上下文环境。因此不同的调用可能就有不同的参数。

总结:ES3 的执行上下文
创建阶段:1. 创建作用域链;2. 创建变量对象VO(包括参数,函数,变量);3. 确定this的值
激活/执行阶段:完成变量分配,执行代码

ES5 的执行上下文


FunctionExectionContext = {  
   
  this: <Global Object>,

  LexicalEnvironment: {  
    EnvironmentRecord: {  
      Type: "Declarative",  // 环境记录分类: 声明环境记录
      Arguments: {0: 20, 1: 30, length: 2},  // 函数环境下,环境记录比全局环境下的环境记录多了argument对象
    },  
    outer: <GlobalLexicalEnvironment>  
  },

  VariableEnvironment: {  
    EnvironmentRecord: {  
      Type: "Declarative",  // 环境记录分类: 声明环境记录
      g: undefined  
    },  
    outer: <GlobalLexicalEnvironment>  
  }  
}

一些问题

  • 词法作用域意味着作用域是由书写代码时函数声明的位置来决定的。编译的词法分析阶段基本能够知道全部标识符在哪里以及时如何声明的,从而能够预测在执行过程中如何对它们进行查找(找到所有的声明,并用适合的左右域将它们关联起来)

// 包括变量和函数在内的所有声明都会在任何代码被执行之前首先被处理(变量提升)
// 函数优先

foo()
var foo;
function foo() {
  console.log('1');
}
foo = function() {
  console.log('2')
}
// 这段代码会被*引擎*理解为如下形式
function foo() { // 变量提升 函数优先
  console.log('1')
}
// var foo = undefined 重复的变量声明 被忽略
foo(); // 1
foo = function() {
  console.log('2');
}

在传统编译语言的流程中,程序的一段源代码执行之前会经历三个步骤,统称为”编译“

  • 词法分析:将代码的字符串分解成词法单元(token)
  • 语法分析:将词法单元流(数组)转换成抽象语法树 AST
  • 代码生成:将 AST 转换成可执行代码

任何 JavaScript 代码片段在执行前都要进行编译(通常就在执行前)

  • var 重复声明变量会被忽略、不允许使用let const重复声明变量,function 重复声明的变量后面会覆盖前面

作用域:全局作用域、函数作用域、块作用域({} 创建,不是 object)

letconst 将变量绑定块级作用域
letconst 的暂时死区:

console.log(a);  // undefined (变量提升)
console.log(b);  // ReferenceError: Cannot access 'b' before initialization (暂时死区)
var a = 1;
const b = 2;

块作用域里的函数声明

foo(); // b
var a = true;
if(a) {
  function foo() {console.log('a')}
} else {
  function foo() {console.log('b')}
}

作用域和执行上下文的区别

  • 作用域:函数声明时确定
  • 执行上下文:函数每调用一次,都会产生一个新的执行上下文环境,处于活动状态的执行上下文环境只有一个。(在你不知道的JavaScript这本书中,执行上下文被叫做动态作用域)

    变量、函数表达式——变量声明(默认赋值为undefined)
    this——赋值;
    函数声明——赋值;

this

this 属于执行上下文的一个属性;由于每次调用函数都会生成一个新的执行上下文,所以每次调用函数都会给 this 赋值;this 表示函数被谁调用

箭头函数

用当前的词法作用域覆盖了 this 本来的值;this 的值同当前词法作用域对应的执行上下文的 this 的值

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容

  • 今天感恩节哎,感谢一直在我身边的亲朋好友。感恩相遇!感恩不离不弃。 中午开了第一次的党会,身份的转变要...
    迷月闪星情阅读 10,498评论 0 11
  • 彩排完,天已黑
    刘凯书法阅读 4,147评论 1 3
  • 表情是什么,我认为表情就是表现出来的情绪。表情可以传达很多信息。高兴了当然就笑了,难过就哭了。两者是相互影响密不可...
    Persistenc_6aea阅读 120,535评论 2 7