一、函数的作用域
首先,作用域就是指变量的作用范围
然后,在JS中只有两个作用域:1.全局作用域,2.局部作用域(函数作用域)
-
全局作用域
- 简介:
全局作用域就是函数作用域外的作用域,处于window对象之中; -
全局变量:
1.全局变量是指不在函数内部创建的变量,全局变量都处于window对象之中,如下变量就是在一个全局变量:
2.另外,在函数内部创建变量时,如果不加var进行声明,那么这个变量也是全局变量,
- 简介:
-
局部作用域(函数作用域)
- 简介:
局部作用域是指在创建了函数后,在函数内部形成的作用域; -
局部变量:
1.局部变量是指在函数内部通过var进行声明的变量,如下变量就是一个局部变量:
- 简介:
-
全局变量和局部变量的调用
-
在函数中,如果函数需要传入一个变量,而这个变量并不在它自身内部,那么就可以调用全局下的变量:
-
全局作用域下不能调用函数内的局部变量
-
那么如何在全局作用域下对局部变量进行调用呢?有两个办法:1、函数return这个变量再赋值;2、使用闭包;
1.函数return这个变量,再将return的值赋值给一个全局变量:
2.使用闭包,在函数内部再创建一个函数,返回这个函数:
-
- 关于关键词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
:
5.然后在函数fn中有一个函数fn2,发现它里面没有自身的局部变量,但是因为fn2是在函数fn内被声明,所以fn2的[[Scope]]
包含fn的作用域fnScope
,并且fn2也可以对全局作用域下的变量进行调用,所以也包含全局作用域globalScope(全局作用域)
;
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
由此可知代码如下:
输出结果: