JavaScript堆栈执行的一些总结

V8引擎执行流程

  • V8引擎是一个JavaScript引擎实现,最初由一些语言方面专家设计,后被谷歌收购,随后谷歌对其进行了开源
  • V8使用C++开发,在运行JavaScript之前,相比其它的JavaScript的引擎转换成字节码或解释执行,V8将其编译成原生机器码(IA-32, x86-64, ARM, or MIPS CPUs),并且使用了如内联缓存(inline caching)等方法来提高性能
  • 有了这些功能,JavaScript程序在V8引擎下的运行速度媲美二进制程序。
  • V8支持众多操作系统,如windowslinuxandroid等,也支持其他硬件架构,如IA32,X64,ARM等,具有很好的可移植跨平台特性

浏览器中存在渲染引擎,V8是它其中处理js代码的一个部分,代码在执行前会经历一些步骤,这些步骤可以笼统的称之为编译的过程。作用域和作用域链在编译阶段就已经发生好了(在代码正式执行前就确认好了的)。

  • 词法分析
  • 语法分析
  • 预解析或全量解析
  • 预编译或编译
  • 最后拿到具体的机器码之后 开始堆栈执行

堆栈处理

在JavaScript执行的时候,浏览器在内存层面上所作的一些底层的处理。也就是堆栈方面的一些处理操作。

我们分析这些内容的主要目的,一方面可以从本质上分析一段代码的执行过程,再者说分析一段代码执行过程中的性能问题。

首先我们的代码会被转为可以被识别的机器码;这些字符串形式的机器码具体是在哪去执行呢?

  • 执行环境栈( ECS execution context stack )

浏览器在执行时会在计算机内存中开辟一个内存空间,专门用来执行JS代码。(栈内存)。

但又不能将所有的代码全部放入执行环境栈中,因为不同区域间的代码需要隔离开。

  • 执行上下文
  1. 一段JS 代码里肯定会有很多内容:变量的声明、函数的定义、对象、块作用域;
  2. 上述这些区域内都有自己的代码,默认情况下他们里面的内容可能会出现重名;
  3. 所以代码将来在执行时候不可能直接放在一个“环境”下去运行,我们需要将它们隔离开;
  4. JS当中就有了执行上下文的概念,专门用于将不同区域的代码 “分开” 【 】,分别管理;
  5. 之后每个执行上下文中的代码在需要执行时 **进栈执行 **就可以了。
  6. EC(G) (execution context global)全局执行上下文肯定是一直存在的。
  • VO(G) (variable object global)
  1. 全局变量对象( 全局执行上下文当中的变量需要有一个地方来存放,因此就有了这个对象 )
  2. 每一段代码中都有声明和定义,他们放在哪?
  3. 针对全局执行上下文来说,它里面的声明和定义放在了一个对象当中,这个对象我们叫 VO(G)
  • GO( global object )
  1. 全局对象, 它和 VO(G) 不是同一个东西 ,它是一个对象,也会有一个内存空间地址;
  2. 它也是浏览器加载界面时就会创建的一个对象,在它内部存放了许多JS默认就可以调用的属性和方法( setTimeout setInterval JSON eval… )
  3. 同时页面创建时JS 就会在VO(G)中创建一个变量【window】 指向GO。

基础数据类型是按值进行操作的,存放在栈区;

引用类型数据 存放在堆区,它的地址存放在栈区,通过变量进行引用

执行环境栈里面 存放不同的执行上下文(EC),栈底永远存放着一个全局执行上下文(ECG);

当前执行上下文执行完毕会有一个出栈操作,出栈后它里面存放的变量值会被释放,但它里面引用的对象会不会被释放取决于垃圾回收机制。

https://segmentfault.com/q/1010000002637728/a-1020000002639246

函数堆栈处理

var arr = ['zce' , 'ali'];
function foo(obj){
    obj[0] = 'zoe'
    obj = ['拉钩']
    obj[1] = 'boss'
    console.log(obj)
}
foo(arr)
console.log(arr)
  • 函数的创建

    1. 创建函数和声明变量类似,可以将函数名看做是变量名
    2. 函数在创建的时候,会单独开辟一个堆内存,存放 字符串形式 的函数体,运行的时候才会被当作真正的代码运行。
    3. 函数的声明与变量不同,它是既声明又定义( 函数可以在定义之前调用 );直接把它的内存地址存放在栈区跟函数名进行关联,也就是把地址赋值给变量foo;
    4. 所以对于函数来说,声明和定义都是发生在变量提升阶段,因此后面代码运行时,看到了 function foo(){}这种代码一般都是不做处理的。
    5. 函数创建时就会确认自己的作用域【scope】(就是创建时所在执行上下文) foo的作用域就是全局执行上下文;函数在创建的时候,它的内存当中存放的是 字符串形式 的函数体,运行的时候才会被当作真正的代码运行。
  • 函数执行

    1. 函数每执行一次都会创建一个私有上下文;
    2. 执行目的就是为了将函数创建时在堆内存里面所保存的那些字符串形式的函数体代码运行起来;
    3. 代码运行时为了和其它上下文做隔离,因此每个函数执行时都会创建一个全新的私有上下文 EC(foo)
    4. 在这个私有上下文当中有一个 AO(foo) 用来存储函数上下文里的变量声明和定义 (AO active object)
    5. 函数执行时如果有形参赋值,那么就会在AO(foo)当中新增属性。
    6. 当前执行上下文中的代码执行完毕后,会考虑是否出栈,释放内存。

函数执行步骤

  • 确定作用域链<当前执行上下文,函数作用域> //< EC(foo) , EC(G) >
  • 确定this 指向
  • 初始化 arguments
  • 形参赋值: 这里定义的变量都是当前函数上下文私有的
  • 变量提升
  • 代码执行

闭包与垃圾回收

  1. 浏览器都有垃圾回收机制(内存管理,V8为例);
  2. 栈空间,堆空间
  3. 堆:当前堆内存如果被占用,就不能被占用,但是我们确认后续不在使用这个内存里的数据,ye可以自己主动置空(fn=null)然后浏览器就会对其进行回收;

循环添加事件的实现

<button index='0'>111</button>
<button index='1'>222</button>
<button index='2'>333</button>

const buttons = document.querySelectorAll('button');
  • 闭包1
for(var i=0;i<buttons.length;i++){
    (function(i){
        buttons[i].onclick = function(){
            console.log(i)
        }
    }(i))
}
  • 闭包2
for(var i=0;i<buttons.length;i++){
    buttons[i].onclick = (function(i){
        return function(){
            console.log(i)            
        }
    }(i))
}
  • let关键字声明局部变量
for(let i=0;i<buttons.length;i++){        
    buttons[i].onclick = function(){
        console.log(i)
    }
}
  • 自定义属性
for(var i=0;i<buttons.length;i++){        
    buttons[i].indexs = i;
    buttons[i].onclick = function(){
        console.log(this.indexs)
    }
}
  • 事件委托
document.body.onclick = function(event){
    var target = event.target, targetName = target.nodeName;
    if(targetName === 'BUTTON'){
        console.log(`这是第 ${target.getAttribute('index')} 个button`)
    }
}

JSBench

JSBench是一个在线的测试JS 代码效率的一个网站。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值