Menu Close

JavaScript 函数 Functions, 变量,常量,全局变量和局部变量

在脚本的许多地方,我们经常需要执行类似的操作。

例如,当访客登录、登出,或在其他场景中,我们可能都需要显示一条漂亮的消息。

函数是程序的主要“构建块”。它们允许我们多次调用相同的代码,而无需重复书写。JavaScript 中的函数是可以定义并在需要时调用的代码片段。它们可以被看作是程序中的子程序。

函数非常有用,因为它们允许程序员只编写一次代码,然后在程序中多次重复使用,从而减少代码重复。同时,函数也使程序员能够创建逻辑上独立的代码段,这些代码段可以与程序中的其他部分区分开来。如果需要更详细的了解函数,可参考C语言的函数介绍

我们已经见过一些内建函数的例子,比如 alert(message)prompt(message, default)confirm(question)。但我们也可以创建自己的函数。

函数具有以下特点:

  • 可以接受零个或多个参数

  • 可以在函数调用结束时返回一个指定的值

  • 即使不返回值,也可以对程序的其他部分产生副作用

JavaScript 函数 Functions
JavaScript 函数 Functions

函数声明

要创建一个函数,我们可以使用函数声明的方式。

它的语法如下:

function showMessage() {
  alert( 'Hello everyone!' );
}

function 关键字写在最前面,然后是函数的名称,接着是括号中的参数列表(用逗号分隔,上面的例子中是空的,稍后我们会看到带参数的例子),最后是函数的代码,也称为“函数体”,包裹在花括号中。

function name(parameter1, parameter2, ... parameterN) {
 // body
}

我们可以通过函数名 showMessage() 来调用新函数。

例如:

function showMessage() {
  alert( 'Hello everyone!' );
}

showMessage();
showMessage();

调用 showMessage() 会执行该函数的代码。在这个例子中,我们会看到这条消息出现两次。

这个例子清楚地展示了函数的主要用途之一:避免代码重复。

如果我们需要更改消息的内容或显示方式,只需修改一个地方:输出消息的那个函数。

局部变量

在函数内部声明的变量只能在该函数内部访问。

例如:

function showMessage() {
  let message = "Hello, I'm JavaScript!"; // local variable

  alert( message );
}

showMessage(); // Hello, I'm JavaScript!

alert( message ); // <-- Error! The variable is local to the function

外部变量

函数也可以访问外部的变量,例如:

let userName = 'John';

function showMessage() {
  let message = 'Hello, ' + userName;
  alert(message);
}

showMessage(); // Hello, John

函数可以完全访问外部变量,也可以修改它。

例如:

let userName = 'John';

function showMessage() {
  userName = "Bob"; // (1) changed the outer variable

  let message = 'Hello, ' + userName;
  alert(message);
}

alert( userName ); // John before the function call

showMessage();

alert( userName ); // Bob, the value was modified by the function

只有在函数内部没有声明同名的局部变量时,外部变量才会被使用。

如果在函数内部声明了一个同名的变量,它会遮蔽(shadow)外部的变量。例如,在下面的代码中,函数使用的是局部的 userName,外部的 userName 被忽略了:

let userName = 'John';

function showMessage() {
  let userName = "Bob"; // declare a local variable

  let message = 'Hello, ' + userName; // Bob
  alert(message);
}

// the function will create and use its own userName
showMessage();

alert( userName ); // John, unchanged, the function did not access the outer variable

全局变量

在任何函数外部声明的变量,比如上面代码中的外部 userName,称为全局变量。

全局变量可以在任何函数中访问(除非被局部变量遮蔽)。

最好尽量减少使用全局变量。现代代码中全局变量较少或没有。大多数变量都驻留在它们各自的函数中。不过,有时全局变量可以用来存储项目级别的数据。

参数

我们可以通过参数将任意数据传递给函数。

在下面的例子中,函数有两个参数:fromtext

function showMessage(from, text) { // parameters: from, text
  alert(from + ': ' + text);
}

showMessage('Ann', 'Hello!'); // Ann: Hello! (*)
showMessage('Ann', "What's up?"); // Ann: What's up? (**)

当函数在 (*) 和 (**) 行被调用时,传入的值会被复制到局部变量 fromtext 中。然后,函数使用这些局部变量。

这是另一个例子:我们有一个变量 from 并将其传递给函数。请注意:函数可以修改 from,但外部并不会看到这个变化,因为函数总是接收到值的副本:

function showMessage(from, text) {

  from = '*' + from + '*'; // make "from" look nicer

  alert( from + ': ' + text );
}

let from = "Ann";

showMessage(from, "Hello"); // *Ann*: Hello

// the value of "from" is the same, the function modified a local copy
alert( from ); // Ann

当一个值作为函数参数传递时,它也被称为实参。

READ  Javascript严格模式,“use strict”

