【JavaScript学习|黑马2023课程】js基础day04——函数入门、作用域、匿名函数、布尔逻辑、布尔转换

1.1 函数的概念

函数是一个被命名为执行特定任务的代码块。它可以将一段代码组织起来,使其可以多次使用,而不必重复编写相同的代码。

为什么需要函数

  1. 代码复用性:通过将重复的代码逻辑封装在函数中,可以避免代码的冗余。当我们需要在多个地方执行相同的操作时,只需要调用该函数即可,而不需要重新编写相同的代码。
  2. 提高代码的可读性和可维护性:通过将代码逻辑封装在函数中,并为其赋予有意义的名称,可以使代码更加易于理解和维护。当其他开发者阅读代码时,可以通过函数名快速了解其功能,而不需要深入研究具体的实现细节。
  3. 模块化编程:函数可以作为代码模块的基本单元,通过将相关的函数组织在一起,可以形成具有特定功能的代码模块。这种模块化编程的方式有利于代码的模块化和组件化,提高代码的复用性和可维护性。

1.2 函数使用

1.2.1 函数定义

在JavaScript中,函数使用 function 关键字进行定义,后跟函数名和括号 (),函数体则在大括号 {} 内。

function 函数名() {  
    // 函数体  
}

例如,下面定义了一个名为 sayHi 的函数,它会在被调用时向文档写入 ‘hai~~’。

function sayHi() {  
    document.write('hai~~');  
}
1.2.2 函数命名规范
  • 推荐使用小驼峰式命名法(lowerCamelCase)。
  • 函数名前缀通常为动词,以清晰表达函数的功能。
  • 常用动词如 getsetload 等,有助于理解函数作用。
1.2.3 函数调用

函数在被定义后,必须被调用才会执行其中的代码。调用函数时,只需要写出函数名,后跟括号 ()

例如,上面定义的 sayHi 函数可以通过以下方式调用:

sayHi();
1.2.4 函数体

函数体是函数的主体部分,其中包含了实现函数功能的代码。只有当函数被调用时,这些代码才会被执行。所有的功能代码都应该写在函数体内。

1.3 函数传参

1.3.1 参数传递的重要性

当函数需要完成某些功能,而这些功能依赖于外部提供的数据时,就需要使用参数。参数使得函数更加灵活,能够适应不同的场景和需求。

1.3.2 声明语法

在函数名后的括号中可以声明参数,多个参数之间用逗号隔开。

function 函数名(参数列表) {  
    函数体  
}

例如,下面的函数 getSum 用于计算两个数的和,它接受两个参数 num1num2

function getSum(num1, num2) {  
    document.write(num1 + num42);  
}
1.3.3 调用语法

调用函数时,需要传入与参数列表对应的实际参数。实际参数的个数和顺序应与形参一致。

例如,调用上面定义的 getSum 函数:

getSum(10, 20);  // 输出 30
1.3.4 形参与实参的理解
  • 形参(Formal Parameters):在函数声明时定义的参数,它们是函数内部的局部变量,用于接收调用者传递的数据。
  • 实参(Actual Parameters):在函数调用时传递给函数的实际值,这些值被赋给函数内部的形参。

可以把形参理解为函数内部的变量声明,而实参则是给这些变量赋值。在开发过程中,为了保证数据的正确传递和处理,通常应确保形参和实参的个数一致。

1.3.5 参数默认值

在JavaScript中,如果函数的形参没有被赋予实参值,那么这个形参的值默认是 undefined。在某些情况下,这可能会导致不可预期的结果,比如在执行数学运算时。为了解决这个问题,我们可以给形参设置默认值。

①设置默认值的方法

在声明函数时,可以直接给形参赋值,这个值就是这个形参的默认值。如果调用函数时没有为这个形参传递实参,那么它就会使用这个默认值。

例如:

function getSum(x = 0, y = 0) {  
    document.write(x + y);  
}

在这个例子中,xy 的默认值都是 0。所以,如果我们调用 getSum(),没有传递任何实参,那么就会输出 0。如果传递了实参,比如 getSum(1, 2),那么就会输出 3

②默认值的作用时机

需要注意的是,默认值只会在缺少实参传递时才会被执行。也就是说,如果有实参传递,那么就会优先执行传递过来的实参,否则才会使用默认值。

案例:求学生总分

现在有一个需求:学生的分数是一个数组,我们需要计算每个学生的总分。这个需求可以通过函数封装来实现。我们可以定义一个函数 getArraySum,它接受一个数组作为参数,然后计算这个数组中所有元素的和。如果调用这个函数时没有传递数组,那么就使用一个空数组作为默认值。

例如:

let a = [1, 2, 3, 4, 6];  
  
function getArraySum(arr = []) {  
    let sum = 0;  
    for (let i = 0; i < arr.length; i++) {  
        sum += arr[i];  
    }  
    alert(sum);  
}  
  
