JavaScript基础(九) ---- 预解析

1. 预解析

关于预解析的定义 1.什么是预解析
在当前作用域下,在JS代码执行之前,浏览器会对带var和带function进行提前声明或定义;— 这种机制叫预解析。
2.作用域(全局作用域 和 私有作用域)
全局作用域:当浏览器打开HTML页面的时候,会形成一个供JS代码执行的全局作用域(全局环境),在这个全局作用域下,
所有的全局变量,都属于window的全局属性;所有的全局函数,都属于window的全局方法
私有作用域: 函数在调用的时候会形成一个私有作用域
私有变量有两个:
1)形参
2)带var的;
3.声明和定义
声明:告诉浏览器,有这么一个变量; 举例: var a;
定义:给已经声明过的变量赋值; eg: var a=123;
4.关于var和function在定义阶段的不同
带var的: 只声明,不定义;
带function的: 声明+定义;

2. 函数的定义和执行

定义3阶段:
1)开辟一个空间地址
2)把函数体中的所有JS代码做为字符串存在这个空间中
3)把空间地址赋值给函数名
执行
1)形成一个私有作用域
2)给形参赋值
3)预解析
4)代码从上到下的执行;

3. 带var和不带var的区别

var1)会进行预解析 2)在全局环境下,window的全局属性
不带var1)不会进行预解析 2window的全局属性

4. 作用域链

当函数执行的时候,会形成一个私有作用域;查看这个作用域中是否有私有变量A:
1)如果有,这个作用域中所有出现的A都属于私有变量,跟外界没有任何关系;
2)如果没有:
1.获取阶段: 往上级作用域进行查找,找到直接弹出,找不到,继续往上级的上级找……一直找到window还没有找到,报错; xx is not defined;
2.设置阶段: 往上级作用域进行查找,找到进行重新赋值,找不到,继续往上级的上级找……一直找到window还没有找到,属于window的全局属性;

5. 上级作用域

上级作用域跟在哪里调用无关,只跟他对应的堆内存在哪里开辟(定义)有关;

6. 内存(栈内存,堆内存)

栈内存:全局作用域和私有作用域
内存释放:
全局作用域释放:只有我们关闭浏览器打开的HTML页面,才能释放;
私有作用域释放:一般情况,当我们执行完函数的时候,他会自动释放; 但特殊情况除外:
1)如果函数里面的东西被外面占用,就无法释放;
2)不立即释放:当函数执行完成的时候会返回一个函数,这个返回的函数还需要再执行一次;只有返回值执行完成后才能释放
堆内存:
对象数据类型:存的是对象的属性名和属性值
函数数据类型:存的是代码字符串;
var a={};
a=null;
堆内存的释放:
如果堆内存被变量占用,无法得到释放,只有把变量的指针指向一个空指针null;这样,当浏览器空闲的时候,会把指向空指针的变量自动收回;浏览器 的这种处理机制,叫做垃圾回收机制

7. 预解析的特点

预解析无节操
1)只对等号左边带var的,进行只声明,不定义;
2)自执行函数不进行预解析,只有执行到他的时候,声明+定义+执行同步完成
3)条件判断语句中,无论条件是否成立,都会进行预解析;
注意:为了代码规范性,不要在条件判断语句中写函数定义阶段;因为预解析时各大浏览器不同;
4)已经声明过的变量,不会进行重复声明
5)return后面的返回值不会进行预解析,return下面的语句虽然不执行,但会进行预解析;

8. 预解析经典问题

例1: — 作用域

<script>
    //每个script都是一个域;两个script属于不同的域;
    alert(n)
</script>
<script>
    var n=456;
</script>

例2:— 变量提升

<script>
    function abc(){
        a=12;//window.a
        alert(a);//12
    }
    function b(){
        alert(a) //12
    }
    abc();
    b();
</script>

例3:

    if(!('a' in window)){ //in:用来判断该属性是否为对象上的属性 (公有属性+私有属性)
        var a=15;
        alert(a)
    }
    alert(a)

例4:

    (function f(){
        function f(){ return 1; }
        alert (f());
        function f(){ return 2; }
    })();

