og

闭包

Snipaste_20200510_172501.jpg

先了解变量提升与函数提升

  1. 变量声明提升 通过var声明的变量,在定义语句之前就能访问到 值:undefined
  2. 函数提升声明 通过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()") }

再了解执行上下文

  1. 代码分类(位置) 全局代码 函数(局部)代码
  2. 全局执行上下文 在执行全局代码前将window确定为全局执行上下文 对全局数据进行预处理

*var定义的全局变量==>undefined,添加为window的属性 *function声明的全局变量==>赋值(fun),添加为window的方法 *this ==>赋值(window) 开始执行全局代码 3. 函数执行上下文 在调用函数,准备执行函数体之前,创建对应的函数执行上下文对象 对局部数据进行预处理 *形参变量==>赋值(实参)==>添加为执行上下文属性 *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. 闭包包含被引用变量(函数)的对象

最简单的闭包

        
  • 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)

作用:

  1. 使用函数内部的变量在函数执行完后,仍然存活在内存中(延长了局部变量的生命周期)
  2. 让函数外部可以操作(读写)到函数内部的数据(变量/函数)

生命周期:

  1. 产生:嵌套内部函数定义就会产生闭包(不用调用内部函数)
  2. 死亡:嵌套内部函数成为垃圾对象

缺点:

  1. 延长了局部变量的生命周期,占用时间变长,容易造成内存泄漏 记得释放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>

Article at   2020/05/11 13:40  Published  code  Category,viewed  244  times

Relevant tags:    JS 

Address:   https://www.kedong.me/article/3

Copyright Notice: Freely reproduced for non-commercial use