2018.09.24 学习笔记 // 前端JavaScript // 作用域与闭包

题目:

  • 说一下对变量提升的理解:变量定义&函数声明(注意和函数表达式的区别)
  • 说明this几种不同的使用场景:构造函数&对象属性&普通函数&call apply bind
  • 用js创建10个<a>标签,点击的时候弹出对应的序号
var i
for(i = 0; i < 10; i++){
    (function(i){
        var a = document.creatElement('a')
        a.innerHTML = i + '<br>'
        a.addEventListener('click',function(e){
            e.preventDefault()
            alert(i)
        })
        document.body.appendChild(a)
    })(i) //自执行函数 将i传进来
}
  • 如何理解作用域:自由变量&作用域链&闭包的两个使用
  • 实际开发中闭包的作用:闭包实际应用中主要用于封装变量,收敛权限
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
firstLoad(20) //true
firstLoad(20) //false

// 目的:在 isFirstLoad 函数外面,不可能改掉 _list 的值

知识点:

  • 执行上下文
  • this
  • 作用域
  • 作用域链
  • 闭包

1. 执行上下文

  • 范围:一段<script>或者一个函数
  • 全局执行上下文(一段<script>):变量定义、函数声明,都提声
  • 函数执行上下文(一个函数):变量定义、函数声明、this、arguments
<script>
console.log(a)
var a = 100 //变量定义,实际不要这么写

fn('zhangsan') // 'zhangsan' 20
function fn(name){ //函数声明
    age = 20 //所以age在这里没有关系
    console.log(name,age)
    var age 
}
</script>

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

fn();//不报错
function fn(){
    //声明
}
fn1();//报错
var fn1 = function (){
    //表达式
} 

2. 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

四种情况:

  • 作为构造函数执行
  • 作为对象属性执行
  • 作为普通函数执行
  • call apply bind 函数
//构造函数
function Foo(name){
    //this = {}
    this.name = name
    //return this
}
var f = new Foo('zhangsan') //牵扯到new一个对象的过程

//对象
var odj = {
    name:'A',
    printName: function(){
        console.log(this.name)
    }
}
obj.printName() //this就是obj对象

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


// call apply bind
function fn1(name){
    alert(name)
    console.log(this)
}
fn1.call({x:100},'zhangsan',20) //this :{x:100} jQuery经常用call来改变this值

//对于bind来说,可以这样使用
var fn2 = function(name,age){ //函数表达式才能用.bind 函数声明会报错
    console.log(this) 
}.bind({y:200}) //this从window变为{y:200}
fn2('zhangsan',20)

3. 作用域

  • 没有块级作用域
  • 只用函数和全局作用域
//无块级作用域
if(ture){
    var name = 'zhangsan'
}
console.log(name) //java会报错,因为变量出不了{},但是js不会,但是程序不易读还是尽量不要在块里声明变量

//函数和全局作用域
var a = 100
function fn(){
    var a = 200
    console.log('fn',a) //200
}
console.log('global',a) //100
fn()

4. 作用域链

  • 自由变量:当前作用域没有定义的变量,即“自由变量”
  • 作用域链:一个自由变量一直不断的向父级作用域去找,形成一个链式结构
var a = 100
function fn(){ //这个函数的父级作用域是全局作用域
    var b = 200
    //a:当前作用域没有定义的变量,即“自由变量”
    console.log(a) 
    console.log(b) 
}
fn()
//函数的父级作用域是函数定义的时候被定义的时候被调用的,不是函数执行的时候

5. 闭包

闭包的使用场景:

  • 函数作为返回值
  • 函数作为参数传递
//1.函数作为返回值
function F1(){
    var a = 100

    //返回一个函数
    return function(){
        console.log(a) //a是自由变量,上父级作用域
    }
}

//f1得到一个函数
var f1 = F1()
var a = 200
f1() //100 重申:是定义时候的作用域 而非执行时候的

//2.函数作为参数
function F1(){
    var a = 100

    //返回一个函数
    return function(){
        console.log(a) //a是自由变量,上父级作用域
    }
}
var f1 = F1()
function F2(fn){
    var a = 200
    fn() //作用域去定义的地方找
}
F2(f1)

猜你喜欢

转载自blog.csdn.net/weixin_41004238/article/details/82829414