基础:函数

148 阅读3分钟

一、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. 箭头函数的注意点/与普通函数的区别

  1. 箭头函数没有自己的 this,只能从上层作用域继承。所以不适用箭头函数的场合有:

    • 对象的方法内部包含 this 时,那么该方法不能用箭头函数定义。
    • 需要动态 this 时,也不应该使用箭头函数。
  2. 没有原型prototype,也不能当构造函数(this指向继承外层作用域,不会改变)、不能使用 new 命令,否则会报错不是构造函数

  3. 没有自己的 arguments 对象(有没有取决于副作用域)。

  4. 不能用作 Generator 函数,不能使用 yield 命令。