javascript考点 —— 作用域和闭包

一、执行上下文

  • 范围:一段<script>或者一个函数
  • 全局:变量定义、函数声明
  • 函数:变量定义、函数声明、this、arguments
console.log(a)    //undefined
var a = 100
fn('zhangsan')
function fn(name){
    age = 20
    console.log(name, age)   //'zhangsan'   20
    var age
}


//实际过程中执行的顺序是:
var a
function fn(name){
    //函数
    var age
    age = 20
    console.log(name, age)   //'zhangsan'   20
}
console.log(a)    //undefined
a = 100
fn('zhangsan')

1、函数声明与函数表达式的区别:

全局:

//函数表达式,在代码执行之前,会把函数的声明放到最前面
fn()
function fn() {
    //函数声明
}
//上述代码的实际执行的代码

function fn() {
    //函数声明
}

fn()



//函数表达式,在代码执行之前不会将它提前,因为代码还没有执行到fn1赋值为函数的代码,此时fn1就为undefined,所以会报错。函数表达式的执行和普通变量的执行是一样的。
fn1()
var fn1 = function() {
    //函数表达式
}
//上述代码的实际执行的代码
var fn1
fn1()
fn1 = function(){

}

注意:代码在执行时,this和arguments已经确定。

二、this

this要在代码执行时才能确认值,定义时无法确定。this的几种情况:

  • 作为构造函数执行
function Foo(name) {
    this.name = name       //this === f
}
var f = new Foo('zhangsan')
  • 作为对象属性执行
var obj = {
    name: 'A',
    peintName: function(){
        console.log(this.name)         //this === obj
    }
}
obj.printName()    
  • 作为普通函数执行
function fn() {
    console.log(this)        //this === window
}
fn() 
  • call  apply   bind
function fn1(name, age) {
    console.log(name)
    console.log(this)
}
fn1.call({x:100}, 'zhangsan', 20)
fn1.apply({x:100},['zhangsan', 20])

var fn2 = function(name, age) {
    console.log(name)
    console.log(this)
}.bind({y:200})
fn2('zhangsan', 20)
//bind必须是函数表达式

三、作用域

  • js没有块级作用域
if(true) {
    var name = 'zhangsan'
}
console.log(name)     //'zhangsan'
  • 只有函数和全局作用域
var a = 100
function fn() {
    var a = 200
    console.log('fn', a)     //'fn'  200
}
console.log('global',a)      //'global'  100
fn()

四、作用域链

什么是自由变量?

var a = 100
function fn() {
    var b = 200
    console.log(a)   //当前作用域没有定义的变量,即自由变量,这里的a就是自由变量,因为在函数作用域里面没有声明
    console.log(b)
}
fn()


//注意,函数的父级作用域是定义时的作用域,不是执行时的作用域
var a = 100
function F1() {
    var b = 200
    function F2() {
        var c = 300
        console.log(a)   //a是自由变量
        console.log(b)   //b是自由变量
        console.log(c)
    }
    F2()
}
F1()

//F1的父级作用域是全局作用域
//F2的父级作用域是F1
//a在F2没有,就去父级作用域F1里面找,没有就去F1的父级作用域去找
//b在F2没有,就去父级作用域F1找

什么是作用域链:一个自由变量,一直不断的去父级作用域找,就像这里的a。

五、闭包

闭包的使用场景:

  • 函数作为返回值
function F1() {
     var a = 100
     //返回一个函数(函数作为返回值)
     return function() {
         console.log(a)      
     }
 }
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

六、题目解答:

  • 说一下变量提升的理解

解答 :https://www.jianshu.com/p/2f4659dfaed3

  • 说明this几种不同的使用场景

解答:作为构造函数执行、作为对象属性执行、作为普通函数执行、call  aapply  bind

  • 创建10个<a>标签,点击的时候弹出对应的序号

解答:

//这是错误的写法,因为我们点击不知道是什么时间,等我们点击的时候,for循环早就执行结束了,然后i就一直是10
var i, a
for(i = 0; i < 10; i++){
    a = document.createElement('a')
    a.innerHTML = i + '<br>'
    a.addEventListener('click', function(e){
         e.preventDefault()
         alert(i)           //i是自由变量,要去父级作用域里面找
     })
     document.body.appendChild(a)
}
    //这是正确写法,这里把每个i都存在函数里面,这里创建了是个函数,每个函数里 
      面有一个i
    var i
    for(i = 0; i < 10; i++){
        (function (i) {
            var a = document.createElement('a')
            a.innerHTML = i + '<br>'
            a.addEventListener('click', function(e){
                e.preventDefault()
                alert(i)    //i自由变量
            })
            document.body.appendChild(a)
        })(i)
    }
  • 如何理解作用域

解答:自由变量、作用域链、闭包的场景

  • 实际开发中闭包的应用

解答:

//主要用于封装变量,收敛权限
function isFirstLoad() {
    var _list = []
    return function(id) {
        if(_list.indexOf(id) >= 0) {
            return false
        } else {
            _list.push(id)
            return true
        }
    }
}

var firstLoad = isFirstLoad()
firstLoad(10)     //true
firstLoad(10)     //false
firstLoad(20)     //true

猜你喜欢

转载自blog.csdn.net/zhanghuali0210/article/details/82118317