ES6 - 函数

函数是可读、可维护和可重用代码的构建块。函数使用 function 关键字定义。以下是定义标准函数的语法。

function function_name() {
    // function body
}

要强制执行函数,必须调用它。这称为函数调用。以下是调用函数的语法。

function_name()

示例:简单函数定义

//定义一个函数
function test() {
    console.log("function called")
}
//调用函数
test()

该示例定义了一个函数 test()。一对分隔符({ })定义函数主体。它也被称为函数作用域。必须调用函数才能强制执行该函数。

成功执行上述代码后将显示以下输出。

function called

函数分类

函数可分为返回函数和参数化函数。

返回函数

函数还可将值连同控制权一起返回给调用者。此类函数称为返回函数。

以下是返回函数的语法。

function function_name() {
    //statements
    return value;
}
  • 返回函数必须以 return 语句结尾。

  • 函数最多可返回一个值。换句话说,每个函数只能有一个返回语句。

  • 返回语句应该是函数中的最后一条语句。

以下代码片段是返回函数的示例 −

function retStr() { 
   return "hello world!!!" 
}  
var val = retStr() 
console.log(val) 

上述示例定义了一个函数,该函数向调用者返回字符串"hello world!!!"。成功执行上述代码后将显示以下输出。

hello world!!!

参数化函数

参数是一种将值传递给函数的机制。参数构成函数签名的一部分。参数值在函数调用期间传递给函数。除非明确指定,否则传递给函数的值的数量必须与定义的参数数量匹配。

以下是定义参数化函数的语法。

function func_name( param1,param2 ,…..paramN) {   
   ...... 
   ...... 
}

示例 − 参数化函数

示例定义了一个函数 add,它接受两个参数 n1n2 并打印它们的和。调用该函数时,参数值将传递给该函数。

function add( n1,n2) { 
   var sum = n1 + n2 
   console.log("The sum of the values entered "+sum) 
} 
add(12,13) 

成功执行上述代码后将显示以下输出。

The sum of the values entered 25

默认函数参数

在 ES6 中,如果未向函数传递任何值或函数未定义,则允许使用默认值初始化函数参数。以下代码说明了这一点。

function add(a, b = 1) {
    return a+b;
}
console.log(add(4))

上述函数默认将 b 的值设置为 1。除非明确传递了值,否则函数将始终认为参数 b 具有值 1。成功执行上述代码后,将显示以下输出。

5

如果函数明确传递值,则参数的默认值将被覆盖。

function add(a, b = 1) {
    return a + b;
}
console.log(add(4,2))

上述代码将参数 b 的值明确设置为 2,从而覆盖其默认值。成功执行上述代码后,将显示以下输出。

6

为了更好地理解,让我们考虑以下示例。

示例 1

以下示例显示了一个接受两个参数并返回其总和的函数。第二个参数的默认值为 10。这意味着,如果没有向第二个参数传递任何值,则其值将为 10。

<script>
   function addTwoNumbers(first,second = 10){
      console.log('first parameter is :',first)
      console.log('second parameter is :',second)
      return first+second;
   }

   console.log("case 1 sum:",addTwoNumbers(20)) // no value
   console.log("case 2 sum:",addTwoNumbers(2,3))
   console.log("case 3 sum:",addTwoNumbers())
   console.log("case 4 sum",addTwoNumbers(1,null))//null passed
   console.log("case 5 sum",addTwoNumbers(3,undefined))
</script>

上述代码的输出将如下所示 −

first parameter is : 20
second parameter is : 10
case 1 sum: 30
first parameter is : 2
second parameter is : 3
case 2 sum: 5
first parameter is : undefined
second parameter is : 10
case 3 sum: NaN
first parameter is : 1
second parameter is : null
case 4 sum 1
first parameter is : 3
second parameter is : 10
case 5 sum 13

示例 2

<script>
   let DEFAULT_VAL = 30
      function addTwoNumbers(first,second = DEFAULT_VAL){
         console.log('first parameter is :',first)
         console.log('second parameter is :',second)
         return first+second;
      }
      console.log("case 1 sum",addTwoNumbers(1))
      console.log("case 2 sum",addTwoNumbers(3,undefined))
</script>

上述代码的输出将如下所示 −

