浅显易懂的 JavaScript 函数

1、两种创建方式

在 JavaScript 中函数的写法和 python 很相似,因为不用提前声明类型,所以也就没有返回值这一说法。下面演示最常用的一种写法

/* 先来看一下函数的结构:
function 函数名(参数1, 参数2 ... , 参数n){
    函数体
    return 返回值;
}

我们来观察一下 JavaScript 中函数的特点:
1、声明的时候没有说明返回值类型
2、参数列表中每一个参数也没有指明类型(多个参数使用 , 隔开)
3、所有的函数开头均以 function 开头
4、返回值使用 return */

//现在我们按照上面的格式,实现一个功能:判断输入的字符是数字还是字母
function judge(variable) {
    
    
    if (variable >= "0" && variable <= "9") {
    
    
        return variable + " 这是一个数字";
    } else if (variable >= "a" && variable <= "z") {
    
    
        return variable + " 这是一个小写字母"
    } else if (variable >= "A" && variable <= "Z") {
    
    
        return variable + " 这是一个大写字母";
    } else {
    
    
        return variable + " 这不是数字,也不是字母";
    }
}

console.log(judge(1));
console.log(judge('a'));
console.log(judge('G'));
console.log(judge('@'));

控制台输出结果:

18



上边的写法其实还是很容易接受的,下面介绍另一种写法

/* 格式:
var 函数名 = function(参数1, 参数2 ... , 参数n){
    函数体
    return 返回值;
} 

解释一下为什么可以这么写:首先在 JavaScript 中函数也是一个对象,那么当然可以通过变量赋值的形式创建,我们简化一下可以看成 var 变量名 = 值,这里值就是函数体
*/

//我们将上边的例子改写成第二种形式:
var judge = function(variable){
    
    
    if (variable >= "0" && variable <= "9") {
    
    
        return variable + " 这是一个数字";
    } else if (variable >= "a" && variable <= "z") {
    
    
        return variable + " 这是一个小写字母"
    } else if (variable >= "A" && variable <= "Z") {
    
    
        return variable + " 这是一个大写字母";
    } else {
    
    
        return variable + " 这不是数字,也不是字母";
    }
}


2、函数参数

本小节我们会介绍 JavaScript 函数参数相关知识点,当然我并不会讲那些大家都知道的东西,我所讲的都是 JavaScript 特有的东西

先来了解一个关键字 arguments,中文翻译就是 参数(s),它永远指向当前函数的调用者传入的所有参数,请注意,一定是传入的参数。arguments 的存储方式类似数组,但切记,它并不是一个Array!

//我们先随便写一个例子,看看 arguments 的用法
function setArray(variable) {
    
    
    var array = [];
    //arguments.length 实际上就是传入参数的个数
    for (let i = 0; i < arguments.length; i++) {
    
    
        //获取的方式也和 Array 相似,可以通过下标访问
        array[i] = arguments[i];
    }
    return array;
}

let arguments = setArray(10, 20, 30, 40, 50);
console.log(arguments);

控制台输出结果:

19


可以看到仅有 一个参数 列表的函数也可以接收 n 个参数,这就是 arguments 的力量。但是有一个缺点——重复保存参数

举个例子:假如现在有一个 function(value_1, value_2, value_3),而我传递了 5 个参数,分别是 a、b、c、d、e

value_1 对应 a;value_2 对应 b;value_3 对应 c;arguments 对应 a、b、c、d、e,这不就重复了嘛,如果存在一个关键字能够只保存 d 和 e 就好了!


为此 ES6 提供了一个新特性,引入 rest 关键字,用来保存多余的函数参数

/* 使用 rest 格式(这里使用最常用的函数写法):
function(参数1, 参数2, ...rest) {
    函数体
    return 返回值;
} 

需要注意,rest 只能写在参数列表的最后边 */

function setArrayWithRest(variable, ...rest) {
    
    
    var array = [];
    for (let i = 0; i < rest.length; i++) {
    
    
        array[i] = rest[i];
    }
    return array;
}

var rest = setArrayWithRest(10, 20, 30, 40, 50);
//直接转换成字符串输出
console.log(rest);

这样看不够清楚,下面展示一下 IDEA 的截图(分别使用 arguments 和 rest):

20


浏览器控制台输出:

21



3、变量那些事儿

3.1、变量作用域

函数还有一点需要我们格外注意,那就是变量的作用域,如果你自己写的代码和别人起冲突,那有可能就是变量冲突。但是不用担心,看完我的讲解,你一定会有所收获(哎就是这么自信)

之前我们的变量都是采用 var 声明,所以我们先来聊聊 var 的作用域

//首先先看下面两句 console.log(variable_1) 那一句会执行?
function func1() {
    
    
    var variable_1 = "I'm variable_1, in func1";
    console.log(variable_1);					//语句 1
}

func1();
console.log(variable_1);						//语句 2

运行结果(你猜对了嘛):

22


很明显,语句 1 成功执行,但是函数体外显示 variable_1 未定义,说明 variable_1 只有在函数体内才有用,那我们先得出一个结论(慢慢验证,不要急):使用 var 声明的变量在函数体外无法使用



好,接下来我们继续看例子:

function func1() {
    
    
    var variable_1 = "I'm variable_1, in func1";
    
    //函数 func1() 内写 func2()
    function func2() {
    
    
        console.log(variable_1);					//语句 1
    }
    
    //下面这两句代码都会成功嘛?
    console.log(variable_1);						//语句 2
    func2();
}

func1();

运行结果:

23


可以看到都执行成功了,说明 variable_1 在 func2() 内也起作用,我们得出第二个结论:使用 var 声明的变量,无论是当前函数自身,还是其内部函数,都可以使用