getArraySum(a); // 输出 16  
getArraySum([10, 20, 30]); // 输出 60  
getArraySum(); // 输出 0

1.4 函数返回值

1.4.1 返回值的概念

在JavaScript中,函数可以返回一个值。这个值可以是任何数据类型,比如数字、字符串、对象等。当函数执行到 return 语句时,它会立即停止执行,并将 return 后面的值返回给调用者。

1.4.2 使用 return 关键字

要使用返回值,需要在函数体内使用 return 关键字,后跟要返回的值。

例如:

function getSum(num1, num2) {
    return num1 + num2;
}

在这个例子中,getSum 函数会返回两个参数的和。

1.4.3 接收返回值

当调用一个有返回值的函数时,需要用一个变量来接收返回的值。例如:

let result = getSum(1, 2); // result 的值为 3

return 关键字的作用

return 关键字不仅会返回一个值,还会立即结束当前函数的执行。所以,return 后面的代码不会被执行。为了避免错误,建议不要将 return 后面的数据换行写。

1.4.4 默认返回值

如果一个函数没有 return 语句,或者 return 后面没有跟任何值,那么这个函数的默认返回值是 undefined

函数补充:

①函数覆盖

在JavaScript中,如果你声明了两个相同的函数,后面的函数会覆盖前面的函数。这意味着,如果两个函数具有相同的名称,那么调用该函数时将执行最后声明的那个。

②参数数量不一致

在JavaScript中,实参的个数和形参的个数可以不一致。这种情况下,函数仍然可以正常工作,但需要注意以下几点:

形参过多

如果形参过多,即函数声明时的参数数量大于调用时传递的实参数量,那么缺失的参数值将是 undefined。例如:

function example(a, b, c) {
  console.log(a, b, c);
}
example(1, 2); // 输出:1 2 undefined
实参过多

如果实参过多,即调用函数时传递的参数数量大于函数声明时的参数数量,那么多余的实参将被忽略。不过,需要注意的是,函数内部有一个名为 arguments 的对象,它包含了所有传递给函数的实参。例如:

function example(a, b) {
  console.log(a, b, arguments[2]);
}
example(1, 2, 3); // 输出:1 2 3

③使用 return 结束函数

一旦函数执行到 return 语句,它将立即停止执行并返回指定的值。return 语句不仅用于返回值,还用于结束函数的执行。如果在函数中使用了 return,那么 return 后面的代码将不会被执行。例如:

function example() {
  console.log('Hello');
  return;
  console.log('World'); // 这行代码不会被执行
}
example(); // 只输出 'Hello'

1.5 作用域

在编程中,作用域是一个非常重要的概念,它定义了变量、函数和对象的可见性和生命周期。理解作用域可以帮助你写出更加健壮、可维护和高效的代码。

1.5.1 全局作用域

全局作用域是最外层的作用域,它在整个代码执行环境中都是有效的。在Web浏览器中,全局作用域通常是整个<script>标签内部或一个独立的JavaScript文件。在全局作用域中声明的变量和函数可以在任何地方被访问和修改。

1.5.2 局部作用域

局部作用域,也称为函数作用域,是在函数内部定义的作用域。在局部作用域中声明的变量和函数只能在该函数内部被访问和修改。当函数执行完毕后,局部作用域中的变量会被销毁,释放内存。

1.5.3 变量分类

根据作用域的不同,JavaScript中的变量可以分为全局变量和局部变量:

  • 全局变量:在函数外部使用let声明的变量。全局变量可以在任何区域被访问和修改。但是过度使用全局变量可能导致命名冲突和代码难以维护,因此通常建议尽量减少全局变量的使用。
  • 局部变量:在函数内部使用let声明的变量。局部变量只能在当前函数内部被访问和修改。当函数执行完毕,局部变量的生命周期也随之结束,这样可以减少命名冲突并节省内存。
注意
  1. 未声明的变量:如果函数内部直接给一个变量赋值而没有使用let声明,那么这个变量将被当作全局变量处理。但是这种做法是不推荐的,因为它容易导致命名冲突和代码难以维护。
  2. 形参:函数的形参也可以看作是局部变量,它们只在函数内部有效。

理解作用域的概念对于写出高质量的JavaScript代码至关重要。通过合理地使用全局作用域和局部作用域,你可以提高代码的可读性、可维护性和性能。

1.5.4 变量访问原则 (重点)

在编程中,当我们在代码中访问一个变量时,JavaScript引擎会遵循一套特定的规则来确定这个变量的值。这套规则通常被称为“变量访问原则”或“作用域链”。

作用域链
  • 只要是代码,就至少有一个作用域。
  • 写在函数内部的代码拥有局部作用域。
  • 如果函数中还有函数,那么在这个作用域中就又可以诞生一个子作用域。
