JS2 - 作用域和闭包

1、题目

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



2、知识点

⑴、执行上下文

console.log(a)  // undefined
var a = 100;

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

①、

②、函数
函数在执行之前,也会创建一个函数执行上下文环境,函数执行上线文中会多出this arguments和函数的参数。

  • 范围:一段<script>或者 一个函数
  • 全局:变量定义、函数声明
  • 函数:变量定义、函数声明、this、arguments

备注:注意 “函数声明” 和 “函数表达式” 的区别



⑵、this

**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

  • 作为构造函数执行
  • 作为对象属性执行
  • 作为普通函数执行
  • 用于call apply bind
// 构造函数
function Foo( name ){
	this.name = name
}
var f = new Foo( 'zhangsan' )

// 作为一个对象的属性
var obj = {
	name: 'A',
	printName: function(){
		console.log( this.name )
	}
}
obj.printName()

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

// call apply bind
function fn1( name, age ){
	// alert( name )
	console.log( 'name', name )
	console.log ( this )
}
// fn1.call({ x: 100}, 'zhangsan', 20)
fn1.apply({ x:200}, [ 'zhangsan', 20 ])

var fn2 = function( name, age ){
	console.log( 'name', name )
	console.log( this )
}.bind({ y: 300 })
fn2( 'zhangsan', 20 )


⑶、作用域

if (true) {
    var name = 'zhangsan'
}
console.log(name)

从上面的例子可以体会到作用域的概念,作用域就是一个独立的地盘,让变量不会外泄、暴露出去。上面的name就被暴露出去了,因此,JS 没有块级作用域,只有全局作用域和函数作用域

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

全局作用域就是最外层的作用域,如果我们写了很多行 JS 代码,变量定义都没有用函数包裹,那么他们就全部都在全局作用域中。这样的坏处就是很容易撞车。



⑷、作用域链

var a = 100
function fn() {
    var b = 200
    console.log(a)
    console.log(b)
}
fn()

console.log(a)要得到a变量,但是在当前的作用域中没有定义a(可对比一下b)。当前作用域没有定义的变量,这成为自由变量。自由变量如何得到 ———— 向父级作用域寻找。

var a = 100
function F1() {
    var b = 200
    function F2() {
        var c = 300
        console.log(a)
        console.log(b)
        console.log(c)
    }
    F2()
}
F1()

如果父级也没呢?再一层一层向上寻找,直到找到全局作用域还是没找到,就宣布放弃。这种一层一层的关系,就是作用域链



⑸、闭包

应用场景

  • 函数作为返回值
  • 函数作为参数传递
// 函数作为返回值
function F1() {
    var a = 100
    return function () {
        console.log(a)
        // a 自由变量, 向父作用域去寻找 - 函数定义 
    }
}
var f1 = F1()
var a = 200
f1()
// => 100

// 函数作为参数来传递
function F1() {
    var a = 100
    return function () {
        console.log(a)
    }
}
function F2(f1) {
    var a = 200
    console.log(f1())
}
var f1 = F1()
F2(f1)
// => 100

自由变量将从作用域链(父级向上)中去寻找,但是依据的是函数定义时的作用域链,而不是函数执行时



3、解题

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

  • 变量定义
  • 函数声明 ( 注意和函数表达式的区别 )

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

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

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

错误的写法

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)
    })
    document.body.appendChild(a)
}

正确的写法

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)
        })
        document.body.appendChild(a)
    })(i)
}

拓展:DocumentFragment 关于 DOM 操作的性能问题

⑷、如何理解作用域

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

⑸、实际开发中闭包的应用

闭包的实际应用,主要是用来封装变量,收敛权限。即把变量隐藏起来,不让外面拿到和修改。

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

// 在 isFirstLoad 函数外面, 根本不可能修改掉 _list 的值
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

后海 0_o

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值