ES5作用域闭包

11 篇文章 0 订阅
1 篇文章 0 订阅

函数声明 函数表达式

  • 区别是函数声明 可以提升,函数表达式不能提升函数,函数表达式只是个变量提升而不是函数提升
//var fn1 = undefined //这是var的变量声明的提升
//var a = undefined // 这是var的变量声明的提升
fn()//可执行
function fn(){
//函数声明
}
fn1()//undefined
var fn1 = function(){
//函数表达式
}
console.log(a)//undefined
var a = 100
var b = 200
console.log(b)//200
console.log(c)//抛错 c is not defined
fn('zhangsan')
function fn(name){
	console.log(this)//指向window
	console.log(arguments)//zhangsan
	age = 20
	console.log(name,age)//name不传值,就是undefined
	var age //变量名提升是在fn函数作用域里的
	bar(100)
	function bar(num){//bar函数提升是在fn函数作用域里的
		console.log(num)
	}
}

题目

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

知识点

执行上下文
  • 范围: 一段< script > 或者 一个函数
  • 全局:变量定义、函数声明 在一段< script >里
  • 函数:变量定义、函数声明、this、 arguments
    1.针对一段< script >执行上下文是全局的,执行上下文的范围是一段< script > 或者 一个函数
    2.在全局中执行上下文(也就是在一段< script >里),会把变量定义、函数声明拿出来
    3.在函数里,函数执行之前,会把变量定义、函数声明、this、 arguments 拿出来
    注意,函数声明和函数表达式的区别
console.log(a)
var a = 100
fn('zhangsan');
function fn(name){
	console.log(name)
	age = 20;
	console.log(name,age)
	var 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
this运行的几种场景
  • 作为构造函数执行
function Foo(name){
	//this = {} //执行上下文,函数中this先拿出来
	this.name = name
	//return this //返回this
}
var f = new Foo('zhangsan')
  • 作为对象属性执行
var obj = {
	name: 'A',
	printName: function(){
		console.log(this.name)
	}
}
obj.printName()// this === obj //函数printName作为对象属性来执行
  • 作为普通函数执行
function fn(){
	console.log(this)
}
fn()//this === window //作为普通函数执行,this指向window
  • call apply bind
    call相对常用
function fn1(name,age){
	alert(name)
	console.log(this)
}
fn1.call({x:100},'zhangsan',20)//函数fn1运行,this === {x:100} // 'zhangsan',20 作为参数传入函数fn1中,
//call的作用就是改变this指向
fn1.apply({y:200},['zhangsan',20])//apply与call区别就是后面参数是否是数组形式
var fn2 = function(name){
	alert(name)
	console.log(this)
}.bind({z:300})//加了bind,函数fn2运行时,this指向{z:300},不然指向window
fn2('zhangsan');
//.bind() 只能用于函数表达式,不能用于函数声明,不然报错
作用域
  • es5没有块级作用域
  • es5只有函数和全局作用域
if(true){
	var name = 'zhangsan'
	//大括号里就是块级作用域
	// es6 就有块级作用域 let const
	//es5中尽量别再块级作用域里用var声明变量
}
console.log(name)// 'zhangsan'
//函数和全局作用域
var a = 100
function fn(){
	var a = 200 //将变量定义在函数里,可以起到与外界隔绝的作用
	console.log('fn',a)//a === 200,不用通过作用域链往层找a
}
console.log('global',a)
fn()//函数fn运行 就会修改全局变量a
作用域链

自由变量:当前作用域没有定义的变量

var a = 100
function fn(){
	var b = 200
	//当前作用域没有定义的变量,即“自由变量”
	//函数可以规定作用域,函数体里可以定义变量
	console.log(a)//100 //从父级作用域找a
	//函数的父级作用域是函数定义时候的作用域
	//而不是函数运行时候的作用域
	console.log(b)//200
}
fn()
var a = 100
function fn1(){
	var b = 200
	function fn2(){
		var c = 300
		console.log(a)//a是自由变量 
		//fn2函数作用域中没有a变量
		//a先从fn2中找,再从fn1中找,最后在全局作用域中找到a
		console.log(b)//b是自由变量
		console.log(c)
	}
	fn2()
}
fn1()
  • 作用域
var a = 100
function fn(){
	var b = 200 //函数作用域里的b
	console.log(a)
	console.log(b)
}
fn()
var b = 20000 //全局作用域里的b
//两个b没有任何关系,互不影响

  • es5无块级作用域
if(true){
	var name = 'zhangsan'
}
console.log(name)
//等同于,且推荐以下写法
var name
if(true){
	name = 'zhangsan'
}
console.log(name)
闭包
function F1(){
	var a = 100
	//返回一个函数,(函数作为返回值)
	return function(){
		console.log(a)//这里的a是自由变量,就从父级找
		//在定义的地方根据作用域链向父级作用域找a
	}
}
//f1 得到一个函数
var f1 = F1()
var a = 200// 这个a定义在全局作用域里
f1()//100 //函数f1 在全局作用域下执行,但自由变量是根据定义时候的作用域查找
闭包的使用场景
  • 函数作为返回值(上一个demo)
  • 函数作为参数传递(下一个demo)
function F1(){
	var a = 100 // 如果这行注释掉,最后结果是300,而不是200
	
	return function(){
		console.log(a)
	}
}
f1 = F1()
function F2(fn){
	var a = 200
	fn()
}
var a = 300 // 上面的 var a=100 注释掉,同时这行也注释掉,结果是报错 is not defined
//因为这就是看在哪里定义的
F2(f1) // 100

解题

说一下变量提升的理解
  • 变量定义
  • 函数声明(注意和函数表达式的区别)
说明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)//此处的i是自由变量,点击的时候,循环完成
		//全局变量的i===10,无论怎么点击都是10
	})
	document.body.appendChild(a)
}

正确写法

//正确写法
var i, a
for(i = 0, i < 10, i++){
	(function(i){
		a = document.createElement('a')
		a.innerHTML = i + '<br>'
		a.addEventListener('click',function(e){
		e.preventDefault()
		alert(i)//i找到参数的i
	})
	document.body.appendChild(a)
	})(i)//i作为参数传入自运行函数,i存在与函数作用域里
}
如何理解作用域
  • 自由变量
  • 作用域链,即自由变量的查找
  • 闭包的两个场景
实际开发中的闭包的应用

实际开发中闭包的应用:主要用于封装变量,收敛权限

//实际开发中闭包的应用:主要用于封装变量,收敛权限
function isFirstLoad(){
	var _list = []
	return function(id){
		if(_list.indexOf(id) >= 0){
			return false
		}else{
			return true
		}
	}
}
//使用
var firstLoad = isFirstLoad()
firstLoad(10)//true
firstLoad(10)//false
firstLoad(20)//true
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值