js运行机制


/*js运行机制题目*/
/*知识点:
1.所有的等号赋值,第一步是先创建值
函数创建的时候就声明了她的作用域

*/

/*
全局代码执行作用域EC(G)

*/
var i =0;
function A(){
    var i =10;
    function x(){
        console.log(i)
    }
    // console.log(x)
    return x   //此时返回的是函数x的函数体
}
// console.log(A()+'111')
var y=A()
console.log(y)
// y()
// var y =A();
y();
function B(){
    var i =20;
    y()
}
B()


/*一般函数执行完毕之后就出栈释放了  函数堆释放

闭包:函数执行时产生一个不被释放的私有上下文(也就是被占用的时候 ),保护里面私有变量不受污染而且还可以把这些信息保存下来,
供她的下级上下文使用 

* heap 堆函数释放:空指针  比如:
let obj ={a:'111'}
obj=null  空指针,此时obj之前指向的堆被释放

* stack 栈内存释放:
1. 全局上下文中,页面关闭即释放
2. 私有上下文中:
   (1)函数执行完,私有上下文都会出栈释放
   (2)当前上下文中的某些内容(比如一个堆),被除了当前上下文之外的内容占用了,就不能出栈.



   GC浏览器垃圾回收机制:
   (1)引用标记法_谷歌浏览器:当堆内存被占用时做标记(这个要自己查 TODO:)
   (2)引用计数_IE低版本浏览器 容易内存泄漏 TODO: 查一下内存泄漏的原因以及情况
   总结:当前内存如果被占用就不能被释放,没被占用的时候,浏览器会在空闲时间将他们释放出去





*/

/*    let  const  var  的区别

* let: 创建一个变量,这个变量可以在下面被修改 比如:
let a =10;
a =12
console.log(a)-->12

* const: 创建一个变量,关联一个值,这个值不可被修改(不能需修改此变量的关联指向) 比如:
const b =10;
b=12  --> 报错

但是,如果  const 是一个对象,可以通过成员访问的方式进行修改
比如:
const b ={
    name:'qqq'
}
b.name='aaa'
console.log(b)--> {name:'aaa'}


* 再相同的上下文中
 (1) var 允许重复声明,但只识别一次
 (2) let 不允许重复声明



*/
// console.log不会被执行,而是直接报错,是因为在词法解析阶段,如果有报错,所有代码都不会执行
//code.html:103 Uncaught SyntaxError: Identifier 'b' has already been declared
// console.log('ok')
// const b =10;
// const b =30;

/*   
var 和function 中声明的变量,除了在全局变量对象VO(G)中储存,也会在GO(window)中设置相应的属性.(新版处理机制:在全局上下文中
基于bar 和function声明的变量,会直接存储到GO也就是window中,不会在 VO(G)中存储了)


let 和const 中声明的变量,只会在全局上下文VO(G)中存储,不会在GO(window )中存储

*/

/*  js 中的暂时性死区:用typeof检测一个未声明的变量,不会报错,会显示 'undefined'
例如:  console.log(typeof n )  -->此时n未被声明,typeof n 形成暂时性死区     但是
如果   let n =10   上面输出结果就会报错:不得在未声明之前使用n   所以 
可以用 在下面let创建变量抵消上面的暂时性死区  即  let的机制可以抵消暂时性死区

*/

console.log(typeof n)
// var n =10  -->不会抵消暂时性死区
//let n=10 
 //-->Uncaught ReferenceError: Cannot access 'n' before initialization  抵消暂时性死区

{
     var k=20
    let m=90;// -->此时的m只是块级私有的 在下面无法被调用
   
    console.log(m)
}
console.log(m)


/*
匿名函数:把函数作为值赋给xxx
例如:  xxx.onclick=function(){....}

*/