first parameter is : 1
second parameter is : 30
case 1 sum 31
first parameter is : 3
second parameter is : 30
case 2 sum 33

剩余参数

剩余参数类似于 Java 中的变量参数。剩余参数不限制可以传递给函数的值的数量。但是,传递的值必须全部属于同一类型。换句话说,剩余参数充当同一类型的多个参数的占位符。

要声明剩余参数,参数名称必须以三个句点作为前缀,称为扩展运算符。以下示例说明了这一点。

function fun1(...params) { 
   console.log(params.length); 
}  
fun1();  
fun1(5); 
fun1(5, 6, 7); 

成功执行上述代码后将显示以下输出。

0 
1 
3

注意 − 剩余参数应位于函数参数列表的最后。

匿名函数

未绑定到标识符(函数名)的函数称为匿名函数。这些函数在运行时动态声明。匿名函数可以接受输入并返回输出,就像标准函数一样。匿名函数通常在初始创建后不可访问。

可以为变量分配匿名函数。这样的表达式称为函数表达式

以下是匿名函数的语法。

var res = function( [arguments] ) { ... } 

示例 − 匿名函数

var f = function(){ return "hello"} 
console.log(f()) 

成功执行上述代码后将显示以下输出。

hello 

示例 − 匿名参数化函数

var func = function(x,y){ return x*y }; 
function product() { 
   var result; 
   result = func(10,20); 
   console.log("The product : "+result) 
} 
product()

成功执行上述代码后将显示以下输出。

The product : 200 

函数构造函数

函数语句并不是定义新函数的唯一方法;您可以使用 Function() 构造函数和 new 运算符动态定义函数。

以下是使用 Function() 构造函数和 new 运算符创建函数的语法。

var variablename = new Function(Arg1, Arg2..., "Function Body");

Function() 构造函数需要任意数量的字符串参数。最后一个参数是函数的主体 - 它可以包含任意 JavaScript 语句,彼此之间用分号分隔。

Function() 构造函数不会传递任何为其创建的函数指定名称的参数。

示例 − 函数构造函数

var func = new Function("x", "y", "return x*y;"); 
function product() { 
   var result; 
   result = func(10,20); 
   console.log("乘积 : "+result)
} 
product()

在上面的例子中,Function() 构造函数用于定义一个匿名函数。该函数接受两个参数并返回它们的乘积。

成功执行上述代码后将显示以下输出。

乘积:200

递归和 JavaScript 函数

递归是一种通过让函数反复调用自身直到得出结果来迭代操作的技术。当您需要在循环中使用不同的参数反复调用同一函数时,最好使用递归。

Example − Recursion

function factorial(num) { 
   if(num <= 0) { 
      return 1; 
   } else { 
      return (num * factorial(num-1)  ) 
   } 
} 
console.log(factorial(6)) 

在上面的例子中,函数调用自身。成功执行上述代码后将显示以下输出。

720

示例 − 匿名递归函数

(function() { 
   var msg = "Hello World" 
   console.log(msg)
})()

该函数使用一对括号 () 调用自身。成功执行上述代码后将显示以下输出。

Hello World

Lambda 函数

Lambda 在编程中指的是匿名函数。Lambda 函数是一种表示匿名函数的简洁机制。这些函数也称为 箭头函数

Lambda 函数 - 剖析

Lambda 函数有 3 个部分 −

  • 参数 −函数可以有参数。

  • 粗箭头符号/lambda 符号 (=>):也称为转到运算符。

  • 语句 − 表示函数的指令集。

提示 − 按照惯例,建议使用单个字母参数,以实现紧凑而精确的函数声明。

Lambda 表达式

它是一个指向一行代码的匿名函数表达式。以下是其语法。

([param1, parma2,…param n] )=>statement;

示例 − Lambda 表达式

var foo = (x)=>10+x 
console.log(foo(10)) 

示例声明了一个 lambda 表达式函数。该函数返回 10 和传递的参数之和。

成功执行上述代码后将显示以下输出。

20

Lambda 语句

这是一个指向代码块的匿名函数声明。当函数体跨越多行时使用此语法。以下是相同的语法。

( [param1, parma2,…param n] )=> {
    //代码块
}

示例 − Lambda 语句

var msg = ()=> { 
   console.log("function invoked") 
} 
msg() 

