JS作用域和闭包核心面试题分析

作用域和闭包-执行上下文:

变量提升(写代码时千万不要先使用再定义)

    <script>
        console.log(a);//undefined
        var a=10;

        fn('cyy',18);
        function fn(name,age){
            age=20;
            console.log(name,age);//cyy 20
            var age;
        }
    </script>

函数声明存在提升,函数表达式不存在提升

    <script>
        fn1();//函数声明  不会报错
        function fn1(){}

        fn2();//函数表达式  报错
        var fn2=function(){}
    </script>
    <script>
        fn('cyy');
        function fn(name){
            console.log(this);
            console.log(arguments);
            console.log(name);
        }
    </script>

作用域和闭包-this:

this要在执行时才能确认值,定义时无法确认

    <script>
        var a={
            name:'cyy',
            fn(){
                console.log(this.name);
            }
        }
        a.fn();//this===a
        a.fn.call({name:'cyy2'});//this==={name:'cyy2'}
        var fn1=a.fn;
        fn1();//this===window
    </script>

this:

作为构造函数执行

作为对象属性执行

作为普通函数执行

call  apply  bind

    <script>
        //构造函数
        function Foo(name){
            this.name=name;
        }
        var f=new Foo('cyy');

        //作为一个对象的属性
        var obj={
            name:'cyy',
            fn(){
                console.log(this.name);
            }
        }
        obj.fn();

        //普通函数的this
        function fn(){
            console.log(this);
        }
        fn();//this===window

        //call  apply  bind
        function fn1(name,age){
            console.log(name);
            console.log(this);
        }
        fn1.call({x:10},'cyy2',18);
        fn1.apply({x:20},['cyy3',19]);

        var fn2=function(name,age){
            console.log(name);
            console.log(this);
        }.bind({x:30});
        fn2('cyy4',20);
    </script>

作用域和闭包-作用域:

没有块级作用域,只有函数和全局作用域

    <script>
        //无块级作用域
        if(true){
            var name='cyy';
        }
        console.log(name);

        //有全局和函数作用域
        var a=10;
        function fn(){
            var a=20;
            console.log('fn:'+a);
        }
        fn();
        console.log('global:'+a);
    </script>

    <script>
        //作用域链
        var a=10;
        function fn(){
            var b=20;
            //当前函数作用域内没有定义的变量,即自由变量
            console.log(a);
            console.log(b);
        }
        fn();
    </script>

作用域和闭包--闭包:

闭包的使用场景:

1、函数作为返回值

2、函数作为参数传递

    <script>
        //函数作为返回值
        function F1(){
            var a=100;
            return function(){
                console.log(a);//a是自由变量,向父级作用域去寻找---函数定义时的作用域
            }
        }
        var f1=F1();
        var a=200;
        f1();//100

        //函数作为参数传递
        function F2(){
            var b=100;
            return function(){
                console.log(b);//b是自由变量,向父级作用域去寻找---函数定义时的作用域
            }
        }
        var f2=F2();
        function F3(fn){
            var b=300;
            fn();
        }
        F3(f2);//100
    </script>

作用域和闭包--解题:

    <script>
        //错误的写法
        //点击结果都是10
        var i;
        for(i=0;i<10;i++){
            var a=document.createElement('a');
            a.innerHTML=i;
            a.addEventListener('click',function(e){
                e.preventDefault();
                alert(i);//i是自由变量,要去父作用域寻找值;for循环不是作用域,所以获取到的i是循环结束的全局变量i=10
            })
            document.body.appendChild(a);
        }


        //正确写法,自执行的匿名函数形成函数作用域
        var i;
        for(i=0;i<10;i++){
            (function(i){
                //形成函数作用域,i不再是全局变量
                var a=document.createElement('a');
                a.innerHTML=i;
                a.addEventListener('click',function(e){
                    e.preventDefault();
                    alert(i);//i是自由变量,要去父作用域寻找值
                })
                document.body.appendChild(a);                
            })(i);
        }
    </script>
    <script>
        //闭包的应用
        function isFirstLoad(){
            var _list=[];//通常_开头的变量表示私有
            return function(id){
                if(_list.indexOf(id) >= 0){//不是第一次出现
                    return false;
                }else{
                    _list.push(id);
                    return true;
                }
            }
        }
        var firstload=isFirstLoad();
        console.log(firstload(10));//true
        console.log(firstload(10));//false
        console.log(firstload(20));//true
    </script>
原文地址:https://www.cnblogs.com/chenyingying0/p/12733764.html