JavaScript函数的使用

写在前面


大家好,我是一溪风月🤖,一名前端工程师,在JavaScript的世界里,函数是极为关键的存在,它就像是程序的"瑞士军刀",能实现各种各样的功能。无论是简单的弹窗提示,还是复杂的算法实现,函数都发挥着重要作用。今天,就让我们一起深入探索JavaScript函数的奥秘。

一.那些编程里的"神秘名词":foo、bar、baz


在编程学习过程中,大家可能经常看到foo、bar、baz这些词,它们常被用作函数、变量或文件的名称 。虽然这些词本身没有特别含义,被称为"伪变量",但在编程领域却十分常用。关于它们的由来有多种说法,比如有人认为是通过Digital公司的手册说明流行起来的;也有人说源自电子学中的反转foo信号;还有一种说法是foo出现在漫画中,代表"好运",和中文"福"读音相似。了解这些有趣的背景知识,也能为我们的编程学习增添一些乐趣。

二.函数初相识:定义与使用


(一)函数是什么

函数是对某段代码的封装,用于实现特定功能。我们在日常编程中已经接触过不少函数,像alert函数,它能在浏览器中弹出一个弹窗,用于提示用户信息;prompt函数,可以在弹窗里接收用户输入;console.log函数,能在控制台输出内容;还有StringNumberBoolean等函数。这些函数都是JavaScript引擎或浏览器为我们提供的"工具",帮助我们完成各种任务。当然,我们也可以自己编写函数,满足特定的业务需求。

(二)函数使用的两步曲:声明与调用

使用函数主要有两个步骤:声明函数和调用函数。声明函数就是把实现特定功能的代码封装起来,而调用函数则是让这些封装好的功能发挥作用。

  1. 声明函数 :在JavaScript中,声明函数使用function关键字,语法如下:
js 复制代码
function 函数名() {
    // 函数封装的代码
    // 这里可以写实现具体功能的代码
}

需要注意的是,函数名的命名规则和变量名一致,要尽量做到见名知意,并且因为函数通常表示某种行为,所以使用动词会更合适。比如,定义一个打印个人信息的函数,可以命名为printPersonInfo。另外,函数定义完后,里面的代码并不会立即执行,必须通过调用函数才能执行。

  1. 调用函数 :调用函数非常简单,直接使用函数名加上一对小括号()即可,例如定义了一个test函数,调用它就用test()。下面通过两个练习来加深理解:

    • 练习一:定义一个函数,打印一个人的个人信息
js 复制代码
function printPersonInfo() {
    let name = "张三";
    let age = 20;
    console.log(`姓名:${name},年龄:${age}`);
}
printPersonInfo();
  • 练习二:定义一个函数,函数中计算10和20数字的和,并且打印出结果
js 复制代码
function calculateSum() {
    let num1 = 10;
    let num2 = 20;
    let sum = num1 + num2;
    console.log(`10和20的和是:${sum}`);
}
calculateSum();

三.函数的参数

函数的参数能让函数更加通用,对于相同的数据处理逻辑,可以适应更多不同的数据。在函数内部,参数就像变量一样,可以进行数据处理。调用函数时,按照函数定义的参数顺序,把需要处理的数据传递进去。参数分为形参和实参:

  • 形参:定义函数时,小括号中的参数就是形参,它用于接收参数,在函数内部当作变量使用。
  • 实参:调用函数时,小括号中的参数是实参,用来把数据传递到函数内部。

下面通过几个练习来看看不同参数数量的函数使用:

  • 一个参数的函数练习

    • 练习一:传入一个名字,对这个人say Hello
js 复制代码
function sayHello(name) {
    console.log(`Hello, ${name}!`);
}
sayHello("李四");
  • 练习二:为某个朋友唱生日快乐歌
js 复制代码
function singHappyBirthday(friendName) {
    console.log(`Happy Birthday to ${friendName}!`);
}
singHappyBirthday("王五");
  • 两个参数的函数练习

    • 练习三:传入两个数字,计算两个数字的和,并且打印结果
js 复制代码
function calculateSum(num1, num2) {
    let sum = num1 + num2;
    console.log(`${num1}和${num2}的和是:${sum}`);
}
calculateSum(5, 8);

四.函数的返回值


函数不仅可以有参数,还能有返回值,使用return关键字来返回结果。一旦执行return操作,当前函数就会终止。如果函数中没有使用return语句,或者return后面没有任何值,函数的返回值都是undefined。下面通过几个练习来理解函数的返回值:

  • 练习一:实现一个加法计算器
js 复制代码
function add(num1, num2) {
    return num1 + num2;
}
let result = add(3, 7);
console.log(`3和7相加的结果是:${result}`);
  • 练习二:定义一个函数,传入宽高,计算矩形区域的面积
