一 预编译

 1概念

  1)什么是预编译: 

  2)全局对象(Global)GO window 

    全局变量

    全局函数

  3)活动对象AO local 

    局部变量

    局部函数

2 全局预编译

  1) 流程:1找变量声明作为Go对象的属性名,值为undefined。2找函数声明,作为Go对象的属性值,值为function。

  var a;变量声明

  function a(){}; 函数声明;

流程:

  (1)先把所有scirpt标签过一遍,然后整合在一起。

  (2)全局预编译

    1 产生window对象。GO

    2 查找变量的声明,把a最为window对象的属性名,属性值为undefined。

    3 查找函数的声明,把函数名a作为window对象的属性名,属性值是function

  (3)全局预编译结束后,从上到下,依次执行代码。

 

 

3函数预编译:

  1)流程:

  1函数被调用的时候,为当前函数产生AO对象。

  2 查找形参和变量作为AO对象的属性名,作为undefined

  3 使用实参值改变形参的值。

  4 查找函数声明,作为AO对象的方法,值为function。

test是AO对象的形参,i是AO对象的属性,b是AO对象的方法。

// 当调用函数a的时候,生产函数a的AO对象。进入函数预编译。

//AO:1 查找形参test,变量i作为i的AO对象属性名,值为undefined。

//  2形参‘1’赋值赋值给test。test:1

//  3查找局部函数 b,b作为AO对象的属性名,值为function。

function a(b,c){
console.log(b)
var b=0;
consoel.log(b)
function b(){
console.lgo(22)
}
console.log(c);
}
a(1)

a:AO{

b:fun,

c:undefinde.

}

function a(i){

var i;//在预编译阶段就执行了,正式阶段不会执行。

console.log(i)//i=1;
}
a(1);

一般来说优先级:

局部函数>实参>形参。

 

总结:1找声明;2 找赋值和调用。3 调用函数 进行AO对象,进行,函数作用域分析。

4找声明 形参 和变量为undefined 5赋值形参。找函数什么。6 找赋值和找调用。

二 作用域 和作用域链

1概念

  1)域

  全局作用域:有<script>标签产生的区域,从计算机的角度可以理解为window对象。

  局部作用与:由函数产生的区域。从计算机的角度理解:函数的AO对象。

ES6之前,没有块作用域。

  2)作用域链

  函数存在一个隐士属性,[scopes],也称为作用于链,我们可以把它理解称为一个数组。

分析1)当在函数a外部的时候,作用域只有一个。就是Global

 

当在函数a内部的时候, 作用域下有两个,一个是local,一个Global。

 

当然我们看,当只有一个函数的时候,它的作用域是什么。(console.dir(a)打印a的内部属性)

 

分析2)

    function a(){
        console.dir(a);
        function b(){
            console.dir(b);
            function c(){
                console.dir(c);
            }
            c();
        }
        b();
    }
    a();

0产生全局作用域

1产生a函数的AO对象,aAO

函数a的scopes:

  0:aAO

  1:GO

2 产生b函数的AO对象,bAO

 

 

 3产生c函数的AO对象。

 

 

 

 

 

 

 

 

 

2作用

作用域链的查找规则:

function a(){
  var aa=111
  function b(){
  var aa=222
  console.log(aa)}
  b()
} a();

 

1 产生a的AO对象,aAO

aAO:{ aa:111,b:fun}

2 产生b的AO对象,bAO

bAO:{aa:22}

在内部可以使用外部的函数,但是外部使用不了内部。因为b的AO对象没有产生。

 

三 闭包

视频:https://www.bilibili.com/video/BV1C54y1r7VS?p=13

博客:https://www.cnblogs.com/sandaizi/p/11582488.html

1外包的形成:

 内部函数使用外部函数的变量,就是形成闭包。闭包是当前作用域的延伸。

案例1

function a(){//外部函数
  var aa=111
  function b(){ //内部函数
  console.log(aa)}//aa是外部函数的变量,立刻,产生闭包。但是闭包并没有保存下来
  b()
}
a();

案例2

function a(){
var aa=100
function b(){
console.log(b);}//形成闭包,{b:fun},但是结束被销毁了指针引用销毁了,
b()
}
a();

案例2

function a(){
var aa=100
function b(){
var aa=10;
console.log(aa);}// 不会形成闭包。因为,没有引用外部函数的变量
b()
}
a();

2 闭包的保持:(真正形成闭包,且不会消失!)

案例三:

    function outerFunction() {
        var num = 0;
        function inner() {
            console.log(num++);
        }
        return inner;//inner就是一个闭包函数,因为可以访问到outerFcuntion的作用域。
    }
    var  demo = outerFunction();
    console.log(demo);
    demo();
    demo();

 

闭包产生的条件:
//闭包要形成:1内部函数使用外部函数的变量。
//闭包要保持:2 把内部函数返回到外部函数的外面。这样闭包才不会消失!!!

 

 

四 闭包的应用:

1闭包的两面性:

好处:一般来说,函数外部是不能访问函数内部的变量。也就是设计闭包。

坏处: 不注意使用闭包,出现奇怪的效果。

(1)《JavaScript高级编程》由于闭包会携带包含它的函数的作用域,因为会比其他函数占用更多内容,过度使用闭包,会导致内存占用过多。并不会垃圾回收。而且因为作用域链的原因。所有内存占用多。

(2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

2 闭包的作用:

1 函数外部访问私有变量:

2 实现封装。

3 防止污染全局函数。

 

    function Person() {
        var uname
        function setName(uname) {
            this.name = uname
        }
        function getName() {
            return this.uname
        }
        return {
            getName: getName,
            setName: setName,
        }
    }
    var xiao = new Person()
    console.dir(xiao)
    xiao.setName('xiaoli')
    console.log(xiao.getName)

 

 

 

 

 

 
posted on 2020-12-21 16:11  程序员草莓  阅读(134)  评论(0)    收藏  举报