JavaScript函数进阶及作用域

Posted 橘猫吃不胖~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript函数进阶及作用域相关的知识,希望对你有一定的参考价值。

1 函数表达式

函数表达式:是将声明的函数赋值给一个变量,通过变量完成函数的调用和参数的传递,函数表达式的定义必须在调用前。

示例:

var sum = function (num1, num2) // 函数表达式
    return num1 + num2;
;
console.log(sum(1, 2));// 调用函数

结果是:3

2 回调函数

回调函数:指的就是一个函数A作为参数传递给一个函数B,然后在B的函数体内调用函数A。此时,称函数A为回调函数。

示例:

function cal(num1, num2, fn) 
    return fn(num1, num2);

var s1 = cal(45, 55, function (a, b) 
    return a + b;
)
console.log(s1);

结果为:
100

程序运行思想如下:

1、从console.log(s1);开始,函数要输出s1的值
2、s1调用cal,并给cal函数传入了3个值,分别是45,55,function(a,b)
3、45传给了num1,55传给了num2,function(a,b)传给了fn
4、在cal函数中,返回值重新返回了fn,并将给cal函数传入的num1=45,num2=55传给了fn(num1,num2),得到function(45,55)
5、回到s1的计算中,此时的s1为cal(45, 55, function (45,55)),返回a+b的值即45+55的值,赋值给s1
6、最后得出结果s1的值为100

3 递归调用

递归调用:指的是一个函数在其函数体内调用自身的过程,这种函数称为递归函数。

用递归解决问题条件:
1、问题可以分解,分解后得到的新问题的解法与原问题的解法相同
2、分解的过程要有明确的结束条件

递归的过程:
1、自上而下分解问题:以计算5!为例
5!–>54!
4! -->4
3!
3!–>32!
2!–>2
1!
2、自下而上回溯得到问题的解
1!–>2!–>3!–>4!–>5!

示例:使用递归求1+2+3+…+100的值

function getSum(n) 
    if (n == 1) 
        return 1;
     else 
        return n + getSum(n - 1);
    

console.log(getSum(100))

结果是:5050

该程序的思想为:

1、定义一个函数,参数值为n,n为要求的前n项的和的数字,这里将传入100
2、当n等于100时,即getSum(100),返回值为100加getSum(99),getSum(99)为99加getSum(98),…,依次类推
3、当递归到3+getSum(2)时,getSum(2)为2加getSum(1),当n为1时,返回值为1,即getSum(2)为2+1,getSum(3)为3+2,…,getSum(100)为100+99
4、最后整个函数就实现了100+99+98+……+1的效果

4 作用域

变量需要在它的作用范围内才可以被使用,这个作用范围称为变量的作用域, JavaScript根据作用域使用范围的不同,划分如下:
全局变量(全局作用域):不在任何函数内声明的(在函数外部定义的)变量(显式定义)或在函数内省略var声明的变量(隐式定义)都称为全局变量。全局变量在浏览器页面没有关闭之前一直占用内存空间,比较耗费内存,在浏览器页面关闭时才释放内存。

例如:直接在函数外部定义

var i = 0;//显式定义

或者在函数内部不加var定义:

function fun() 
    i = 0;//隐式定义

局部变量(局部作用域):在函数体内利用var关键字定义的变量称为局部变量。局部变量只在函数内部起作用,函数调用结束后,局部变量所占的内存就会被释放。

例如,在函数内部定义:

function fun() 
    var i = 0;//在函数内部定义

块级变量:ES6提供的let关键字声明的变量称为块级变量

示例:

for (let i = 0; i < 100; i++) 
    //函数体代码

全局变量和局部变量两者的区别:
1、在全局作用域下,添加或省略var关键字都可以声明全局变量,全局变量在浏览器关闭页面的时候才会销毁,比较占用内存资源
2、在函数中,添加var关键字声明的变量是局部变量,省略var关键字时,如果变量在当前作用域下不存在,会自动向上级作用域查找变量。局部变量在函数执行完成后就会销毁,比较节约内存资源

作用域链:当在一个函数内部声明另一个函数时,内层函数只能在外层函数作用域内执行,在内层函数执行的过程中,若需要引入某个变量,首先会在当前作用域中寻找,若未找到,则继续向上一层级的作用域中寻找,直到全局作用域,称这种链式的查询关系为作用域链。

5 闭包函数

5.1 什么是闭包函数

所谓“闭包”指的就是有权访问另一函数作用域内变量(局部变量)的函数。主要的两点用途如下:
1、可以在函数外部读取函数内部的变量
2、可以让变量的值始终保持在内存中

注意:由于闭包会使得函数中的变量一直被保存在内存中,内存消耗很大,所以闭包的滥用可能会降低程序的处理速度,造成内存消耗等问题。

5.2 闭包函数的实现

闭包的常见创建方式就是在一个函数内部创建另一个函数,通过另一个函数访问这个函数的局部变量,可以在函数外部读取函数内部的变量。

示例:

function fn() 
    var times = 0;
    var c = function ()  return ++times; ;
    return c;

var count = fn(); // 保存fn()返回的函数,count就是一个闭包
console.log(count());	// 输出结果:1
console.log(count());	// 输出结果:2
console.log(count());	// 输出结果:3  

6 预解析

JavaScript解析器在运行JavaScript代码的时候会进行预解析,也就是提前对代码中的var变量声明和function函数声明进行解析,然后再去执行其他的代码。

把变量的声明提升到当前作用域的最前面,只会提升声明,不会提升赋值。把函数的声明提升到当前作用域的最前面,只会提升声明,不会提升调用。

先后规则:先提升 var,在提升functi

例如:

console.log(num);// 输出结果:undefined
var num = 10;
console.log(num2);// 报错,提示num2 is not defined

这段代码会先将var进行预解析,就是:

var num ;
 // undefined
console.log(num) ;
num  = 10;

例如:

var a = 25;
function abc() 
    console.log(a);
    var a = 10;

abc();//结果为:undefined

预解析结果:

var a;// 在全局作用域里提升变量
function abc() // 在全局作用域里提升函数
    var a;// 在局部作用域里提升变量
    console.log(a);// a 的值是 undefined
    a = 10;// 在局部作用域里给变量赋值

a = 25;// 给变量赋值
abc();// 调用函数

以上是关于JavaScript函数进阶及作用域的主要内容,如果未能解决你的问题,请参考以下文章

JS 作用域及作用域链

JS 作用域及作用域链

JavaScript 精粹 基础 进阶函数和作用域(函数this)

JavaScript 开发进阶:理解 JavaScript 作用域和作用域链

JavaScript 精粹 基础 进阶函数和作用域(闭包作用域)

JavaScript 开发进阶:理解 JavaScript 作用域和作用域链