180330 预编译

JS编译过程

  1. 语法分析:JS引擎通篇扫描,有低级错误直接报错不执行。
  2. 预编译
  3. 解释执行

执行期上下文

  • 当函数执行时,会创建一个称为执行期上下文的内部对象。一个执行期上下文定义了一个函数执行时的环境,函数每次执行时对应的执行上下文都是独一无二的,所以多次调用一个函数会导致创建多个执行上下文,当函数执行完毕,执行上下文被销毁。

预编译

window是全局对象,在全局范围声明一个变量,则该变量成为window的一个属性。
imply global暗示全局变量:任何变量如果未经声明就赋值,都会变成window全局对象的属性。

var age = 18;
function (){
    var haha = age = 20;
}
show();    
console.log(a)  // age  ->  20

函数预编译过程

  1. 创建执行期上下文 AO = { };
  2. 找出全部变量(变量声明!var)及形参,并赋值undefined。
    AO –> {a:undefined,b:undefined,c:undefined};
  3. 形参实参相统一
    AO –>{a:3,b:4,c:undefined};
  4. 寻找函数声明(函数表达式不好使!),值赋给函数体
    AO –>{a:3,b:4,c:function c () {} };
function show(a,b){
    console.log(a);  //3
    console.log(b);  //4
    console.log(c);  //function c(){}
    var c = 20;
    function c (){};
    c = 30;
    a = 20;
}
show(3,4);

全局预编译过程:

  1. 创建全局执行期上下文GO = { }
  2. GO -> { this:window,document:,a:,b: }
  3. GO -> {this:window,document:,a:undefined,b:function(){} }

作用域[[scope]]:

只有JS引擎有权限访问。
存储了执行期上下文的集合。
一个函数被定义时,它的[[scope]]指向的对象(scope chain)的第0位存储的就是该函数所在的执行环境。

作用域链(scope chain):

[[scope]]中所存储的执行期上下文对象的集合,这个集合呈链式链接,我们把这种链式链接叫做作用域链。

a{[[scope]]:{}}
//   属性(作用域scope)    值是一个对象(作用域链scope chain)

1.语法分析后创建全局执行期上下文GO -> {...}
2.此时定义 a.[[scope]] -> {0:GO}
3.函数执行时创建函数执行期上下文AO -> {...}
4.此时执行 a.[[scope]] -> {0:AO,GO}


这里写图片描述



var global = 300;

function test() {
    console.log(global); // AO: undefined
    var global = 400;
    console.log(global); // 400
}
test();


var global = 100;

function test() {
    console.log(global); // AO :没有global  GO:100
    global = 200; //不是变量声明  
    console.log(global); // 200
}
test();
console.log(global); // 200
function a(){
    function b(){  //  b.[[scope]] -> {0:AO2,1:AO1,2:GO}
        var b = 234;
    }
    var a = 123;
    b();
}
var glob = 100;
a();

这里写图片描述
这里写图片描述
这里写图片描述

这里写图片描述


闭包

  • 当内部函数(内部引用值)被保存到外部时,将会生成闭包。
  • 闭包会导致原有作用域链不释放,造成内存泄露。
function a() {
    function b() {
        var bbb = 234;
        document.write(aaa);
    }
    var aaa = 123;
    return b;
}

var glob = 100;
var demo = a();
demo();  // 函数b被保存到外部,因此产生闭包
//此时延用之前的作用域链,函数执行期上下文不会被删除

// 用处,原本输出aaa的值是undefined,但是这样之后是111

// b.[[scope]] -> {0:aAO,1:GO}
// b/demo.[[scope]] ->{0:bAO,1:aAO,2:GO}
// demo.[[scope]] -> {0:aAO,1:GO}

这里写图片描述

使用闭包

  • 缓存
function add() {
    var num = 0;

    function get() {
        num++;
        console.log(num);
    }
    return get; 
} 

//get函数被保存到外部,
//它的作用域链scope chain -> {0:getAO,1:addAO,2:GO}

var outerGet = add(); 
outerGet(); // 1   
outerGet(); // 2
outerGet(); // 3  
//   一直操作的是作用域链当中的num值,即 接着上一次的num运算结果
//    每次执行,使用的都是同一个AO, AO没有被销毁

//---------------------------------------------------------
function add() {
    var num = 0;
    num++;
    console.log(num);
}
add(); // 每次执行会创建一个新的AO
add();
add();

// ----------------------------------------------------------

function add(){
    var num1 = 1;
    var num2 = 1;
    function get1(){
        num1++;
        console.log(num1);
    }
    function get2(){
        num2++;
        console.log(num2);
    }
    return [get1,get2];   // 注意返回多个值时的技巧
}
var outerGetALL = add();
outerGetALL[0]();
outerGetALL[0]();
outerGetALL[1]();
outerGetALL[1]();
  • 私有化变量

立即执行函数

  • 此类函数没有声明,在一次执行过后即释放。
  • 可以做初始化工作。
(function () {}());
(function () {})();
//函数声明被()包裹,被强制转换成函数表达式
//函数([圆括号包裹函数声明形式],[函数表达式形式])定义时就用()执行,
//如果不产生闭包,函数就会被销毁。

+function() show(){}() 
// + 等其它运算符 可以将函数声明转换成函数表达式
fucntion show (){

}();
//不能执行,只有函数表达式可以被()直接执行
--------------------------------------------------------------
var test = function(){

}();
//可以执行,因为是函数表达式
--------------------------------------------------------------
var test = function show (){

}();
//可以执行,因为是函数表达式
--------------------------------------------------------------
var test = function(){
}
//执行方式有两种:
变量表达式执行:test();
非变量表达式执行(定义时直接执行):[var test(){}] ();
//当函数表达式选择执行方式----(执行非变量的函数表达式)方式时
//表达式会在执行后销毁
--------------------------------------------------------------
var test2 = function show (){
    console.log(1);
    return show;
}();
test2();// 可以执行,形成闭包才没被销毁

应用

var a = [];
for (var i = 0; i < 10; i++) {
    a[i] = function() {
        console.log(i); // i在GO中
    }
}
a[0](); // 10
a[1](); // 10


var a = []; //定义了一个数组,每次循环都会向数组各索引存储一个输出函数
for (var i = 0; i < 10; i++) {
    (function(i) { // [[scope]] -> {0:nAO -> {i:0} 1:GO -> {}} 保存到外部,形成闭包,存档
        a[i] = function() { // a[i].[[scope]] -> {0:a[i]AO,1:nAO,2:GO}  a[i]AO每次执行完销毁
                console.log(i);
            }
            // return  因为将函数存到了全局的数组当中,相当于将函数return到外部
    })(i);
}

a[1](); // 产生闭包,立即执行函数不会被销毁,相当于普通函数
a[9](); // 每一次循环,将i=1~9传入函数

对象知识点补充

对象属性的调用:o.attributes

function test (){

}
test();

// 相当于

function test (){
    this:window
}
window.test();

//谁(对象)通过.方式调用了函数,谁就是this

如果一个函数是构造函数,则会隠式的创建this对象,并返回this

function CarFactory (){
    // var this = {
    //  wheel:4,
    //  door:2,
    //  distance:0,
    //  run:function(){}
    //  }
    this.wheel = 4;
    this.door = 2;
    this.distance = 0;
    this.run = function (){
        this.run = function(){
            this.distance += 100;
        }
    }
    // return this
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值