/*
this 的指向

1-全局上下文中的this指向的是window
2-块级作用域指向的是他所继承的this,箭头函数也是

函数执行
 *   正常的普通函数执行:看函数执行前是否有“点”,有,“点”前面是谁this就是谁,没有“点”,this是window「严格模式下是undefined」,
 跟他在哪里调用 哪里执行的都没关系
 *   匿名函数:
 *     + 函数表达式:等同于普通函数或者事件绑定等机制
 *     + 自执行函数:this一般都是window/undefined
 *     + 回调函数:一般都是window/undefined,但是如果另外函数执行中,对回调函数的执行做了特殊处理,以自己处理的为主
 *   括号表达式:小括号中包含“多项”,这样也只取最后一项,但是this受到影响(一般是window/undefined),比如:(10,obj.fn)(),
 * 指向的是window,如果开启严格模式,会显示undefind
 * function fn() {
//     console.log(this);
// }
// let obj = {
//     name: 'zhufeng',
//     fn
//     // fn: fn
// };
// fn(); //this->window/undefined
// obj.fn(); //this->obj
自执行函数的this是window 或者undefeated(在严格模式下
自执行函数举例:
(function(){
    console.log(this)==>输出window
})(10)


回调函数:把一个函数A作为实参,传递给另外一个执行的函数B「在B函数执行中,可以把A执行」
/* function fn(callback) {
    // callback -> 匿名函数
    callback();
}
fn(function () {
    console.log(this);
}); */

/* let arr = [10, 20, 30];
// arr.forEach(function (item, index) {
//     console.log(this); //->window
// });
arr.forEach(function (item, index) {
    console.log(this); //->forEach第二个参数「对象」  forEach内部做处理了
},{xxx:'xxx'}); 


数组的foreach方法,传的第二个参数会改变this的指向
*/
//一道题来了!!
var x = 3,
    obj = {
        x: 5
    };  
    /**在全局上下文中创建了变量
     * x-------3
     * 对象obj-------指向堆地址 0x001
     * 作用域
    **/
obj.fn = (function () {
    this.x *= ++x;
    return function (y) {
        this.x *= (++x) + y;
        console.log(x);
    }
})();

/*
自执行函数,在创建的时候会自己调用一次,指向堆地址0x002  
作用域:全局 EC(G)

内容:
'this.x *= ++x;
    return function (y) {
        this.x *= (++x) + y;
        console.log(x);'

执行: this.x=this.x*(++x),前面的this.x,是window.x,也就是3,后面的x也是全局的x,也是3  所以
此时里面的x都是3 全局x经过运算之后
this.x=this.x*(++x)
      =3*4
      =12
      

执行完毕,返回一个匿名函数,存储在0x003 同时在0x001堆内存中创建 fn-------0x003,被占用,形成不被释放的闭包
注意:自执行函数,创建时自调用一次之后,返回的值 赋给等号前面的东西
此时:
全局变量中:
x-----3 变为 x------4(因为++x),再变为x-----12

0x003的内容:
'this.x *= (++x) + y;
        console.log(x)'
        形成作用域EC(003)

执行完毕后,没有被占用,释放0x002内存

此时0x001中的变量
x-------5
fn------0x003

*/
var fn = obj.fn;

/*在全局中创建一个变量fn-------0x003

此时全局变量中存在的有:
x-------------12
obj--------0x001
fn------------0x003
*/
obj.fn(6);
/*
执行0x003中的代码段
this.x *= (++x) + y;
        console.log(x)
形成私有上下文,私有作用域EC(1),私有变量
y--------传参6
this的指向为obj,根据点语法,obj.fn调用,this就是obj
this.x=this.x*((++x)+y)
      =5*((全局x--12自增=13)+6)
      =5*(13+6)
      =95
      此时obj中的x发生改变
obj中:
x-----5 变为x----95

全局变量中
x----12 因为自增,变成了x----13



*/
fn(4);
/*
函数调用:相当于0x003中传参4
因为没有被点,所以匿名函数的this 没有严格模式下为window
此时:
this.x *= (++x) + y;
        console.log(x)
this.x是window中的x,为13,++x的x 也是全局的x 为13,y是此匿名函数执行时形成的新的私有上下文EC(2)中的私有变量
y------4
所以执行函数:
this.x=this.x*((++x)+y)
      =13*((x--13自增为14)+4)
      =13*18
      =234
----也就是 此时全局的x变成了234
因为没被占用,执行完毕后释放
*/

console.log(obj.x, x,);
/*最终这道题的答案是:
obj.x为95
x为234
*/




你可能感兴趣的:(js运行机制)