作用域以及递归--js(十四)

95 阅读5分钟

一、变量和函数的预解析

1、预解析: (预解释)

2、变量的规则:也有人说是变量提升

  • JS在运行我们的代码的时候, 会先整体阅读一次我们的 JS 代码,此时读取完毕后, 会将变量的声明(定义)提取到页面的最顶部(JS代码的最顶部)
  • 但是注意: 提升的只有变量的声明, 没有变量的赋值。那么换句话说, 也就是在变量定义前去使用, 得到的是一个undefined
    原本的代码
                console.log(a)
                var a = 100
                console.log(a)

            开始运行代码, 浏览器读取我们JS整体代码

            读取完毕, 预解析 后的代码

                var a
                console.log(a)  // undefined
                a = 100
                console.log(a)  // 100

3、函数的规则:也有人说是函数提升

  • JS 在运行我们的代码的时候, 会先整体阅读一次我们的 JS 代码,此时读取完毕后, 会将声明式定义的函数 提取到页面的最顶部(JS代码的最顶部).所以我们在书写代码的时候, 可以在 声明式定义的函数前, 去调用函数
     *  原本的代码
         *          console.log(a)  // ƒ a () { console.log('我是a函数') }
         *          function a () { console.log('我是a函数') }
         *          console.log(a)  // ƒ a () { console.log('我是a函数') }
         *
         *      浏览器读取我们的JS整体代码, 开始函数提升
         *
         *      提升后的代码:
         *          function a () { console.log('我是a函数') }
         *          console.log(a)
         *          console.log(a)

=========================================================

    原本的代码
                console.log(a)
                var a = function () { console.log('我是a函数') }
                console.log(a)

            开始运行代码, 浏览器读取我们JS整体代码

            读取完毕, 预解析 后的代码

                var a
                console.log(a)  // undefined
                a = function () { console.log('我是a函数') }
                console.log(a)  // ƒ () { console.log('我是a函数') }

二、作用域

  • 简单来说: 就是一个变量生效的范围

1、全局作用域

  • 整个 script 标签内部的区域声明的变量就是在全局作用域创建
  • 如果是在全局作用域创建的变量或者函数我们统称为全局变量或者全局函数,能在当前代码的所有位置去使用
  • JS 在全局作用域中提供了一个 对象, 叫做 window, 我们书写的所有的 全局变量或者全局函数, 都在 window 对象内部存放

2、局部作用域(函数作用域)

  • 在一个函数内部生成的变量就是存在于局部作用域的,在局部作用域创建的变量只能在当前作用域内使用

三、作用域链

  • 每一个作用域上一层会有一个全新的作用域, 每个作用域之间的一个连接, 我们称之为作用域链
  • 如果我们在一个作用域内寻找一个变量, 那么我们会在当前作用域内查找, 如果找到直接使用; 如果没有找到, 那么会继续去上一层作用域继续查找, 找到就使用, 如果没有找到继续去上一层查找;所以我们将这个层层查找的顺序之间的连接, 称之为作用域链
  • 作用域链分为两个规则:
      1. 查找规则
        在一个作用域内查找一个变量, 如果有直接使用, 如果没有会去上一层继续查找, 如果找到直接使用, 没有的话继续去上一层查找;直到找到了全局作用域, 找到了直接使用, 如果没有找到直接报错
        注意: 查找的时候只会层层向上, 不会向下
      1. 赋值规则
        在一个作用域对一个变量进行赋值, 那么会先在当前作用域内查找变量, 找到直接修改, 如果没有, 会去上一层作用域查找;如果找到直接修改, 没有继续向上, 如果找到了全局作用域还是没有, 那么会在全局作用域创建一个变量, 然后对他进行赋值操作
    var a = 100

        function fn() {
            // fn 函数内部会有一个独立的作用域, 也就是局部作用域

            function fn2() {

                console.log(a)   // 100
            
            }
            fn2()

        }

        fn()//100
     var a = 100

        function fn() {

            var a = 200

            function fn2() {

                console.log(a)  // 200
            
            }
            fn2()

        }

        fn()//200
     function fn() {

            function fn2() {
                a = 'QF001'
            }
            fn2()
        }

        fn()

        console.log(a)   // QF001
    function fn() {
            function fn2() {
                var a = 'QF001'
            }
            fn2()
        }
        fn()
        console.log(a)// 报错:a is not defined

四、递归函数

  • 在编程中就是指 自己调用自己的一种手段;递归函数就是在一个函数内部调用了自身. 循环执行
  • 递归函数有点类似于循环:也需要有初始化, 自增, 执行的代码, 判断条件;如果上述的内容缺少, 那么就是一个死递归, 永远不会结束

1、求 1~5 的所有数字相加的和

    /**
         *  求 1~5 的所有数字相加的和
         * 
         *  1 + 2 === 3
         *  3 + 3 === 6
         *  6 + 4 === 10
         *  10 + 5 === 15
        */

        function fn(n) {
            // 1. 先书写结束条件
            if (n === 5) {
                return 5
            }


            /**
             *  2. 开始递归
             * 
             *      假设我们的 fn 函数能够帮我们计算 某一个数字到5的所有数字相加的和
             * 
             *      1~5 fn(1)
             *      2~5 fn(2)
             *      3~5 fn(3)
             *      4~5 fn(4)
             *      5~5 fn(5)
             * 
             * 
             *      目前是要计算 1~5的所有数字相加
             *          所以等式可以理解为    1 + 2~5
             *                              1 + fn(2)
            */

            return n * fn(n + 1)
            
        }

        var res = fn(1)
        console.log(res)

2、斐波那契数列

     /**
         *  斐波那契数列是一个特殊的数列
         * 
         *      该数列中, 前两位的数字固定为 1, 从第三位开始, 每个位置上的数字是前两位的和
         * 
         *      数列:       1,1,2,3,5,8,13,21,34,55,89
         * 
         *  要求: 封装一个函数, 能够计算出斐波那契数列中某一个位置的具体数值
         * 
         *      请使用递归函数解决
        */
        function fn(n) {
            let arr = []
            arr[0] = 1
            arr[1] = 1
            for (let i = 2; i <= n; i++) {
                arr[i] = arr[i - 1] + arr[i - 2]
            }
            return arr[n - 1]
        }
        let res = fn(6)
        console.log(res)