例5:

    (function f(){
        var f=function(){return 3}
        function f(){ return 1; }
        alert (f());
        function f(){ return 2; }
    })();

例6:

    function fn(){
        alert(n);
        fn2();
        fn1();
        return function fn1(){
            alert('fn1')
        };
        var n=456;
        alert(n)
        function fn2(){
            alert('fn2')
        }
    }
    fn();

例7:

    var name='定义';
    var age=500;
    name=(function(name,age){//2.定义了形参age,但没有赋值,拿到的值就是undefined;
        arguments[0]='形参';
        age=age||this.age;//3. || 前面为假,才会走后面 4.自执行函数中的this-永远都是windowconsole.log(name,age);//'形参' 500
    })(name);//1.只执行函数的返回值:因为没有return,所以返回值是undefined
    console.log(name,age) //undefined 500

例8:

    var obj={
        fn:function(){
            alert(this);
            return function(){
                alert(this);
            }
        }
    };
    var f=obj.fn;
    f(); // window
    f()(); // window window
    obj.fn()(); //obj window

例9:

闭包的作用:
1.避免变量名冲突 : 1)在闭包中重新定义变量 2)给形参赋值;
2.在闭包中影响全局:1)在闭包中不定义跟全局变量一样的变量名 2)用自执行函数中的this/直接用window;
3.封装

var name='aaa';
var age=8;
(function(name,age){
        window.name='qiang';
        window.age=28;
        alert(window.name)
    })();
    alert(name)

利用闭包来封装— 获取节点的兼容方法

    var aLi=document.getElementsByTagName('li');
    (function(){
        function prev(curEle){
            //previousElementSibling:直接可以拿到上一个哥哥元素,但是他不兼容,他只支持标准浏览器;
            if('previousElementSibling' in curEle){
                return curEle.previousElementSibling;
            }
            //先保存上一个哥哥节点;
            var pre=curEle.previousSibling;
            //判断条件:pre是节点,并且不是元素节点;
            while(pre && pre.nodeType !== 1){
                pre=pre.previousSibling;//只要条件成立,继续在当前节点上找他的上一个节点,直到找到元素节点后,就没法进while循环了;
            }
            return pre;
        }
        window.prev=prev;//在闭包中封装的方法,如果想让外面用,需要通过window.xx把他输送出去;否则,外面用不了
    })();
   console.log(prev(aLi[3]))

例10:

    var num = 10;
    var obj = {
        num: 20,
        fn: (function (num) {
            this.num *= 3;
            num += 10;
            return function () {
                this.num *= 3;
                num += 1;
                console.log(num);
            }
        })(num)
    };
    var fn = obj.fn;
    fn();
    obj.fn(); 
    console.log(window.num, obj.num);

例11: – 函数声明优于变量声明

    function change() {
        alert(typeof fn) //function
        function fn() {
            alert('hello')
        }
        var fn;
    }
    change();

例12:函数预解析

    //只能在IE10及10以下执行;
    f=function(){return true};
    g=function(){return false};
    (function(){
        //运算符的优先级:算术>比较>逻辑>赋值
        if(g()&&[]==![]){  //条件判断语句中,无论条件是否成立,都会进行预解析
            f=function(){return false;}
            function g(){return true;}
        }
    })();//自执行函数,不会进行预解析,只有当执行到他的时候,声明+定义+执行同步完成;
    alert(f());
    alert(g());

9. 预解析难题集

题1:

    var n=0;
    function a(){
        var n=10;
        function b(){
            n++;
            alert(n);
        }
        b();
        return b;
    }
    var c=a();
    c();
    alert(n);

题2

    var a=4;
    function b(x,y,a) {
        alert(a);
        arguments[2]=10;
        alert(a);
    }
    a=b(1,2,3);   
    alert(a);

题3

    var foo='hello';
    (function(foo){
        console.log(foo);
        var foo=foo||'world';
        console.log(foo);
    })(foo);
    console.log(foo);

题4

    var a=9;
    function fn(){
        a=0;
        return function(b){ return b+a++; }
    }
    var f=fn()
    var m=f(5);
    alert(m);
    var n=fn()(5);
    alert(n);
    var x=f(5); 
    alert(x);
    alert(a);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值