访问原则

在能够访问到的情况下,先局部,局部没有再找全局。具体来说:

  1. 局部作用域优先:当在当前作用域中查找一个变量时,如果找到了,就直接使用。不会再往上一层作用域去查找。
  2. 逐级向上查找:如果在当前作用域中没有找到所需的变量,引擎就会逐级向上查找,直到全局作用域。
  3. 全局作用域中的变量总是可用的:在任何作用域中都可以访问全局作用域中的变量。但是,如果在局部作用域中有一个与全局变量同名的变量,那么局部变量将会“遮蔽”全局变量。
案例解析

给出的案例中:

function f1() {
    let num = 123;
    function f2() {
      console.log(num); // ①
    }
    f2();
}
let num = 456;
f1();
console.log(num); // ②
  • 在①处,f2函数试图访问num变量。由于f2有自己的作用域,并且在这个作用域中没有找到num,所以它会去父级作用域(也就是f1的作用域)中查找。在f1的作用域中找到了num,值为123,所以输出123。
  • 在②处,我们在全局作用域中访问num变量。全局作用域中确实有一个num变量,值为456,所以输出456。

因此,最终输出为:123 456。这验证了“优先局部作用域”的原则。

1.6 匿名函数

在JavaScript中,函数可以有两种形式:具名函数和匿名函数。

1.6.1 具名函数

具名函数有一个明确的名称,可以通过这个名称来调用该函数。例如:

// 声明
function greeting() {
    console.log('Hello, world!');
}

// 调用
greeting();
1.6.2 匿名函数

匿名函数没有名称。由于其没有名称,所以不能直接调用。例如:

function () {
    console.log('This is an anonymous function.');
}
1.6.3 匿名函数使用方式
①函数表达式

匿名函数通常用作函数表达式的一部分,可以赋值给一个变量,或者作为参数传递给其他函数。这样,虽然函数本身没有名字,但是可以通过变量名来调用它。例如:

var greet = function() {
    console.log('Hello, world!');
};
greet(); // 通过变量名调用匿名函数
②立即执行函数

立即执行函数是一种特殊的函数表达式,它在定义后立即被调用,然后返回一个值。这种模式在JavaScript中经常被用来创建一个隔离的作用域,防止变量污染全局作用域。例如:

(function() {
    console.log('This function will run immediately!');
})(); // 立即执行匿名函数

在这个例子中,匿名函数被包裹在括号中,然后后面跟着一对括号来立即调用它。这种模式确保了函数只执行一次,并且创建了一个局部作用域,使得在其中定义的变量不会泄漏到全局作用域中。

案例:转换时间案例

需求: 用户输入秒数,可以自动转换为时分秒

let second = +prompt("请输入秒数:");

      function getTime(t) {
        let h = parseInt((t / 60 / 60) % 24);
        let m = parseInt((t / 60) % 60);
        let s = parseInt(t % 60);
        h = h < 10 ? "0" + h : h;
        m = m < 10 ? "0" + m : m;
        s = s < 10 ? "0" + s : s;
        // console.log(h, m, s)
        return `转换完毕之后是${h}小时${m}${s}`;
      }
      let str = getTime(second);
      document.write(str);

1.7 逻辑终端

在JavaScript中,逻辑终端(Short-circuiting)是逻辑运算符&&(逻辑与)和||(逻辑或)的一种行为,当运算符左侧的表达式能够决定整个逻辑表达式的结果时,右侧的表达式将不会被执行。

1.7.1 短路原理
  • 在使用 && 运算符时,如果左侧的表达式为 false,则整个表达式的结果必定为 false,因此右侧的表达式将不会被执行。
  • 在使用 || 运算符时,如果左侧的表达式为 true,则整个表达式的结果必定为 true,因此右侧的表达式也将不会被执行。
1.7.2 运算结果

无论是 && 还是 ||,运算结果都是最后被执行的表达式值。这一特性在变量赋值等场景中非常有用。

1.8 转为boolean类型

在JavaScript中,可以使用显式转换和隐式转换将其他类型的数据转换为布尔类型(truefalse)。

1.8.1 显示转换

可以使用 Boolean() 函数进行显式转换。以下值在转换为布尔类型时将被转换为 false

  • 0
  • undefined
  • null
  • false
  • NaN

其余所有值都将被转换为 true

1.8.2 隐式转换

在某些情况下,JavaScript会自动将数据转换为布尔类型,例如:

  • 当使用 + 运算符进行字符串拼接时,数字会被转换为字符串。例如:"" + 1 的结果是字符串 "1"
  • 当使用 - 运算符进行减法运算时,空字符串 "" 会被转换为数字 0
  • null 在经过数字转换之后会变成 0
  • undefined 在经过数字转换之后会变成 NaN(非数字)。

在这里插入图片描述

  • 27
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱喝冰红茶的方舟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值