换句话说,澄清这些术语的定义:

  • 参数 是在函数声明时括号内列出的变量(这是声明时的术语)。

  • 实参 是在调用函数时传递给函数的值(这是调用时的术语)。

我们声明函数时列出其参数,然后在调用时传递实参。

在上面的例子中,可以这样说:“showMessage 函数声明时有两个参数,然后在调用时传入了两个实参:from"Hello"。”

默认值

如果调用了一个函数,但未提供某个参数,则对应的值将变为 undefined。

例如,上述函数 showMessage(from, text) 可以只用一个参数进行调用:

showMessage("Ann");

这不是错误。这样的调用会输出 “Ann: undefined”。由于未传入 text 的值,它变为 undefined。

我们可以在函数声明中使用 = 为参数指定所谓的“默认”(在省略时使用)值:

function showMessage(from, text = "no text given") {
  alert( from + ": " + text );
}

showMessage("Ann"); // Ann: no text given

现在如果未传入 text 参数,它将获得值 “no text given”。

如果参数存在但严格等于 undefined,默认值也会生效,如下所示:

showMessage("Ann", undefined); // Ann: no text given

这里的 “no text given” 是一个字符串,但它也可以是更复杂的表达式,且仅在参数缺失时才会被计算并赋值。因此,这也是可行的:

function showMessage(from, text = anotherFunction()) {
  // anotherFunction() only executed if no text given
  // its result becomes the value of text
}

默认参数的求值

JavaScript 中,每次调用函数且未提供相应参数时,默认参数都会被求值。

在上面的例子中,如果提供了 text 参数,anotherFunction() 根本不会被调用。

另一方面,每次缺少 text 参数时,它都会被单独调用一次。

默认参数的替代

有时在函数声明之后的某个阶段为参数赋默认值更有意义。

我们可以在函数执行期间通过将参数与 undefined 进行比较来检查是否传入了该参数:

function showMessage(text) {
  // ...

  if (text === undefined) { // if the parameter is missing
    text = 'empty message';
  }

  alert(text);
}

showMessage(); // empty message

……或者我们可以使用 || 运算符

function showMessage(text) {
  // if text is undefined or otherwise falsy, set it to 'empty'
  text = text || 'empty';
  ...
}

现代 JavaScript 引擎支持空值合并运算符 ??,当大多数假值(如 0)应被视为“正常”时,它更合适:

function showCount(count) {
  // if count is undefined or null, show "unknown"
  alert(count ?? "unknown");
}

showCount(0); // 0
showCount(null); // unknown
showCount(); // unknown

返回值

函数可以将一个值作为结果返回到调用代码中。

最简单的例子是一个将两个值相加的函数:

function sum(a, b) {
  return a + b;
}

let result = sum(1, 2);
alert( result ); // 3

指令 return 可以出现在函数的任意位置。当执行到它时,函数将停止,并将该值返回给调用代码(在上面的例子中赋值给 result)。

一个函数中可能会有多处 return。例如:

function checkAge(age) {
  if (age >= 18) {
    return true;
  } else {
    return confirm('Do you have permission from your parents?');
  }
}

let age = prompt('How old are you?', 18);

if ( checkAge(age) ) {
  alert( 'Access granted' );
} else {
  alert( 'Access denied' );
}

下面的示例在一个函数中使用多个 return 语句来根据条件返回不同的值:

function compare(a, b) {
    if (a > b) {
        return -1;
    } else if (a < b) {
        return 1;
    }
    return 0;
}

compare()函数比较两个值。它返回:

  • 如果第一个参数大于第二个参数,则返回 -1 。
  • 如果第一个参数小于第二个参数,则返回 1。
  • 如果第一个参数等于第二个参数,则返回 0。
READ  Javascript 逗号运算符(Comma)

函数在到达 return 语句时立即停止执行。因此,您可以使用不带值的 return 语句来提前退出函数,如下所示:

例如:

function showMovie(age) {
  if ( !checkAge(age) ) {
    return;
  }

  alert( "Showing you the movie" ); // (*)
  // ...
}

在上面的代码中,如果 checkAge(age) 返回 false,那么 showMovie 将不会继续执行 alert。

JavaScript 函数、变量、和常量的命名规范

1. 命名规范

ECMAScript 规范中标识符采用驼峰大小写格式,驼峰命名法由小(大)写字母开始,后续每个单词首字母都大写。根据首字母是否大写,分为两种方式:

  1. Pascal Case 大驼峰式命名法:首字母大写。eg:StudentInfo、UserInfo、ProductInfo
  2. Camel Case 小驼峰式命名法:首字母小写。eg:studentInfo、userInfo、productInfo

标识符,则包括变量、函数名、类名、属性名和函数或类的参数,每个命名方法又略有不同,下面详细解释一下:

2. 函数的命名

