美文网首页前端学习指南javascript 知识点饥人谷技术博客
JS函数简介(二)----函数作用域、函数作用域链、函数的递归

JS函数简介(二)----函数作用域、函数作用域链、函数的递归

作者: 大春春 | 来源:发表于2017-01-09 23:38 被阅读113次

    一、函数的作用域

    首先,作用域就是指变量的作用范围
    然后,在JS中只有两个作用域:1.全局作用域,2.局部作用域(函数作用域)

    • 全局作用域

      • 简介:
        全局作用域就是函数作用域外的作用域,处于window对象之中;
      • 全局变量:
        1.全局变量是指不在函数内部创建的变量,全局变量都处于window对象之中,如下变量就是在一个全局变量:


        全局变量

        2.另外,在函数内部创建变量时,如果不加var进行声明,那么这个变量也是全局变量,


        不加var声明的变量都是全局变量
    • 局部作用域(函数作用域)

      • 简介:
        局部作用域是指在创建了函数后,在函数内部形成的作用域;
      • 局部变量:
        1.局部变量是指在函数内部通过var进行声明的变量,如下变量就是一个局部变量:


        局部变量
    • 全局变量和局部变量的调用

      • 在函数中,如果函数需要传入一个变量,而这个变量并不在它自身内部,那么就可以调用全局下的变量:


        函数调用全局变量
      • 全局作用域下不能调用函数内的局部变量


        提示错误变量a没有声明
      • 那么如何在全局作用域下对局部变量进行调用呢?有两个办法:1、函数return这个变量再赋值;2、使用闭包;
        1.函数return这个变量,再将return的值赋值给一个全局变量:


        把变量return后赋值

        2.使用闭包,在函数内部再创建一个函数,返回这个函数:


        使用闭包
    • 关于关键词var的两点
      • 在全局作用域下的函数中不加var对变量进行声明时,就是全局变量:


        不加var进行声明的变量都是全局变量
      • 在同一个作用域内,当一个变量已经被声明并被赋值,后面再次对其进行声明,该变量的值不变:


        重复声明值不变

    二、关于函数的作用域链

    • 简介
      1.函数的作用域链就是指函数在调用变量时所经过的路径,比如函数fn调用变量a,但是它自身并没有变量a(没有在函数内部用var进行声明),于是就从全局作用域下找变量a,找到就调用全局变量a,那么这个过程就是函数fn的作用域链;
      2.要了解函数作用域链,首先就要知道在函数对象中,拥有一个内部属性[[Scope]],该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问。
      3.简单来说:函数对变量的调用是由自身开始向外一层一层找的,距离自身最近变量被找到,就调用该变量;

    • 画出函数的作用域链
      1.代码如下:


      2.首先因为变量提升和声明前置,我们将代码修改成下面这样:
      变量提升和声明前置
      3.第一步找到全局作用域下,发现有全局变量i和全局变量fn,然后全局变量fn变成了一个函数,于是可以写出如下伪代码:

      全局作用域下
      4.找到函数fn作用域下,发现有局部变量i和函数fn2,但是因为没有执行,所以这两项并未被创建,又因为函数fn处于全局作用域下,所以它也可以对全局作用域下的变量进行调用,所以fn的[[Scope]]包含全局作用域globalScope

      fn作用域下
      5.然后在函数fn中有一个函数fn2,发现它里面没有自身的局部变量,但是因为fn2是在函数fn内被声明,所以fn2的[[Scope]]包含fn的作用域fnScope,并且fn2也可以对全局作用域下的变量进行调用,所以也包含全局作用域globalScope(全局作用域);
      fn2作用域下
      6.执行函数fn,进入了fn的执行上下文中fn execution context,此时声明了变量i以及函数fn2,i此时未被赋值,所以是i的值是undefined:


      7.因为i的值是undefined,所以console.log(i)得到的就是undefined,所以执行fn得到的第一个结果就是undefined,然后将99赋值给了i,i变为99


      8.然后执行fn2,进入到fn2的执行上下文fn2 execution context,fn2将100赋值给i,但是因为它自身没有变量i,于是先到上一层,也就是函数fn中找变量i,得到fn中的i后进行赋值,函数fn中的i变为了100,所以下面的console.log(i)得到的值就是100,函数fn执行的第二个结果就是100;


      9.执行完函数fn后,进入到全局作用域的执行上下文global execution context中,将10赋值给全局变量i,20赋值给全局变量fn,然后因为下面的console.log(i)是在全局作用域下执行,所以这里的i是全局变量的i,得到最后一个结果10;


      10.所以这段代码的执行结果依次为undefined、100、10,而以上这个一层一层向上找变量的过程就是作用域链;
      结果

    三、函数递归

    • 什么是递归
      递归简单说来就是不断地重复执行同样的代码来解决问题
    • 函数的递归
      1.特点:
      ①:自己调用自己;
      ②:要设定终止条件;
      2.优缺点
      ①:算法简单;
      ②:效率低;
    • 一个使用递归的简单例子,求n的阶乘n!
      比如求5的阶乘就是5! = 5*4*3*2*1
      由此可知,n的阶乘就是n! = n*(n-1)*(n-2)....
      (n-2) = (n - 1) - 1
      由此可知代码如下:
      求阶乘
      输出结果:

    相关文章

      网友评论

        本文标题:JS函数简介(二)----函数作用域、函数作用域链、函数的递归

        本文链接:https://www.haomeiwen.com/subject/iehhbttx.html