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)
-
- 严格模式下:
- 给arguments[1]赋值不会影响m的值
- 在函数种尝试重写arguments对象会导致语法错误(代码也不会执行)
(1)箭头函数中的参数