JavaScript 如何工作系列:声明函数的不同方式 + 5个最佳实践

几乎每次使用带括号的 JavaScript 语句时,我们只是在使用 JavaScript 函数。 函数属于称为对象的 JavaScript 数据类型,几乎每个 JavaScript 程序都在函数内部运行。

JavaScript 中的函数与其他一些高级脚本语言(如 TypeScript)的函数非常相似,并且有两种类型的函数:预定义的和用户定义的。 预定义函数是内置的,已经嵌入在程序中的函数,而作为本文重点的用户定义函数是用户输入到程序中以执行自定义任务的函数。

本文探讨了什么是 JavaScript 函数、声明函数的不同方式以及使用它们时的最佳实践。 了解 JavaScript 对象和 this 关键字将帮助我们更好地理解本文。 随意将本文中的代码行复制到浏览器的控制台中,以熟悉函数背后的逻辑和不同的声明方法。


什么是 JavaScript 函数?

函数是 JavaScript 中必不可少的构建块,它们包含执行任务的逻辑。 函数可以比作执行任务或计算值的过程。 但是,要将此过程视为一个函数,它需要接受一些输入并返回一个输出。 例如,一个计算值的函数应该接受用户的输入(要计算的值)并返回一个输出(计算的值)。 简单来说,函数是一组执行任务的语句。

一个函数可以重复使用。 — 它可以在程序中执行任意多次,无需重复代码。 这被称为模块化编码。 由于每个函数都执行特定的任务,因此函数也可用于代码分组——根据它们执行的任务将大型程序分解为更小的代码片段。 它们是预定义的或用户定义的(自定义代码)。


声明 JavaScript 函数的不同方法

在 JavaScript 中,有多种声明函数的方式。 让我们来看看什么是函数声明。

函数声明,也称为函数定义或语句,是一种在程序执行时提供要在程序中执行的指令集的方式。 这是一种使用特定参数保存函数的方法,以便在需要执行定义它的任务时调用(调用)它。

必须先定义函数的语法(如下所示),然后才能实现它:

function name() {
    //…….
}

让我们看看上面的例子:

  • function 是实际代码之前的关键字。 它是一个语句标识符。 这就是为什么说函数是自包含的。
  • name 是要对参数执行的函数的名称。 它是用户定义的,必须是一个动作词。
  • ( ) 是分组运算符,它是一对括号,它封装了要在程序中运行的参数。
  • { } 是存放代码本身的块。 它是函数的真正定义,用于对语句进行分组。

声明的函数可以用名称 ( ) 调用; 在需要的时候。

函数语句的示例如下所示:

function greet() {
    console.log("Hello 迹忆客");
}
greet();

该函数使用函数名称 greet ,并在浏览器的控制台上输出“Hello 迹忆客”。 要再次生成输出,可以通过简单地调用 greet(); 来调用它。

现在我们知道了什么是函数声明,接下来我们可以考虑在 JavaScript 中声明函数的不同方式:

  • 函数表达式
  • 匿名函数
  • 立即调用的函数表达式
  • 构造函数
  • Getter函数
  • Hoisting
  • 箭头函数

函数表达式

可以使用函数表达式来声明函数。 它的声明与一般语法完全不同,因为它使用变量来表示函数的名称。 此变量位于关键字函数之前。 该函数通过调用带有尾括号和分号的变量来调用:

var greet = function () {
  console.log("Welcome to Javascript");
};
greet();

这种函数声明方法使跟踪错误变得容易。 它指定堆栈跟踪中函数的名称。 通过函数表达式方法声明的函数既可以用作匿名函数,也可以用作 IIFE(立即调用的函数表达式)。

匿名函数

匿名函数声明允许函数名称隐藏在声明本身中。 在一般的函数声明语法中,函数名附加在 function 关键字上,但匿名函数仅使用 function 关键字和括号来声明。

下面是匿名函数的语法:

function  () {
  // function body
}

此函数仅声明一次,因为没有标识符就无法调用。 可以调用它的唯一方法是将函数分配给变量,以便可以在我们的代码中调用变量名称。

