复习3----作用域和闭包

Posted 慕容文刀

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了复习3----作用域和闭包相关的知识,希望对你有一定的参考价值。

 
题目
1.说一下对变量提升的理解
2.说明this几种不同的使用场景
3.创建10个<a>标签,点击时弹出对应序号
4.如何理解作用域
5.实际开发中闭包的应用
 
知识点#####
  • 执行上下文
 
范围:一段<script>或者一个函数 或者eval代码
全局:变量定义、函数声明 (提前拿出来)                    针对一段<script>
函数:变量定义、函数声明、this、arguments  (提前拿出来)                    针对一个函数
 eval不常用,也不推荐大家用。
 
在一段js代码拿过来真正一句一句运行之前,浏览器已经做了一些“准备工作”,在“准备工作”中完成了哪些工作:
1.变量、函数表达式——变量声明,默认赋值为undefined;
2.this——赋值;
3.函数声明——赋值;
这三种数据的准备情况我们称之为“执行上下文”或者“执行上下文环境”。
 
 
ps:注意函数声明和函数表达式的区别
//函数声明
function fn(){
    //.....
}
 
//函数表达式
var fn1=function(){
    //.....
}

 

//全局console.log(a); //undefined
var a=100
 
fn(‘zhangsan‘) //zhangsan 20
function fn(name){
    //函数
    console.log(this); //Window
    console.log(arguments); //"zhangsan"
    age=20
    console.log(name,age);
    var age   //age会提前
}
  • this
 
this要在执行时才确认值,定义时无法确认
var a={
    name:‘A‘,
    fn:function(){
        console.log(this.name);
    }
}
a.fn() //this===a
a.fn.call({name:‘B‘}) //this==={name:‘B‘}
var fn1=a.fn
fn1() //this===Window
  • - 作用域
js没有块级作用域
if(true){
    var name=‘zhangsan‘
}
console.log(name); //zhangsan

只有函数和全局作用域

var a=100
function fn(){
    var a=200
    console.log(‘fn‘,a)
}
console.log(‘global‘,a)  //global 100
fn() //fn 200

 

  •  作用域链
自由变量
var a=100
function fn(){    
    var b=200    
    console.log(a) //当前作用域没定义的变量,即‘自由变量‘    
    console.log(b)
}
fn() //100 200

调用在当前作用域不存在的变量,便会向父级作用域查找。需要注意的是,父级作用域是函数定义时产生的,并非函数调用时。

var a=100
function F1(){
    var b=200
    function F2(){
        var c=300
        console.log(a) //a是自由变量,在F2中未找到便向父级作用域F1查找,仍未找到,继续向上查找,在Window中找到
        console.log(b) //b是自由变量
        console.log(c)
    }
    F2()
}
F1() //100 200 300
  • - 闭包
使用场景,函数作为返回值;函数作为参数传递
//闭包的使用场景:函数作为返回值
function F1(){
    var a=100
    //返回一个函数
    return function(){
        console.log(a) //自由变量,父作用域查找,仍未找到,继续向上查找,在Window中找到
    }
}
//f1得到一个函数
var f1=F1()
var a=200
f1()  //100   
//闭包的使用场景:函数作为参数传递
function F1(){
    var a=100
    return function(){
        console.log(a) //自由变量,父作用域查找
    }
}
var f1=F1()
function F2(fn){
    var a=200
    fn()
}
F2(f1) //100

 

 
#####解题#####
**1.说一下对变量提升的理解**
执行上下文的知识:http://www.jianshu.com/p/a6d37c77e8db
在<script>或函数中,各个变量、函数的声明与定义会被提前
 
**2.说明this几种不同的使用场景**
this的几种执行情况:
  • 作为构造函数执行
  • 作为对象属性执行
  • 作为普通函数执行
  • call apply bind
//构造函数
function Foo(name){
    this.name=name
}
var f=new Foo(‘zhangsan‘)

 

//对象属性
var obj={
    name:‘zhangsan‘,
    printName:function(){
        console.log(this.name)
    }
}
obj.printName()

 

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

 

//call apply bind
function fn1(name,age){
    alert(name)
    console.log(this)    
}
fn1.call({x:100},‘zhangsan‘,20)    //({x:100}
//apply
fn1.apply({x:100},[‘zhangsan‘,20])    //({x:100}
//call, apply方法区别是,从第二个参数起, call方法参数将依次传递给借用的方法作参数, 而apply直接将这些参数放到一个数组中再传递
//bind
var fn2=function (name,age){ //bind在函数声明的形式后不可用,必须是函数表达式
    alert(name)
    console.log(this)
}.bind({y:200})
fn2(‘zhangsan‘,20)   //{y: 200}

 

**3.创建10个```<a>```标签,点击时弹出对应序号**
//错误的写法
    var i,a;
    for(i=0;i<10;i++){
//除了click函数内部,都为全局作用域,会被覆盖。因此最终 i 的值为10
//全局作用域
        a = document.createElement(‘a‘);
        a.innerhtml = i+‘</br>‘ ;
        a.addEventListener(‘click‘,function(e){
            e.preventDefault();
            alert(i);  //i为自由变量,向上去父作用域查找时,值已经变成10. 因为click事件执行时,其它部分早已执行完毕。
        })        
        document.body.appendChild(a);
    }
    

 

//正确的写法
var i
for(i=0;i<10;i++){
//多包了一层,除了click函数,其它变量的作用于都变成了函数作用域,而不是全局作用域,因此不会被覆盖。相当于创建了10个函数
    (function(i){      
   //函数作用域
        var a=document.createElement(‘a‘)
        a.innerHTML=i
        a.addEventListener(‘click‘,function(e){
            e.preventDefault()
            alert(i)   //i为自由变量,向上去父作用域查找,就找到调用时的i值 (加粗处)
        })
        document.body.appendChild(a)
    })(i)
}

 

 
**4.如何理解作用域**
回答要点:
自由变量
作用域链,即自由变量的查找
闭包的两个场景
 
**5.实际开发中闭包的应用**
//闭包实际应用中主要用于封装变量,收敛权限
function isFirstLoad(){
    var _list=[]
    return function(id){
        if(_list.indexOf(id)>=0){
            return false
        }else {
            _list.push(id)
            return true
        }
    }
}
//使用
var firstLoad=isFirstLoad()9
firstLoad(10) //true
firstLoad(10) //false
firstLoad(20) //true
//在isFirstLoad函数外,无法修改_list的值

 

以上是关于复习3----作用域和闭包的主要内容,如果未能解决你的问题,请参考以下文章

js面试题知识点全解(一作用域和闭包)

作用域和闭包

JavaScript中的作用域和闭包

了解js基础知识中的作用域和闭包以及闭包的一些应用场景,浅析函数柯里化

JS(作用域和闭包)

JavaScript作用域和闭包