J

JavaScript 函数概述

2025-05-27

JavaScript 函数概述

图像
访问 howtocodejs.com 并结合示例进行编码

我们可以整天对函数及其用途进行诗意的描述。与其如此,不如让我们探索一下有函数和没有函数的生活。

没有功能的生活

let pets = 35;
let owners = 15;
let petsPerOwner = pets / owners;
//======Pet Info Form
let answer = prompt("how many pets do you have?");
//============
 // update based on answer, add new owner
pets += answer / 1; //  coerce string into number
owners += 1; // register new owner
petsPerOwner = pets / owners;

//test
`There are now ${petsPerOwner} pets per owner at Pet Nirvana `;

Enter fullscreen mode Exit fullscreen mode

那比这个更容易读吗?

功能生活

let pets = 35;
let owners = 15;
let petsPerOwner = average(pets, owners);
let answer = prompt("how many pets do you have?");

registerPets(answer);
registerOwner();
updateAvg(); // update based on answer, add new owner
console.log(`There are now ${petsPerOwner} pets per owner at Pet Nirvana `);


function average(total, number){
  return total / number;
}
function registerPets(newNum){
  pets += Number(newNum); // register new pet(s)
}
function registerOwner(){
  ++owners;
}
function updateAvg(){
  petsPerOwner = Math.ceil(average(pets, owners)); // find new average, round up
}
Enter fullscreen mode Exit fullscreen mode

除了易读性之外,你还能发现,有了这些内置函数,我们的工作变得轻松多了。它们可以Math.ceil汇总代码并log()帮助我们调试代码。另外,请注意,第一个示例仍然只是出于必要性而使用函数。

没有函数,就没有 JavaScript,至少没有我们所熟知和喜爱的 JavaScript 的所有优秀部分。

函数的剖析

function multiply(x, y){
  return x * y;
}

function // keyword for decleration
multiply // function name
(x,y)   // parameters
return x * y; // a return statement allows
              //the function to produce value

Enter fullscreen mode Exit fullscreen mode

函数有一个或多个参数。我们可以随意命名它们,就像变量一样。不过,我们应该将参数视为引用而不是存储。我们告诉函数,我们期望用户将某个变量或数据类型插入到这个空间中。然后,我们在函数体中对参数名称进行操作。

很多时候,你需要确保返回预期的结果。否则,undefined调用函数时会产生错误。如果你打算使用函数来设置值,请添加 return 关键字。

返回

return语句可以返回任何数据类型。

数字:

return 2;
Enter fullscreen mode Exit fullscreen mode

字符串:

return "hello";
Enter fullscreen mode Exit fullscreen mode

无效的:

return null;
Enter fullscreen mode Exit fullscreen mode

不明确的:

return undefined;
Enter fullscreen mode Exit fullscreen mode

数组:

return [1,2,3];
Enter fullscreen mode Exit fullscreen mode

对象:

return {one: 1, two: 2, three: 3};
Enter fullscreen mode Exit fullscreen mode

功能:

return function(){
  return "I'm in a function";
}
Enter fullscreen mode Exit fullscreen mode

调用函数

通过在函数名称中添加参数来调用函数()。如果函数需要参数,则必须输入参数,否则会出错。

function multiply(x, y){
  return x * y;
}
multiply(2,2); // 4
Enter fullscreen mode Exit fullscreen mode

你可以在函数声明之前调用它,它仍然有效。这称为函数提升。

multiply(2,2); // 4

function multiply(x, y){
  return x * y;
}
Enter fullscreen mode Exit fullscreen mode

函数符号

当一个地标或事物在任何人类语言中具有重要意义时,通常有多种方式来表达其名称。

有趣的事实:在古典阿拉伯语中,有数百种方式来命名骆驼。

类似地,函数对于 JavaScript 来说非常重要,因此根据其使用环境,它们有许多名称。

函数声明

您有经过验证的函数声明

function greet(){
  return 'hello';
}

// we can the call or invoke this functions

greet(); // 'hello'

Enter fullscreen mode Exit fullscreen mode

函数表达式

你还有一个函数表达式。它之所以被称为函数表达式,是因为你将一个函数赋值给了一个变量:

let greet = function(){
  return 'hello';
}

// we can still call or invoke this functions

greet(); // 'hello'

Enter fullscreen mode Exit fullscreen mode

需要注意的一件重要事情是,提升不适用于函数表达式。

greet(); // undefined

let greet = function(){
  return 'hello';
}
Enter fullscreen mode Exit fullscreen mode

匿名函数

function()后面没有名称的function 关键字 ( ) 被称为匿名函数。ES6 引入了一种编写匿名函数的新方法。您可以不使用 function 关键字,而是将其删除,并=>在括号中添加箭头运算符。

let greet = ()=>{
  return 'hello';
}


Enter fullscreen mode Exit fullscreen mode

在很大程度上,引入语法差异是为了满足那些喜欢编写极简代码的纯粹主义者。不过,箭头函数确实引入了自动绑定。我们不会深入探讨技术细节,稍后会向您展示什么是自动绑定。

匿名函数用途广泛。你可以将它们设置为对象字面量中某个键的值:

let person = {
  name: "Mark",
  greet: function(){
    return 'hello' + ' ' +  this.name;   
  }
}; // end of object literal

person.greet();
Enter fullscreen mode Exit fullscreen mode

注意:在我们的匿名函数this中指的是person。我们也可以简单地写成person.name

回调函数