函数的引用被返回并存储在变量 msg 中。成功执行上述代码后将显示以下输出。

function  invoked 

语法变化

单个参数的可选括号。

var msg = x=> { 
   console.log(x) 
} 
msg(10)

单个语句的可选括号。空括号表示无参数。

var disp = ()=>console.log("Hello World")
disp();

函数表达式和函数声明

函数表达式和函数声明不是同义词。与函数表达式不同,函数声明受函数名称约束。

两者之间的根本区别在于,函数声明在执行之前进行解析。另一方面,函数表达式仅在脚本引擎在执行过程中遇到时才进行解析。

当 JavaScript 解析器在主代码流中看到一个函数时,它会假定函数声明。当函数作为语句的一部分出现时,它就是函数表达式。

函数提升

与变量一样,函数也可以提升。与变量不同,函数声明在提升时会提升函数定义,而不仅仅是提升函数名称。

以下代码片段说明了 JavaScript 中的函数提升。

hoist_function();  
function hoist_function() { 
   console.log("foo"); 
} 

成功执行上述代码后将显示以下输出。

foo 

但是,函数表达式不能被提升。以下代码片段说明了这一点。

hoist_function(); // TypeError: hoist_function() 不是函数
var hoist_function() = function() {
    console.log("bar");
};

立即调用函数表达式

立即调用函数表达式 (IIFE) 可用于避免在块内提升变量。它允许公共访问方法,同时保留函数内定义的变量的隐私。此模式称为自执行匿名函数。以下两个示例更好地解释了这一概念。

示例 1:IIFE

var main = function() { 
   var loop = function() { 
      for(var x = 0;x<5;x++) {
         console.log(x); 
      } 
   }(); 
   console.log("x can not be accessed outside the block scope x value is :"+x); 
} 
main();

示例 2 : IIFE

var main = function() { 
   (function() { 
      for(var x = 0;x<5;x++) { 
         console.log(x); 
      } 
   })(); 
   console.log("x can not be accessed outside the block scope x value is :"+x); 
} 
main();

两个示例都将呈现以下输出。

0 
1 
2 
3 
4 
Uncaught ReferenceError: x is not define

生成器函数

当调用普通函数时,控制权将由被调用函数控制,直到它返回。使用 ES6 中的生成器,调用函数现在可以控制被调用函数的执行。生成器就像一个普通函数,除了 −

  • 该函数可以在任何时候将控制权交还给调用者。

  • 当你调用生成器时,它不会立即运行。相反,你会得到一个迭代器。当你调用迭代器的下一个方法时,该函数会运行。

生成器通过在 function 关键字后加上星号来表示;否则,它们的语法与常规函数相同。

以下示例说明了相同的内容。

"use strict"
function* rainbow() {
	// 星号将其标记为生成器
   yield 'red'; 
   yield 'orange'; 
   yield 'yellow'; 
   yield 'green'; 
   yield 'blue'; 
   yield 'indigo'; 
   yield 'violet'; 
} 
for(let color of rainbow()) { 
   console.log(color); 
} 

生成器支持调用者和被调用函数之间的双向通信。这是通过使用 yield 关键字来实现的。

请考虑以下示例 −

function* ask() { 
   const name = yield "你的名字是什么?"; 
   const sport = yield "你最喜欢的运动是什么?"; 
   return `${name}'s 最喜欢的运动是 ${sport}`; 
}  
const it = ask(); 
console.log(it.next()); 
console.log(it.next('Ethan'));  
console.log(it.next('Cricket')); 

生成器函数的顺序如下 −

  • 生成器在暂停状态下启动;返回迭代器。

  • it.next() 产生"你的名字是什么"。生成器暂停。这是通过yield关键字完成的。

  • 调用it.next("Ethan")将值Ethan分配给变量name并产生"你最喜欢的运动是什么?"生成器再次暂停。

  • 调用it.next("Cricket")将值Cricket分配给变量sport并执行后续的返回语句。

因此,上述代码的输出将是 −

{
    value: '你叫什么名字?', done: false
}
{
    value: '你最喜欢的运动是什么?', done: false
}
{
    value: 'Ethan 最喜欢的运动是板球', done: true
}

注意 − 生成器函数不能使用箭头函数表示。

箭头函数

