闭包

什么是闭包

当一个函数的返回值是另一个函数,而返回的函数如果调用了父函数的内部变量并在外部执行的话,这种情况就产生了闭包!

闭包的特性

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
posted @ 2020-10-13 09:03  林9九  阅读(96)  评论(0编辑  收藏  举报