例如,下面的示例显示了一个分配给变量 greet 的匿名函数声明。 在示例中,变量 greet 存储函数,并且每当我们想要调用该函数时,我们只需调用 greet()

var greet = function () {
    console.log("Welcome to Javascript");
};
greet();

匿名函数也可以是函数的参数,因此,它可以在另一个函数中声明为它的参数。 一个简单的示例是一个原生 JavaScript 函数 setTimeout

setTimeout(
  function () {
    console.log("3秒之后执行");
  }  , 3000 // 延迟毫秒
)

立即调用的函数表达式

IIFE 是可以表示为表达式或普通声明并使用函数表达式的匿名属性来执行其代码的函数。 如果要在声明后立即执行函数,请使用 IIFE。 这是通过将匿名函数包装在括号中并以分号结束来执行的:

(function () {
  console.log("Welcome to Javascript");
})();

尾括号 () 用于调用该函数。 IIFE 主要用于避免对全局对象的污染。 例如,在将两个包含相同函数的 JavaScript 文件加载到一个 HTML 文件中的情况下,来自 IIFE 的后面的标识符会覆盖最前面的标识符。

虽然不是很常见,但可以使用一元运算符创建 IIFE。 但是,这些运算符会影响 IIFE 的返回值。 以下是一元运算符列表以及它们如何影响 IIFE

+function(){
   return 2;
}();//返回 2


-function(){
   return 2;
}();//返回 -2

~function(){
   return 2;
}();//返回 -3


!function(){
   return 2;
}();//返回 false

构造函数

构造函数的概念是创建一个在全局范围内执行的函数对象。 它可用于创建多个相似的对象。 函数构造函数具有与函数表达式类似的功能。 使用 new 关键字调用构造函数来创建对象。 Function() 是包含参数的构造函数:

var F = new Function(arg1, functionBody)
var F = new Function(arg1, arg2, functionBody)
var F = new Function(arg1, arg2, .........., argN, functionBody)

在下面的示例中,我们使用 new 关键字创建了一个函数 multiply。 然后,我们可以通过调用 multiply() 来调用我们声明的函数:

// new Function 创建一个新的函数对象 'multiply'
const multiply = new Function('a', 'b', 'return a * b');

console.log(multiply(2, 6));
// 期望输出: 12

此外,构造函数可以与 this 关键字一起使用。 这允许开发人员将值作为属性分配给函数对象。 例如,在下面的代码中,属性 name 和 age 使用 this 关键字分配给函数 Person。

// 构造函数
function Person() {
    this.name = "Anita",
    this.age = 21
}
// create an object
const person = new Person();

//access properties
console.log(person.name);
console.log(person.age);

可以使用构造函数创建多个对象,如下例所示:

var Person = function (name, age) {
    this.name = name;
    this.age = age;
};

// 创建第一个对象实例
const person1 = new Person("Anita", 12);
// 创建第二个对象实例
const person2 = new Person("Ugochi", 10);

// 打印第一个对象的名称
console.log(person1.name);
// 打印第二个对象的名称
console.log(person2.name);

this 关键字用于 this 函数声明方法,它在创建对象时引用对象,以便可以访问该属性。 但是,在函数构造函数下调用的函数在 JavaScript 中并不常用,因为它们性能差,缺乏安全性。

Hoisting

使用 JavaScript 函数,可以在实际编写函数语句的代码之前调用函数并给出定义的输出。 此属性称为提升(Hoisting)。 提升是在声明之前在脚本顶部调用函数的能力。 由于该函数在块的顶部被提升但未初始化,因此在声明之前不能使用它。 回顾之前的例子:

greet();

function greet() {
    console.log("Hello 迹忆客");
}

这是一个已被提升的函数声明,当被浏览器执行时会输出 “Hello 迹忆客“。 greet() 在声明之前被调用。 但是,在 greet() 函数初始化之前,greet() 将存储在堆中,因此不会出错。

提升作用于作用域的机制,用于识别函数表达式的变量都是基于在初始化函数之前执行的 JavaScript 引擎的作用域。

箭头函数

这是 ES6 版本的 JavaScript 中可用的一个特性,因此它并没有像函数声明中的其他特性那样长期存在。 它通常是创建 JavaScript 函数的一种更简洁的方式,它类似于函数表达式。

