当一段代码被执行时,js引擎会先对其编译,并创立执行上下文。

  1. 当执行全局代码时,会编译全局代码并创立全局执行上下文,整个页面生存周期内,全局上下文只有一份。
  2. 调用到函数时,函数体内代码编译并创立函数执行上下文,函数完结后,下下文会被销毁。

栈恪守后进先出的准则,比方一条死胡同,进去的多人,只能最初进来的人先出。

var a = 2;function add(b,c){ return b+c }function addAll(b,c){     var d = 10,     result = add(b,c);     return a+result+d}addAll(3,6)
  1. 创立全局上下文,放最底下:先进。a = undefined, add = function(){...}, addAll = function(){...}
  2. 执行全局代码,a = 2赋值,上下文变量的a = 2
  3. 调入addAll()js编译addAll函数,并创立其函数执行上下文,压入栈中。参数列表,d = undefined, result = undefined
  4. 执行d = 10,把上下文赋值
  5. 执行到add(b,c)时,创立函数执行上下文,压入栈中,参数列表。
  6. add函数返回时,add函数上下文从栈顶弹出,将result设为add函数的返回值,add上下文销毁。
  7. addAll执行相加操作后,返回addAll执行上下文从栈顶弹出,销毁。只剩全局上下文,完结。

call stack调用栈,console.trace()打印函数调用关系。
当栈的执行上下文超过肯定数据会栈溢出。
let const 有块级作用域,当执行到块级时,会在执行上下文的词法环境,词法环境也是一个栈的构造,最外层在栈底一个块级执行结束,该作用域的信息就会从栈顶弹出,销毁。

function foo(){    var myName='思否'    let test1=1;    const test2=2;    var innerBar={         getName:function(){             console.log(test1)             return myName         },         seeName:function(newName){             myName=newName;         }     }    return innerBar;}var bar=foo();bar.seeName('思否')bar.getName()console.log(bar.getName())


innerBar是个对象,蕴含seeNamegetName这2个办法,这2个办法是在foo函数外部定义的,用了foomyNametest12个变量。
词法作用域规定,外部是函数总是能够拜访它们内部函数的变量,尽管foo曾经完结,其执行上下文也曾经弹出去销毁了,但因为其变量myNametest1被应用,所以这2个变量仍然保留在内存中,是专属于外面的闭包的。
闭包:应用内部函数变量,闭包函数销毁后,下次js引擎回收时判断不再用会回收这块内存。

var myObj={    name:'思否‘,    showThis:function(){        this.name='思否1'        console.log(this)    }}var foo=myObj.showThis;//相当于赋值指向同一块内存地址,然而调用对象变了,//foo在全局执行上下文指向window,所以foo函数this指向windowfoo()//foo在window全局里

js8种类型:Boolean,Null,Undefined,Number,BigInt,String,Symbol,Object
7种原始类型是存在调用栈中。Object援用类型实在存在堆中,栈中存的是堆的援用地址。
调用栈的执行上下文调完了,会弹出调用栈,所占用的内存也会被其它占用。而调用栈中援用地址指向的堆空间垃圾回收分为2类。V8把堆分成新生代和老生代,新生代容量1-8M,调用少的。其它则在老生代。次要是标识对象是否在应用标记齐全回收清理非流动对象,因为非流动对象散布在不同的内存地址,大小也不同,回收之后会有很多内存碎片。新生代有对象区域和闲暇区域,退出的放到对象区域,对象区域满垃圾回收。回收剩下的对象放到闲暇区域,闲暇区域变成了对象区域。老行生代的标记革除,会循环调用栈找对象地址的援用 ,找不到就是要回收,回收之后让所有剩下对象移向一端汇合在一起内存碎片就变成大空间。js和回收穿插进行。