继续,我们离真相很接近了:
function func1() {
    
    
    
    function func2() {
    
    
        //现在我们在 func2 内部定义变量
        var variable_2 = "I'm variable_2, in func2";
        console.log(variable_2);						//语句 1
    }

    //下面这两句代码都会成功嘛?
    func2();
    console.log(variable_2);							//语句 2
}

func1();

运行结果:

24


语句 1 正常输出,语句 2 报错,所以 variable_2 无法在 func1() 内使用,只能在 func2() 中使用,我们得出第三个结论:使用 var 声明的变量无法在外层函数使用

综上所述,我们得出结论:使用 var 声明的变量无法在函数体外使用,在函数体内无论在哪都可以使用。例如 for (var a = 0; a < 10; a++),这里面的 a 只要是在当前函数体内,可以随便用!那有些人可能好奇,如果使用 var 修饰的变量出现在函数体外,那怎么办?我们可以把一整个文件看成一个函数(假设),按照原则,这个变量可以在文件内任意地方使用,即 全局变量


很明显,使用 var 容易引起变量冲突。所以 ES6 新增了两个修饰变量的关键字:let 和 const


ES6 新增的关键字 let,以及它的作用域

这里由于篇幅原因(因为还有其他知识点需要写,长了你们又不爱看),所以我简略一点

在 ES6 之前,是没有 块作用域(就是用 {} 包起来的代码块)的概念的。ES6 之后我们可以使用 let 声明变量,这种变量只能在当前代码块内使用,即 {} 外无法访问

function func3() {
    
    
    for (let i = 0; i < 10; i++) {
    
    
        let variable_3 = 10;
    }

    //这回能成功输出吗?按照 let 的定义,应该是不可以的
    console.log("variable_3 = " + variable_3);
}

func3();

运行结果(确实是不可以输出 variable_3 的值,毕竟它的作用域仅在 for 语句内):

25


几点推导的知识点:

  • 使用 let 声明的变量如果出现在 函数体外(直接写在非函数或代码块区域),那么它还是一个 全局变量
  • 使用 let 声明的变量如果出现在 函数开头,那么该变量的作用范围就是整个函数
  • 使用 let 修饰的变量不属于 window 变量。这点先看看吧,我们还没提到什么是 window 对象呢,这里剧透一下,window 对象是 JavaScript 的一个全局对象


ES6 新增的关键字 const,以及它的作用域

在其他编程语言中,const 用于修饰常量,在 JavaScript 中也不例外。ES6 之前定义常量有一个不成文规定 —— 全部用大写字母表示的变量就是常量(明显会出问题)。自 ES6 后,我们可以使用 const 声明常量(即不能改变的值),具体用法如下:

function func4() {
    
    
    const variable_4 = 100;
    console.log("variable_4 = " + variable_4);					//语句 1

    //尝试改变常量的值,编译都无法通过
    variable_4 = 200;
    console.log("改变 variable_4 的值:" + variable_4);			 //语句 2
}

func4();

运行结果(提示 Assigment to constant variable 错误):

26


上边介绍了 var、let、const 三种声明变量的方式,也详谈了它们的作用域,下面我们来看一下 在 JavaScript 中其它有关函数变量的知识点:



3.2、同名变量的处理机制

//我们还是先看例子,并观察执行结果

function func5() {
    
    
    //学习了 let,我们之后尽量都用它
    let variable_5 = "outer variable";

    function func6() {
    
    
        //和外部函数相同名称的变量
        let variable_5 = "inner variable";
        console.log("func6 输出:" + variable_5);					//语句 1
    }

    func6();
    console.log("func5 输出:" + variable_5);						//语句 2
}

func5();

这回我们先分析语句 2 可能的输出结果:根据 let 的作用域规则,func6() 内部的变量一定无法在 func5() 中使用,所以语句 2 不可能输出 “inner variable”,那就只可能输出 “outer variable”;对于语句 1,确实两个值都符合规定,但如果我们是编译器,是不是会选择“近一点”的,所以可能会选择 “inner variable”,下面看运行结果:

27


确实和我们分析的一样,所以我们总结一下同名变量的处理机制(很简单):

  • 当内部函数和外部函数拥有相同名称的变量时,内部函数优先使用内部变量
  • 外部函数由于变量作用域的问题,无法访问内部函数的变量,所以只能使用属于自己的变量


3.3、变量提升

也许前面的结论你都能从其他编程语言中推导得出,但是对于变量提升,你应该是第一次听说。JavaScript 的函数定义有个特点,它会先扫描整个函数体的语句,把所有 **var 申明的变量 **“提升” 到函数顶部(看例子看例子)

function func7() {
    
    
    'use strict';
    var variable_6 = "Hello ";
    //使用到了未定义的变量
    console.log(variable_6 + variable_7);					//语句 1
    var variable_7 = "world!";
    console.log(variable_6 + variable_7);					//语句 2
}

//请问语句 1 会报错吗?
func7();

运行结果:

28


结果分析:即使我们开启了严格检查模式,代码依旧可以通过编译,而且正常输出,这是因为 variable_7 虽然在函数体末尾被声明,但是根据变量提升原则,在执行 func7() 时,会首先把所有的变量声明提到顶部,这样相当于 variable7 被声明了,但是没有赋值,所有才会显示 undefined

但是请注意,根据我的测试,变量提升对 let 和 const 声明的变量无效,所以为了正常使用,我推荐无论是使用 var 还是 let,变量的声明都放在函数顶部,防止给自己添麻烦!

猜你喜欢

转载自blog.csdn.net/qq_52174675/article/details/122636391