闭包
先了解变量提升与函数提升
- 变量声明提升 通过var声明的变量,在定义语句之前就能访问到 值:undefined
- 函数提升声明 通过function声明的函数,在函数之前就能直接调用 值:函数对象
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
var a=3
function fn(){
console.log(a)
var a=4
}
fn() //a输出多少? undefined
console.log(b) //undefined 变量提升
fn2() //可调用 函数提升
fn3() //不可调用 变量提升
var b=3
function fn2(){
console.log("fn2()")
}
var fn3=function(){
console.log("fn3()")
}
再了解执行上下文
- 代码分类(位置) 全局代码 函数(局部)代码
- 全局执行上下文 在执行全局代码前将window确定为全局执行上下文 对全局数据进行预处理 *var定义的全局变量==>undefined,添加为window的属性 *function声明的全局变量==>赋值(fun),添加为window的方法 *this ==>赋值(window) 开始执行全局代码
- 函数执行上下文 在调用函数,准备执行函数体之前,创建对应的函数执行上下文对象 对局部数据进行预处理 *形参变量==>赋值(实参)==>添加为执行上下文属性 *arguments==>赋值(实参列表),添加为执行上下文属性 *var定义的局部变量==>undefined,添加为执行上下文的属性 *function声明的函数==>赋值(fun),添加为执行上下文的方法 *this==>赋值(调用函数的对象) 开始执行函数体代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
//放到html 的script中运行
//全局执行上下文
console.log(a1,window.a1)
a2()
console.log(this)
var a1 = 3
function a2(){
console.log("a2()")
}
console.log(a1)
//函数执行上下文
function fn(a1){
console.log(a1) //2
console.log(a2) //undefined
a3() //a3()
console.log(this) //window
console.log(arguments) //(2,3)
var a2 = 3
function a3(){
console.log("a3()")
}
}
fn(2,3)
再了解下作用与作用于
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
var x= 10;
function fn(){
console.log(x);
}
function show(f){
var x=20
fn();
}
show(fn)
闭包
- 当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时,就产生了闭包
- 闭包包含被引用变量(函数)的对象
最简单的闭包
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
function fn1(){
var a=2
function fn2(){//执行函数定义就会产生闭包(不用调用内部函数)
console.log(a)
}
// fn2()
}
fn1()
常见的闭包 将函数作为另一个函数的返回值
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
function fn1(){
//此时闭包已经产生(函数提升,内部函数对象已创建)
var a=2
function fn2(){
a++
console.log(a)
}
return fn2()
}
var f=fn1()
f() //3
f() //4
f=null //闭包死亡 (包含闭包的函数对象成为垃圾对象)
*将函数实参传给另一个函数调用 function showDelay(msg,time){ setTimeout(function(){ alert(msg) //假如没有alert(msg) 就不会产生闭包 },time) } showDelay("111",1000)
作用:
- 使用函数内部的变量在函数执行完后,仍然存活在内存中(延长了局部变量的生命周期)
- 让函数外部可以操作(读写)到函数内部的数据(变量/函数)
生命周期:
- 产生:嵌套内部函数定义就会产生闭包(不用调用内部函数)
- 死亡:嵌套内部函数成为垃圾对象
缺点:
- 延长了局部变量的生命周期,占用时间变长,容易造成内存泄漏 记得释放f=null
巩固:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
var name = "window"
var object = {
name: "obj",
getNameFunc: function () {
return function () {
return this.name;
}
}
}
console.log(object.getNameFunc()())
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
var name2 = "window"
var object2 = {
name: "obj",
getNameFunc: function () {
var that = this
return function () {
return this.name;
}
}
}
console.log(object2.getNameFunc()())
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
function fun(n, o) {
console.log(o)
return {
fun: function (m) {
return fun(m, n)
}
}
}
var a = fun(0); a.fun(1); a.fun(2); a.fun(3) //undefined 0 0 0
var b = fun(0).fun(1).fun(2).fun(3)//undefined 0 1 2
var c = fun(0).fun(1); c.fun(2); c.fun(3) //undefined 0 1 1
这个东西当年做对的,现在回头反而不会了。。。。 关键点: a.fun(1)并没有一个新的变量接受,所以闭包是产生了但是立即消失了 var a1=fun(0); var a2=a1.fun(1);var a3=a2.fun(2) ;var a4=a3.fun(2) 可以参照这条理解。
运用: 节流与防抖
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
//<body>
//<button id="btn1">节流函数</button>
//<button id="btn2">防抖函数</button>
//<script type="text/javascript">
function debounce(fn, delay) {
let timeoutId = null
console.log("debounce已被运行")
return function () {
//console.log("this:",this,'arguments:',arguments)
const that = this
const args = arguments
if (timeoutId) {
//console.log('删除定时器')
clearTimeout(timeoutId)
}
timeoutId = setTimeout(() => { console.log('运行需要运行的函数'); fn.apply(that, args) }, delay)
}
}
btn1 = document.getElementById('btn1')
btn1.addEventListener('click', throttle(onclick1, 1000), false);
btn2 = document.getElementById('btn2')
btn2.addEventListener('click', debounce(onclick1, 1000), false);
//</script>
//</body>
(完)
0条看法
最新最后最热
等待你的评论