闭包
什么是闭包
当一个函数的返回值是另一个函数,而返回的函数如果调用了父函数的内部变量并在外部执行的话,这种情况就产生了闭包!
闭包的特性
1.函数套函数
2.内部函数可以访问外部函数的内部变量或参数
3:变量或参数不会被垃圾回收机制回收
闭包的优点
1.变量长期扎驻在内存中
2.避免全局变量的污染
3.私有成员的存在
闭包的缺点
1.使用不当会造成内存泄漏
2.常驻内存
3.增大内存使用量
闭包的使用场景
1.封装对象的私有属性和方法
2.函数节流防抖
闭包需要三个条件:
1.函数嵌套函数
2.访问所在的作用域
3.在所在的作用域外被调用
1. 如何产生闭包(closure)
上图代码
// 函数作为返回值
function create() {
const a = 100
return function () {
console.log(a)
}
}
const fn = create()
const a = 200
fn() // 100
// 函数作为参数被传递
function print(fn) {
const a = 200
fn()
}
const a = 100
function fn() {
console.log(a)
}
print(fn) // 100
所有的自由变量的查找,是在函数定义的地方,向上级作用域查找
不是在执行的地方!!!
2. this
5大调用场景:
普通函数、
对象方法、
call apply bind
class
箭头函数
注意:
this取什么值,是在执行时确认的,定义时无法确认
全局下,普通函数fn1执行,相当于window执行了fn1函数,所以this是window
call apply bind可以修改this,
function fn1(this={x:100}){
fn1,call({x:100}) ==> console.log(this)
}
bind也可以修改,但是多了一步执行。
对象方法中的this,指向当前对象(因为当前对象执行了方法)。
setTimeout函数中的this,相当于普通函数中的this,因为setTimeout触发的函数执行,并不是外部对象执行的。
setTimeout中函数是箭头函数,this为当前对象。因为箭头函数中的this始终是父级上下文中的this.
es6 class中的this,当前实例本身。
手写bind:
// 模拟 bind
Function.prototype.bind1 = function () {
// 将参数拆解为数组
const args = Array.prototype.slice.call(arguments)
// 获取 this(数组第一项)
const t = args.shift()
// fn1.bind(...) 中的 fn1
const self = this
// 返回一个函数
return function () {
return self.apply(t, args)
}
}
function fn1(a, b, c) {
console.log('this', this)
console.log(a, b, c)
return 'this is fn1'
}
const fn2 = fn1.bind1({x: 100}, 10, 20, 30)
const res = fn2()
console.log(res)
this总结 (重要)
普通函数中调用,this指向window
对象方法中调用,this指向当前对象
call apply bind中调用, this指向被传入的对象
class中的方法中调用, this指向实例对象
箭头函数,this就是父级上下文中的this