搜索
您的当前位置:首页正文

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

来源:哗拓教育

一、函数的作用域

首先,作用域就是指变量的作用范围
然后,在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
    由此可知代码如下:
    求阶乘
    输出结果:
Top