js中函数的定义与创建以及闭包

97 阅读4分钟

函数

函数的定义与创造

定义:

在堆内存中开一个空间,将函数体内的代码,保存到堆内存中,将堆内存的地址保存变量名(函数名),最后将这个变量名存储到栈内存中

调用:

根据变量名(函数名)中的地址找到对应的函数,

然后再调用栈中开一个新的空间(函数的执行空间),

在执行空间中 对函数的形参进行赋值,

在执行空间中 进行变量的预解析,

在执行空间中 执行函数的代码,

销毁当前函数的执行空间.

创建:

声明式定义

语法:function 变量名 (参数){'需要运行的代码'}

//利用声明式创建函数
function fn() {
console.log('我是利用声明式定义的')
}

//调用函数
fn()

赋值式定义

语法: let 变量名 = function (参数) {'需要运行的代码'}

//利用赋值式创建函数
let fn = function () {console.log('我是利用赋值式创建的')}

//调用函数
fn()

永不销毁的执行空间

什么是永不销毁的执行空间(如何创建一个永不销毁的执行空间)

1.正常书写一个函数

2.在这个函数内 向外返回一个引用数据类型

3.当满足上述条件时,这个函数的执行空间将不会被销毁

        function fn(){
            const obj = {
                name:'fn函数的name',
                age:'不知道'
            }
            return obj
        } 
        const newObj = fn()
        console.log(newObj)
        
        //将newObj 的值修改后就与函数内部的对象切断联系,那么这个函数的执行空间就会被销毁
        
        //newObj = null

闭包

什么是闭包

闭包是指有权访问外层函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建一个内层函数,通过内层函数访问外层函数的局部变量,利用闭包可以突破作用链域

闭包的特性:

函数内再嵌套函数

内部函数可以引用外层的参数和变量

函数的执行空间不会被销毁

如何创建一个闭包

创建闭包的最常见的方式就是在一个函数内创建一个内层函数,通过内层函数访问外层函数的局部变量

function outer(){

        let a = 100
        let obj = {
            name:'outer函数',
            age:'随意'
        }
            function inner(){
                console.log(a)
                console.log(obj)
            }
            //返回一个函数
            return inner
        } 
        const newFn = outer()
        console.log(newFn)//得到一个函数(inner)
        newFn()

闭包的优点:

1.可以避免全局污染

2.可以读取函数内部的变量,并将这些变量保存到内存中

闭包的缺点:

加大内存的使用,可能会造成内存泄漏

解决办法:

在退出函数之前,将不使用的变量删除.

案例

       function fun(n, o) {
            console.log(o);

            const obj = {
                fun: function (m) {
                    return fun(m, n);
                },
            };

            return obj;
        }

        var a = fun(0); // undefined
        a.fun(1);   // 0
        a.fun(2);   // 0
        a.fun(3);   // 0

解题思路

    /**
     *  var a = fun(0)
     *      调用全局函数 fun (QF001), 并传递了一个实参 0,   所以对应的两个形参 n === 0; o === undefined
     * 
     *          函数内部代码开始执行
     *              1. console.log(o)    undefined
     *              2. 创建一个 对象 obj, 内部有一个属性名为 fun 值为一个函数
     *              3. 将这个 对象 obj 返回到函数外边   (变量 a 接受了 这个 对象, 所以 将来 变量a 可以调用内部的 fun)
     *  
     *  a.fun(1)
     *      调用的是 对象 obj 内部的 fun (QF999) 函数, 并传递了一个 实参 1, 所以对应的一个形参 m === 1
     *          开始执行函数内部代码
     *              return fun(m, n)    注意!!! 这个函数是全局函数 fun(QF001). 如果想要调用对象内部的 应该是  对象.属性名()
     *                  并传递了两个实参
     *                      m === 1
     *                      n === 0     (函数QF999 的作用域中没有, 所以需要去上一层作用域查找, 也就是 函数QF001, 在这个函数中找到了一个形参n, 它的值为0)
     *                  函数开始执行时就会执行一句 console.log(o)   我们传递的是数字 0
     *  
     *  a.fun(2)
     *      调用的是 对象 obj 内部的 fun(QF999), 并传递一个 实参 2, 所以对应的一个形参 m === 2
     *          开始执行函数内部代码
     *              return fun(m, n)    传递的两个实参  m === 2;    n === 0     (n 怎么来的参考 45行注释)
     *              函数开始执行: console.log(o)    我们传递的是数字 0
     *  
     *  a.fun(3)
     *      调用的是 对象 obj 内部的 fun(QF999), 并传递一个 实参 3, 所以对应的一个形参 m === 3
     *          开始执行函数内部代码
     *              return fun(m, n)    传递的两个实参 m === 3;     n === 0     (n 怎么来的参考 45行注释)
     *              函数开始执行: console.log(o)    我们传递的是数字 0
    */