ES 中引入的箭头函数有助于以简洁的方式在 JavaScript 中编写函数。现在让我们详细了解一下。

ES5 和匿名函数

JavaScript 大量使用匿名函数。匿名函数是没有附加名称的函数。匿名函数在函数回调期间使用。以下示例说明了 ES5 中匿名函数的使用 −

<script>
   setTimeout(function(){
      console.log('Learning at TutorialsPoint is fun!!')
   },1000)
</script>

上述示例将匿名函数作为参数传递给预定义的 setTimeout() 函数。setTimeout() 函数将在 1 秒后回调匿名函数。

1 秒后显示以下输出 −

Learning at TutorialsPoint is fun!!

箭头函数语法

ES6 引入了 箭头函数 的概念,以简化 匿名函数 的使用。箭头函数分为 3 个部分,如下所示 −

  • 参数 − 箭头函数可以有参数

  • 粗箭头符号 (=>) −它也被称为转到运算符

  • 语句 − 表示函数的指令集

提示 − 按照惯例,鼓励使用单个字母参数进行紧凑而精确的箭头函数声明。

语法

//指向单行代码的箭头函数
()=>some_expression

OR

//指向代码块的箭头函数
()=> { //一些语句 }`

//带参数的箭头函数
(param1,param2)=>{//一些语句}

示例:ES6 中的箭头函数

以下示例使用箭头函数定义两个函数表达式 addisEven

<script>
   const add = (n1,n2) => n1+n2
   console.log(add(10,20))

   const isEven = (n1) => {
      if(n1%2 == 0)
         return true;
      else
         return false;
   }
   console.log(isEven(10))
</script>

上述代码的输出将如下所示 −

30
true

Array.prototype.map() 和箭头函数

在下面的示例中,箭头函数作为参数传递给 Array.prototype.map() 函数。 map() 函数对数组中的每个元素执行箭头函数。本例中的箭头函数显示数组中的每个元素及其索引。

<script>
   const names = ['TutorialsPoint','Mohtashim','Bhargavi','Raja']
   names.map((element,index)=> {
      console.log('inside arrow function')
      console.log('index is '+index+' element value is :'+element)
   })
</script>

上述代码的输出如下所示 −

inside arrow function
index is 0 element value is :TutorialsPoint
inside arrow function
index is 1 element value is :Mohtashim
inside arrow function
index is 2 element value is :Bhargavi
inside arrow function
index is 3 element value is :Raja

示例:window.setTimeout() 和箭头函数

以下示例将箭头函数作为参数传递给预定义的 setTimeout() 函数setTimeout() 函数将在 1 秒后回调箭头函数。

<script>
   setTimeout(()=>{
      console.log('Learning at TutorialsPoint is fun!!')
   },1000)
</script>

1 秒后显示以下输出 −

Learning at TutorialsPoint is fun!!

箭头函数和"this"

如果我们在箭头函数内部使用 this 指针,它将指向封闭的词法作用域。这意味着箭头函数在调用时不会创建新的 this 指针 实例。箭头函数利用其封闭作用域。为了理解这一点,让我们看一个例子。

<script>
   //构造函数
   function Student(rollno,firstName,lastName) {
      this.rollno = rollno;
      this.firstName = firstName;
      this.lastName = lastName;
      this.fullNameUsingAnonymous = function(){
         setTimeout(function(){
            //创建此的新实例,隐藏此的外部范围
            console.log(this.firstName+ " "+this.lastName)
         },2000)
      }
      this.fullNameUsingArrow = function(){
         setTimeout(()=>{
            //使用外部范围的这个实例
            console.log(this.firstName+ " "+this.lastName)
         },3000)
      }
   }
   const s1 = new Student(101,'Mohammad','Mohtashim')
   s1.fullNameUsingAnonymous();
   s1.fullNameUsingArrow();
</script>

当匿名函数与 setTimeout() 一起使用时,该函数将在 2000 毫秒后被调用。将创建一个新的 "this" 实例,它将遮蔽 Student 函数的实例。因此,this.firstNamethis.lastName 的值将为 undefined。该函数不使用词法作用域或当前执行的上下文。可以使用 箭头函数 解决此问题。

上述代码的输出将如下所示 −

undefined undefined
Mohammad Mohtashim