一、ES5 的函数
1. 函数声明的两种方法
- function 声明
function f() {}
f();
- 函数表达式
var f = function() {}
f();
2. 函数的重复声明
如果同一个函数多次声明,那么后面的会覆盖前面的声明。另外,注意函数的变量提升。
// 相同声明方式,变量提升等同无效,因此后面会覆盖前面的,输出 2。
function f() { console.log(1); }
function f() { console.log(2); }
f(); // 2
// 函数声明优于函数表达式,执行时后面的表达式又会覆盖函数声明,输出 1。
var f = function() { console.log(1); }
function f() { console.log(2); }
f(); // 1
3. 第一等公民
js 将函数看作一种值,与数值、字符串地位相等,凡是可以使用值的地方就能使用函数。例如把函数赋值给变量和对象的属性。
function add (x, y) { return x + y}
var sum = add;
sum();
4. 传递方式
函数参数如果是原始类型值,传递方式是按值传递,在函数体内部修改参数值、不会影响到函数外部。
如果是复杂类型值(函数、数组、对象),传递方式是传址传递,在函数内部修改参数将会影响到原始值;另外如果函数内部是直接替换掉了整个参数,这种情况不会影响原始值。
5. 同名参数
如果参数同名,则取的是最后出现的那个值。
function f(a, a) { console.log(a); }
f(1, 2); // 2
// 第 2 个自动赋值 undefined
function f(a, a) { console.log(a); }
f(1); // undefined
二、ES6 的函数扩展
1. 可设置参数的默认值
ES6 允许为函数的参数设置默认值。
function f(x, y = 'hello') {}
function f(a) {
let a = 1; // Error
console.log(a);
}
f(2);
「参数变量是默认声明的」,所以不能用 let 或 const 再次声明,会报错。 如果用 var 就相当于变量的重复声明,覆盖前面的值,输出 1。
注意:var 多次重复声明一个变量时,那么后面的声明都是无效的。
2. 参数作用域
var x = 1;
function f(x, y = x) { // 声明 f 时,参数会形成一个单独的作用域
console.log(y);
}
f(2); // 2
一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域。等函数初始化结束后,这个作用域就会消失。这个行为,在不设置参数默认值时,并不会出现。
下面这种情况,x 在函数作用域中没有定义,所以指向外层的全局变量 x。
let x = 1;
function f(y = x) {
console.log(y);
}
f(); // 1
3. 扩展运算符
用来获取函数的多余参数,rest 参数搭配的是一个数组,且 ... 参数之后不能再有其他参数。
4. 箭头函数的注意点/与普通函数的区别
-
箭头函数没有自己的 this,只能从上层作用域继承。所以不适用箭头函数的场合有:
- 当对象的方法内部包含 this 时,那么该方法不能用箭头函数定义。
- 需要动态 this 时,也不应该使用箭头函数。
-
没有
原型prototype,也不能当构造函数(this指向继承外层作用域,不会改变)、不能使用 new 命令,否则会报错不是构造函数。 -
没有自己的 arguments 对象(有没有取决于副作用域)。
-
不能用作 Generator 函数,不能使用
yield命令。