函数是执行某些操作的行为。因此,它们的名称通常是动词。名称应简洁、尽可能准确,并描述函数的作用,以便阅读代码的人能大致了解该函数的功能。

一个广泛采用的做法是用动词前缀来命名函数,这些前缀模糊地描述了动作。团队内部应就这些前缀的含义达成一致。

命名方法:小驼峰式命名法。

命名规范:前缀应当为动词。

命名建议:可使用常见动词约定

动词 含义 返回值
can 判断是否可执行某个动作(权限) 函数返回一个布尔值。true:可执行;false:不可执行
has 判断是否含有某个值 函数返回一个布尔值。true:含有此值;false:不含有此值
is 判断是否为某个值 函数返回一个布尔值。true:为某个值;false:不为某个值
get 获取某个值 函数返回一个非布尔值
set 设置某个值 无返回值、返回是否设置成功或者返回链式对象
load 加载某些数据 无返回值或者返回是否加载完成的结果

以下是一些常见前缀及其含义:

  • “get…” – 返回一个值,

  • “calc…” – 计算某些内容,

  • “create…” – 创建某些内容,

  • “check…” – 检查某些内容并返回布尔值,等等。

这类名称的示例:

showMessage(..)     // shows a message
getAge(..)          // returns the age (gets it somehow)
calcSum(..)         // calculates a sum and returns the result
createForm(..)      // creates a form (and usually returns it)
checkPermission(..) // checks a permission, returns true/false

有了这些前缀,一眼就能从函数名中了解它的作用以及返回值的类型。

函数命名注意事项

一个函数 —— 一个动作

一个函数应当只做其名称所暗示的事情,不多也不少。

两个独立的动作通常应该写成两个函数,即使它们经常一起被调用(这种情况下我们可以写一个第三个函数来调用这两个)。

以下是一些违反该原则的例子:

  • getAge —— 如果它弹出一个显示年龄的警告框,那就不合适(它应该只是获取年龄)。

  • createForm —— 如果它修改了文档并将表单添加到其中,那就不妥(它应该只是创建并返回表单)。

  • checkPermission —— 如果它显示了“允许访问/拒绝访问”的消息,那就不好(它应该只执行检查并返回结果)。

这些例子基于前缀的一般含义。你和你的团队可以就其他含义达成一致,但通常不会有太大差别。无论如何,你应当清楚了解每个前缀的意义,知道带有该前缀的函数应该做什么、不能做什么。所有使用相同前缀的函数都应遵循同一规则,并在团队中达成共识。

超短的函数名称

那些非常常用的函数有时会使用超短的名称。

例如,jQuery 框架定义了一个函数,名称是 $。Lodash 库的核心函数名为 _。

这些是例外。通常情况下,函数名称应简洁且具有描述性。

函数 == 注释

函数应该简短并且只做一件事。如果这件事很大,也许值得将函数拆分成几个更小的函数。有时候遵循这个规则可能并不容易,但它绝对是有益的。

一个单独的函数不仅更容易测试和调试——它的存在本身就是一个很好的注释!

例如,比较下面的两个 showPrimes(n) 函数。每个函数都会输出小于等于 n 的质数

下面第一段CODE使用了标签:

function showPrimes(n) {
  nextPrime: for (let i = 2; i < n; i++) {

    for (let j = 2; j < i; j++) {
      if (i % j == 0) continue nextPrime;
    }

    alert( i ); // a prime
  }
}

第二段COD使用了一个额外的函数 isPrime(n) 来测试是否为质数

function showPrimes(n) {

  for (let i = 2; i < n; i++) {
    if (!isPrime(i)) continue;

    alert(i);  // a prime
  }
}

function isPrime(n) {
  for (let i = 2; i < n; i++) {
    if ( n % i == 0) return false;
  }
  return true;
}

第二段code更容易理解,不是吗?我们看到的是一个动作的名称(isPrime),而不是一段代码。有时人们将这样的代码称为自描述(self-describing)代码。

因此,即使我们不打算重复使用它们,函数仍然可以被创建。它们帮助结构化代码并提高可读性。

3. 变量的命名

命名方法:小驼峰式命名法。

命名规范:前缀应当是名词。(函数的名字前缀为动词,以此区分变量和函数)

命名建议:尽量在变量名字中体现所属类型,如:length、count等表示数字类型;而包含name、title表示为字符串类型。

// 好的命名方式
let maxCount = 10;
let tableTitle = 'LoginTable';
// 不好的命名方式
let setCount = 10;
let getTitle = 'LoginTable';

4. 常量

命名方法:名称全部大写。

命名规范:使用大写字母和下划线来组合命名,下划线用以分割单词。

const MAX_COUNT = 10;
const URL = 'https://2743.com';
除教程外,本网站大部分文章来自互联网,如果有内容冒犯到你,请联系我们删除!
Posted in JavaScript 基础

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

Leave the field below empty!