js 复制代码
function calculateRectangleArea(width, height) {
    return width * height;
}
let area = calculateRectangleArea(5, 4);
console.log(`宽为5,高为4的矩形面积是:${area}`);
  • 练习三:定义一个函数,传入半径,计算圆形的面积
js 复制代码
function calculateCircleArea(radius) {
    return Math.PI * radius * radius;
}
let circleArea = calculateCircleArea(3);
console.log(`半径为3的圆形面积是:${circleArea}`);
  • 练习四:定义一个函数,传入n(n为正整数),计算1~n数字的和
js 复制代码
function sumFrom1ToN(n) {
    let sum = 0;
    for (let i = 1; i <= n; i++) {
        sum += i;
    }
    return sum;
}
let sumResult = sumFrom1ToN(5);
console.log(`1到5的数字和是:${sumResult}`);
  • 实战函数练习:传入一个数字,可以根据数字转化成显示为亿、万文字显示的文本
js 复制代码
function formatNumberToText(num) {
    if (num >= 100000000) {
        return `${num / 100000000}亿`;
    } else if (num >= 10000) {
        return `${num / 10000}万`;
    } else {
        return num.toString();
    }
}
let numText = formatNumberToText(500000000);
console.log(numText);

五.arguments参数


在函数中有一个特殊的对象arguments,它是所有(非箭头)函数都可用的局部变量。这个对象存放着所有调用者传入的参数,从0位置开始依次存放。虽然它的类型是object(类似数组,但不是真正的数组),不过用法和数组很相似。如果调用者传入的参数比函数接收的参数多,就可以通过arguments获取所有参数。由于涉及到数组、对象等概念,刚开始学习的同学了解有这么个参数就行,后续深入学习时会详细研究它和数组之间的转化。例如:

js 复制代码
function showArgs() {
    for (let i = 0; i < arguments.length; i++) {
        console.log(arguments[i]);
    }
}
showArgs(1, 2, 3);

六.函数中调用函数


在开发过程中,函数内部是可以调用其他函数的。比如:

js 复制代码
function foo() {
    console.log("foo函数被调用");
}
function bar() {
    foo();
}
bar();

那函数能不能调用自己呢?答案是可以的,不过必须要有结束条件,否则会产生无限调用,导致报错。例如下面这个错误的示例:

js 复制代码
var count = 0;
function bar() {
    console.log(count++);
    bar();
}
bar();
// 报错:Uncaught RangeError: Maximum call stack size exceeded

这种函数调用自己的方式有个专业名词,叫做递归(Recursion)。递归是一种很重要的编程思想,它能把一个复杂的任务转化成可以重复执行的相同任务。以实现一个幂函数pow为例,我们可以用for循环来实现:

js 复制代码
function pow(a, n) {
    var result = 1;
    for (var i = 0; i < n; i++) {
        result *= a;
    }
    return result;
}

也可以用递归的方式实现。在数学上,(x^{n}=x * x^{n - 1}),所以在函数实现时可以这样写:

js 复制代码
function pow(x, n) {
    if (n === 1) return x;
    return x * pow(x, n - 1);
}

递归的代码初次接触可能会觉得有点绕,刚开始学习函数的同学可以先跳过,后续学习数据结构与算法时,会经常用到递归来解决算法问题。

七.局部变量和外部变量


在JavaScript(ES5之前)中没有块级作用域的概念,但函数可以定义自己的作用域。作用域表示一些标识符的有效范围,函数的作用域意味着在函数内部定义的变量,只有在函数内部才能被访问到。

  • 局部变量:定义在函数内部的变量就是局部变量。
  • 外部变量:定义在函数外部的变量称为外部变量。
  • 全局变量 :在函数之外(比如在<script>标签中声明的变量)声明的变量就是全局变量,全局变量在任何函数中都可见。通过var声明的全局变量还会在window对象上添加一个属性(了解即可)。在函数中访问变量时,会优先访问自己函数中的变量,如果没找到,才会去外部访问。关于块级作用域、作用域链、变量提升、AO、VO、GO等概念,后续会深入学习。例如:
js 复制代码
let globalVar = "我是全局变量";
function testFunction() {
    let localVar = "我是局部变量";
    console.log(localVar); // 输出:我是局部变量
    console.log(globalVar); // 输出:我是全局变量
}
testFunction();

八.函数表达式与头等函数


(一)函数表达式

前面定义函数的方式叫函数声明,还有一种写法是函数表达式。例如:

js 复制代码
var foo = function() {
    console.log("foo函数");
};

这里function关键字后面没有函数名,函数表达式允许省略函数名。函数声明和函数表达式有一些区别:

区别点 函数声明 函数表达式
语法 在主代码流中声明为单独的语句 在一个表达式中或另一个语法结构中创建
创建时机 在脚本运行前,JavaScript会先寻找并创建全局函数声明 代码执行到达时被创建,从那一刻起才可用
开发选择 优先考虑,组织代码更灵活,声明前可调用 根据具体需求,比如需要在特定表达式中创建函数时使用

