JS—函数概述

 1.定义

函数是对象,所以函数名就是指向函数对象的指针

(1)函数声明

function add (n,m){
  return n+m
}

(2)函数表达式

let add = function(n, m) { 
 return n + m; 
};

函数表达式声明和函数声明方式几乎等价,不过还是有些不同的,如使用函数声明方式声明的函数:

  • 函数声明提升:函数声明会在任何代码执行之前先被读取并添加到执行上下文。

(3)箭头函数

let add = (n, m)=> { 
 return n + m; 
}

(4)Function构造函数

这个构造函数接收任意多个字符串参数,最后一个参数始终会被当成函数体,而之前的参数都是新函数的参数
let sum = new Function("num1", "num2", "return num1 + num2"); // 不推荐
不推荐使用这种语法来定义函数,因为这段代码会被解释两次:
  • 第一次是把它当作常规ECMAScript代码
  • 第二次是解释传给构造函数的字符串

这样会影响性能

注意:

  • 如果是访问函数而不是调用函数,那就必须不带括号

2.箭头函数——ES6

任何可以使用函数表达式的地方,都可以使用箭头函数

箭头函数简洁的语法非常适合嵌入函数的场景:
1 let ints = [1, 2, 3]; 
2 console.log(ints.map(function(i) { return i + 1; })); // [2, 3, 4] 
3 console.log(ints.map((i) => { return i + 1 })); // [2, 3, 4]

箭头函数的语法:

  • 如果只有一个参数,可以省略括号,多个参数必须加括号
    • let l = e =>{ return e }
  • 如果语句只有一条return语句,则可以省略return和函数体的{}
    • let l = e => e

注意:

  • 箭头函数不能使用arguments、super、new.target
  • 也不能用作构造函数
  • 没有prototype属性

3.函数名

因为函数名就是指向函数的指针,所以它们跟其他包含对象指针的变量具有相同的行为。这意味着一个函数可以有多个名称,如下所示:
1 function sum(num1, num2) { 
2  return num1 + num2; 
3 } 
4 console.log(sum(10, 10)); // 20 
5 let anotherSum = sum; 
6 console.log(anotherSum(10, 10)); // 20 
7 sum = null; 
8 console.log(anotherSum(10, 10)); // 20 

ES6的所有函数对象都会暴露一个只读的name属性,其中包含关于函数的信息。多数情况下,这个属性种保存的就是一个函数标识符,或者说是一个字符串化的变量名。如果是使用Function构造函数创建的,会被标识为"anonymous":

1 function foo (){}
2 let bar = function(){}
3 let baz = ()=> {}
4 
5 console.log(foo.name);  // foo
6 console.log(bar.name);  // bar
7 console.log(baz.name);  // baz
8 console.log((()=>{}).name);  // 空字符串
9 console.log((new Function()).name);  // anonymous(匿名的)

如果函数是一个获取函数(getter)、设置函数(setter),或者使用bind()实例化,那么标识符前面会加上一个前缀

 1 function foo() {} 
 2 console.log(foo.bind(null).name); // bound foo 
 3 let dog = { 
 4  years: 1, 
 5  get age() { 
 6  return this.years; 
 7  }, 
 8  set age(newAge) { 
 9  this.years = newAge; 
10  } 
11 } 
12 let propertyDescriptor = Object.getOwnPropertyDescriptor(dog, 'age'); 
13 console.log(propertyDescriptor.get.name); // get age 
14 console.log(propertyDescriptor.set.name); // set age

4.参数

  • JS不关心传入的参数个数,也不关心参数的数据类型。
  • 主要是因为 ECMAScript 函数的参数在内部表现为一个数组。函数被调用时总会接收一个数组,但函数并不关心这个数组中包含什么。如果数组中什么也没有,那没问题;如果数组的元素超出了要求,那也没问题。
    在使用 function 关键字定义(非箭头)函数时,可以在函数内部访问 arguments 对象,从中取得传进来的每个参数值。
  • arguments 对象是一个类数组对象(但不是 Array 的实例),因此可以使用中括号语法访问其中的
    元素(第一个参数是 arguments[0],第二个参数是 arguments[1])。而要确定传进来多少个参数,
    可以访问 arguments.length 属性。

 arguments对象的值始终会与对应的参数同步:

1 function foo (n,m){
2     arguments[1] = 12
3     console.log( m );  // 12
4     console.log( arguments[1] );  // 12
5 }
6 
7 foo(1,2)

注意:

  • 这并不意味这两者访问同一个内存地址,只会保持同步而已
  • 如果只传了一个参数,然后把 arguments[1]设置为某个值,那么这个值并不会反映到第二个命名参数。这是因为 arguments 对象的长度是根据传入的参数个数,而非定义函数时给出的命名参数个数确定的。
    • 1 function foo (n,m){
      2     arguments[1] = 12
      3     console.log( m );  // undefined
      4     console.log( arguments[1] );  // 12
      5 }
      6 
      7 foo(1)
  • JS种所有的参数都是按值传递的,不可能按引用传递参数。如果把对象作为参数传递,那么传递的值就是这个对象的引用
  • 严格模式下:
    • 给arguments[1]赋值不会影响m的值
    • 在函数种尝试重写arguments对象会导致语法错误(代码也不会执行)

(1)箭头函数中的参数

 箭头函数中的参数无法通过arguments关键字访问,只能通过定义的命名参数访问

1 let foo = (a,b)=>{
2     console.log(arguments); 
3 }
4 
5 foo(1,2)  // arguments is not defined

5.没有重载

ECMAScript 函数不能像传统编程那样重载。在其他语言比如 Java 中,一个函数可以有两个定义,只要签名(接收参数的类型和数量)不同就行。如前所述,ECMAScript 函数没有签名,因为参数是由包含零个或多个值的数组表示的。没有函数签名,自然也就没有重载。
如果在 ECMAScript 中定义了两个同名函数,则后定义的会覆盖先定义的。
1 function add(n){
2     return n + 1
3 }
4 
5 function add(n){
6     return n + 2
7 }
8 
9 console.log(add(1));  // 3

模拟重载

可以通过检查参数的类型和数量,然后执行不同的逻辑来模拟函数重载。

 1 function add(){
 2     if(arguments.length===1){
 3         return arguments[0]
 4     }else if(arguments.length==2){
 5         return arguments[0] + arguments[1]
 6     }
 7 }
 8 
 9 console.log(add(1));  // 1
10 console.log(add(1,2));  // 3
原文地址:https://www.cnblogs.com/codexlx/p/14334126.html