作用域和闭包

题目:

  • 说一下对变量提升的理解
  • 说明this几种不同的使用场景
  • 创建10个<a>标签,点击的时候弹出来对应的序号
  • 如何理解作用域
  • 实际开发中闭包的应用

知识点:

1、执行上下文

2、this

3、作用域 

4、作用域链 

5、闭包

一、执行上下文

  • 范围:一段script内或一个函数
  • 全局:变量定义、函数声明 ——范围在一段<script>标签内。在函数执行之前,先把变量定义、函数声明拿出来
  • 函数:变量定义、函数声明、this、arguments——范围在函数内。在函数执行之前,先把函数中的变量定义、函数声明、this、arguments拿出来

PS:函数声明和函数表达式的区别:

//执行上下文
console.log(a) //undefined
var a = 10

fn('张三',22) //张三 22
function fn(name){
    age = 20
    console.log(name,age)
    var age
}

 在script标签内的全局函数执行之前,如果是函数表达式,会把声明的变量名拿出来放到最前面,先赋值为undefined,如果是函数声明则把整个函数放到最前面。同理,在执行第5行的函数时,会先在函数内执行前,先把定义的变量、函数声明、this和arguments拿出来放到最前面,先赋值为undefined,然后再执行

二、this

  • this要在执行时才能确认值,定义时无法确认
  • 作为构造函数执行
  • 作为对象属性执行
  • 作为普通函数执行
  • call apply bind
//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

//构造函数中的this
function Foo(name) {
    //首先创建一个this的空对象
    this.name = name
    // return this
}
var f = new Foo('zhangsan')

//对象属性中的this
var obj = {
    name:'A',
    printName:function () {
        console.log(this.name)
    }
}
obj.printName() //this指向obj

//作为普通函数来执行
function fn () {
    console.log(this)
}
fn()//this === window

//call apply bind
function fn1(name, age) {
    alert(name + age)
    console.log(this)
}
// fn1("zhangsan")
fn1.call({x: 100}, "lisi", 22) 
/*
第一个参数是指定this的指向,这里this指向{x:100}这个对象
第二个参数是传入的参数,第二个当参数
也就是说执行fn1时使用call,那么第一个参数就是this,就是这么简单!
在实际中call更常用
*/
// apply 除了传入参数是以一个数组形式外,和call一模一样
function fn2(name, sex) {
    alert(name + "," + sex)
    console.log(this)
}
fn2.apply({age:22},['taiyang','man'])

//bind,不能使用函数声明,使用bind必须是函数表达式
var fn3 = function fn3(name, age) {
    alert(name + age)
    console.log(this)
}.bind({
    x: 123
})
fn3('taiyang', 22)

三、作用域

  • JS没有块级作用域
  • 只有函数和全局作用域
  • 函数的父级作用域,是函数定义的时候的父级作用域,不是函数执行的时候的父级作用域,即函数在哪定义,父级作用域就在什么地方

//无块级作用域
if(true){
    var name = 'taiyang'
}
console.log(name)

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

// 作用域链
var a = 200
//
// 这个函数在全局定义,其父级作用域就是全局作用域
function fn() {
    var b = 100
    // 当前作用域没有定义的变量,称作自由变量
    console.log(a)
    console.log(b)
}
fn()

// 父级作用域
 var a = 100
// F1函数在全局定义,其父级作用域就是全局作用域
function F1() {
    var b = 200
    // F2函数在F1定义,其父级作用域就是F1的作用域
    function F2(){
        var c = 300
        // a,b为自由变量,即不在该函数内定义的变量,首先会从F2函数中寻找a
        //如果没有找到,会去寻找它的父级作用域F1,如果还没有找到,就继续寻找全局作用域,如果还没找到,就会报错
        console.log(a)
        console.log(b)
        console.log(c)
    }
    F2()
}
F1()

理解父级作用域:一个函数的作用域是它定义时候的作用域,如这里F2的父级作用域就是:哪个函数定义了F2函数,那它的父级作用域就是那个函数,这对理解闭包是很重要的

四、闭包

闭包的使用场景

  • 函数作为返回值,如上图所示
  • 函数作为参数传递
//函数作为参数来传递
function F1() {
    var a = 100;
    return function(){
        console.log(a)
    }
}
var f1 = F1()
function F2(fn) {
    var a = 200
    fn()//100
}
F2(f1)

记住闭包是通过寻找其父级作用域的,而其父级作用域是定义它时的作用域,与执行作用域(如F2函数的作用域)没有关系,把握这点就不会出错。闭包通过以上两个例子,就基本概括了。

 

解题:

1、说一下对变量提升的理解

主要考查变量提升和函数声明(要注意函数表达式对比),即在一段<script>标签或一个函数内,在函数执行前,声明的变量会前置并首先赋值为undefined,如果是一个函数声明,则会把整个函数前置,如果是一个函数表达式,则同其他定义的变量一样,先赋值为undefined。函数内同理。

2、说明this的几种使用场景

  • 作为构造函数执行
  • 作为对象属性执行
  • 作为普通函数执行
  • call apply bind

3、如何理解作用域

关键3点:

  • 自由变量
  • 作用域链,即自由变量的查找
  • 闭包的两个场景

首先什么是闭包?《JS高级程序设计》是这样定义的:闭包是指有权访问另一个函数作用域中的变量的函数。

在闭包中存在自由变量(即自身函数作用域为声明的变量),在函数执行时,自由变量会首先从自身作用域中查询是否存在该变量,如果没有找到该变量,则会进一步从父级作用域中去寻找,如果在父级作用域中没有找到,则从父级作用域的父级作用域中去寻找,这样就构成了作用域链,也即自由变量的查找。父级作用域是指函数定义时的作用域,即函数在哪定义,哪该函数的父级作用域就是哪,注意父级作用域不是执行时的作用域,是函数定义时的作用域。

闭包的两个使用场景:

  1. 函数作为返回值
  2. 函数作为参数传递

示例如上

4、闭包的实际应用场景

//闭包的实际应用,主要用于封装变量,收敛权限
function isFirstLoad() {
    var _list = []
    return function (id) {
        if (_list.indexOf(id) != -1) {
            return false
        } else {
            _list.push(id)
            return true
        }
    }
}
var FirstLoad = new isFirstLoad()
FirstLoad(100)//true
FirstLoad(100)//false
FirstLoad(200)//true
//在isFirstLoad外无法修改_list的值,因此具有很高的安全性

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值