(二)头等函数与函数式编程

在JavaScript中,函数是一种特殊的值(其类型是对象,关于对象后续会深入学习),并且可以被当作头等公民。这意味着函数能作为别的函数的参数、函数的返回值,还能赋值给变量或存储在数据结构中。支持这种编程方式的语言,我们称之为函数式编程,JavaScript就是其中之一。例如:

js 复制代码
function foo() {
    console.log("foo函数执行");
}
var bar = foo;
bar();

函数还能传递给另外一个函数,像下面这种情况:

js 复制代码
function foo(fn) {
    fn();
}
function bar() {
    console.log("我是bar函数被调用");
}
foo(bar);

这里foo函数接受一个函数作为参数,这种函数也被称为高阶函数。高阶函数必须至少满足两个条件之一:接受一个或多个函数作为输入;输出一个函数。另外,如果传入函数时没有指定函数名,或者通过函数表达式指定函数对应的变量,这个函数就叫做匿名函数。

九.立即执行函数


(一)什么是立即执行函数

立即执行函数,专业名字叫Immediately - Invoked Function Expression(IIFE),它的特点是函数定义完后会立即执行。它由两部分组成,第一部分是定义一个匿名函数,这个函数有自己独立的作用域;第二部分是后面的(),表示这个函数被执行了。例如:

js 复制代码
(function() {
    console.log("立即执行函数");
})();

(二)立即执行函数的作用

立即执行函数会创建一个独立的执行上下文环境,这样可以避免外界访问或修改内部的变量,也能防止内部变量被外界修改。比如在操作DOM元素时:

js 复制代码
var btns = document.querySelectorAll(".btn");
for (var i = 0; i < btns.length; i++) {
    (function(m) {
        btns[m].onclick = function() {
            console.log(`第${m}个按钮被点击了`);
        };
    })(i);
}

(三)立即执行函数的注意事项

立即执行函数必须是一个表达式,不能是函数声明。下面这种写法会报错,因为它被当成了函数声明:

js 复制代码
function foo() {
}()
console.log("立即执行函数");
// 报错

而把函数用圆括号包裹起来,就会被当作表达式解析,例如:

js 复制代码
(function foo() {
    console.log("立即执行函数");
})();

另外,还有一些其他写法也能实现立即执行函数,比如:

js 复制代码
+function foo() {
    console.log("立即执行函数");
}();
(function foo() {
    console.log("立即执行函数");
}());

十.代码风格与调试技巧


(一)代码风格规范

在编写JavaScript代码时,遵循良好的代码风格规范很重要。比如:参数之间要有空格;函数名和括号之间要有空格;操作符周围要有空格;forifwhile等关键字后面要有空格;代码缩进使用2个空格;逻辑块之间要有空行;每行代码不要太长等。良好的代码风格能让代码更易读、易维护。

(二)Chrome的debug调试技巧

在开发过程中,调试代码是必不可少的环节。Chrome浏览器提供了强大的调试工具。例如,在代码中添加debugger关键字,当代码执行到这一行时,会暂停执行,这时可以在调试面板中查看变量的值、调用栈信息等,方便我们排查代码中的问题。比如下面这段代码:

js 复制代码
function foo() {
    console.log("fo0函数执行");
    setTimeout(function() { }, 2000);
}
function bar() {
    console.log("bar函数执行");
    foo();
}
debugger;
bar();

在Chrome浏览器的开发者工具中,就能利用调试功能,一步步查看代码的执行过程,找到可能存在的问题。

十一.总结


这篇文章到这里就结束了🔚,JavaScript函数的知识丰富而有趣,从基础的声明调用,到参数、返回值、递归,再到函数的各种高级特性,每一部分都值得我们深入学习和研究。希望通过这篇文章,大家能对JavaScript函数有更全面、更深入的理解,在编程的道路上更上一层楼。

相关推荐
Gazer_S1 分钟前
【Vite构建性能优化实战:我如何将项目构建时间减少60%】
前端·javascript·性能优化
前端 贾公子6 分钟前
每日一题 == 674. 最长连续递增序列
前端·javascript·力扣
丁总学Java8 分钟前
Vue 2 探秘:visible 和 append-to-body 是谁的小秘密?
前端·javascript·vue.js·ts
BerryBC16 分钟前
ChatBI的流程图
java·前端·流程图
张洪財1 小时前
留记录excel 模板导入
java·服务器·前端
2401_897930063 小时前
jQuery 常用方法详解及示例
前端
不想上班只想要钱3 小时前
Css环形旋转立体感动画
前端·css
AndrewPerfect5 小时前
关于跨域问题(本地前端访问服务器端接口跨域出错)
前端·后端
2301_789169545 小时前
angular路由守卫的break down2
前端·javascript·angular.js
浪遏6 小时前
我的远程实习(五)| 教你一招走查网站SEO😉| AITDK
前端·面试·seo