箭头函数的语法如下所示

let name = (arguements1, arguements2, arguements 3...) => {
    statements
};

它在其语法中不使用 function 关键字。 对于多行语句,使用大括号。 箭头函数语句可以隐式返回值。 这意味着在某些情况下不需要关键字 return 来返回函数的值。 下面的例子解释了这一点:

const greet = () => "Hello 迹忆客"

greet() // Hello 迹忆客

但是,在某些情况下会显式返回箭头函数语句。 例如,当花括号包裹在函数体周围时,它不会隐式返回值。 这意味着我们必须使用 return 关键字。 下面是一个简单的例子来说明这一点:

let sum = (x, y) => {
    let result = x + y
    return result;
}
let result1 = sum(2, 3);
console.log(result1);

但是,如果只有一个语句,则可以省略大括号。 这也适用于只有一个论点的地方。 这称为速记。 下面的例子展示了如何声明没有大括号的箭头函数

let greet = (x) => console.log("x");
greet("欢迎学习JavaScript箭头函数");

对于没有参数的表达式,括号留空:

let greet = () => console.log("欢迎学习JavaScript箭头函数");
greet();

箭头函数还提供更好的语法,对 Promise 和回调更友好。 下面的示例使用箭头函数重写函数表达式:

asyncFunction().then(function () {
    return asyncFunction1();
}).then(function () {
    return asyncFunction2();
}).then(function () {
    // Finish:
});

上面可以用箭头函数(JavaScript 的 ES6 版本)更好地重写为:

asyncFunction()
    .then(() => asyncFunction1())
    .then(() => asyncFunction2())
    .then(() => finish)

不同声明方法的最佳实践

这里探讨了如何以及何时使用不同的函数声明方法以从其独特功能中获得最大收益:

  • 不要将返回值放在新行上,因为 JavaScript 总是假定在 return 语句后有一个分号。 如果违反,函数返回 undefined: “`javascript function foo() { return 1; }

// 这将引发错误。 foo();

“` 上面的代码会抛出错误,因为返回值和 return 关键字在不同的行中。

  • 最好对大型程序使用函数表达式,因为它可以很容易地识别错误。
  • Getter 函数最适合用于值验证和只读属性。 此外,在使用 getter 函数时,不要为 getter 分配相同的名称,因为 getter 函数将覆盖该属性的属性。
  • 虽然不是规则,但构造函数的函数名最好以大写字母开头。 此外,构造函数最好用于创建仅在全局范围内执行的函数。
  • 不要在对象内部使用箭头函数来创建方法。 它输出未定义。 这是因为箭头函数没有自己的 this 绑定。

总结

在本文中,我们已经能够探索 JavaScript 函数以及可以在程序中声明它们的各种方式。如果想多次执行一段代码,而不必在程序中重复编写相同的代码块,那么在编写 JavaScript 程序时,JavaScript 函数是必不可少的。我们可以简单地说,该函数是一个保存的算法,在被调用时提供给程序以供使用。

了解声明函数的各种方法很重要,因为这允许我们在为用例声明函数时选择最佳方法。

选择正确的函数声明方法可以优化我们的代码并允许我们构建更好的架构。

对于 SessionStack 的我们来说,优化代码的每一点都至关重要。

原因是我们的库被集成到 Web 应用程序中并从用户会话中收集数据,例如用户事件、DOM 更改、网络数据、异常、调试消息等。在不影响性能的情况下捕获这些数据一直是我们成功解决的挑战。

免责声明:
1.本站所有内容由本站原创、网络转载、消息撰写、网友投稿等几部分组成。
2.本站原创文字内容若未经特别声明,则遵循协议CC3.0共享协议,转载请务必注明原文链接。
3.本站部分来源于网络转载的文章信息是出于传递更多信息之目的,不意味着赞同其观点。
4.本站所有源码与软件均为原作者提供,仅供学习和研究使用。
5.如您对本网站的相关版权有任何异议,或者认为侵犯了您的合法权益,请及时通知我们处理。
火焰兔 » JavaScript 如何工作系列:声明函数的不同方式 + 5个最佳实践