匿名函数也可以传入参数。这样做会将匿名函数变成所谓的回调函数

//here's a function expression
let greet = (callback, times)=>{
  for(let cnt=0; cnt < times; cnt ++){
      console.log(callback()); //it doesn't return.
                              //This will cause a side effect
  }
}


//here's our anonymous func AKA callback
greet(()=>{return 'hello'}, 3);
//we could have written it like this:
greet(function(){return 'hello'}, 3);
Enter fullscreen mode Exit fullscreen mode

注意:还记得我们讨论过函数的构造吗?定义函数时,实际上是在创建一个模型。回调函数正是利用了这一点,因为我们可以等待函数调用。我们通过附加()参数名称来告诉解释器,我们希望在函数调用时调用该函数。

闭包

函数内的函数称为闭包

// We have two functions. One is named outie and the other is named closure *wink* *wink*
function outie(){
  // this is closure's first and only outer scope
  function closure(){
   // this is closure's local scope
  }
}
Enter fullscreen mode Exit fullscreen mode

如果你曾经接触过回调,你可能已经猜到了,回调其实也是一个闭包。在它存在的某个时刻,它会在另一个函数中被调用。

Context: '
既然我们已经开始嵌套函数,就应该处理上下文。函数会创建自己的上下文,这会影响this关键字,但如果我们在匿名函数中编写闭包,this闭包就会引用我们的函数。因此,我们会得到 undefined。

以下是一个例子:

 let person = {
  name: "Mark",
  greet: function(){    
    return function(){
          return 'hello' + ' ' +  this.name;  
    }      
  }
}
// double invoke ()() can invoke a returned closure
person.greet()();// >'hello undefined'
Enter fullscreen mode Exit fullscreen mode

为了解决这个问题,开发人员只需将其设置this为一个变量来保存上下文。换句话说,我们正在绑定this。现在来看看自动绑定可能意味着什么吧?

//code excerpt
greet: function(){
  let self = this;   
  return function(){
        return 'hello' + ' ' +  self.name;  
  }      
}
//end of excerpt
Enter fullscreen mode Exit fullscreen mode

另一种解决方案是明确bind(this)调用函数的右括号。

//code excerpt
greet: function(){
  return function(){
        return 'hello' + ' ' +  this.name;  
  }.bind(this)      
}
//end of excerpt
Enter fullscreen mode Exit fullscreen mode

它看起来很丑,但是却很有效。

专业提示:还记得新的()=>语法吗?上面的例子很好地解释了为什么我们需要自动绑定。以前,你必须this像我们之前那样记住绑定变量。现在,你只需使用新的语法,哇!你就有了一个可以运行的this关键字。不妨通过重写闭包来尝试一下。

最终的解决方案是使用Es6箭头函数。

//code excerpt
greet: function(){
  let self = this;   
  return ()=>{
        return 'hello' + ' ' +  this.name;  
  }      
}
//end of excerpt
Enter fullscreen mode Exit fullscreen mode

注意:在外部匿名函数上使用箭头函数会破坏上下文。由于箭头函数会自动绑定,因此您将绑定this到对象外部的上下文person。因此,this.person这将不再起作用。

当前执行函数

调用自身的函数称为立即调用函数表达式(IIFE)

(function(){
  return 'hello'; //'hello'
}());
Enter fullscreen mode Exit fullscreen mode

您仍然可以使用其他函数执行任何操作。您可以设置参数并使用“调用器”()输入数据。

(function(name){
  return name;   // 'hi'
}("hi"));
Enter fullscreen mode Exit fullscreen mode

你可以将 IIFE 赋值给一个变量,但必须声明变量名。不过你不必调用它。

var greet =
(function(name){
  return name;   
}("hi"));

greet // 'hi'
Enter fullscreen mode Exit fullscreen mode

函数狂热

我们可以使用 IFFE 和闭包,结合匿名函数来创建一个 android。

//function expression
let android = (function(){
    //==private
    this.name = "Mark VI";
    //declaration
    function addStrings(){
       return "hello" + " " + this.name;
    }
    function setName(name){
      this.name = name;
    }
    //==public: we're just returning an object.
    return {  //anonymous functions
       setName:(name)=>{
          return setName(name);
        },    
        greet: ()=>{
            return addStrings();
        }
    }
}());//IIFE

android.setName("Raj");
android.greet(); //'Hello, I'm Raj'
Enter fullscreen mode Exit fullscreen mode

上面的代码充分利用了函数提供的所有功能,生成了一个可运行的对象。它管理自身的状态,这意味着我们所做的任何更改都将被保存。因此,如果我们设置一个新名称,并告诉机器人“欢迎”我们,它就会用这个新名称来欢迎我们。这真是太强大了!我们将在另一章中学习更多关于面向对象编程的知识。

注意:如果开发人员希望他们的代码无需通过事件触发即可运行,他们通常会使用 IFFE 包装 JavaScript 代码。

概括

跟踪所有这些不同类型的函数可能很困难,所以让我们列出不同的函数类型。

  • 声明函数
  • 匿名函数
  • 回调
  • 闭包
  • 立即调用函数表达式

挑战:编写一个利用所有这些不同功能的程序

文章来源:https://dev.to/howtocodejs/an-overview-of-javascript-functions-47id
PREV
开发人员健身指南
NEXT
从零开始的 Web 开发:CI/CD 基础设施和开发流程搜索信息、问题的相关性典型的开发流程基础设施材料