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>