欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JavaScript中创建函数的多种方式

程序员文章站 2022-04-04 09:05:25
...

在JavaScript中,我们可以通过多种方式来定义一个函数。下面,我们就对这些定义函数的方式分别进行说明。

Function构造器

利用Function构造器可以创建一个新的Function对象。但是通过构造器动态创建函数,存在安全性和性能方面的问题。这种方式,我们很少,或基本上不会用到。

var addition = new Function('a', 'b', 'return a + b;');
console.log('函数名:' + addition.name); // anonymous
console.log(addition(1, 2)); // 3

此外,我们也可以将Function构造器当作函数调用(不使用new)来创建函数,这和使用new关键字的效果是一模一样的:

var addition = Function('a', 'b', 'return a + b;');
console.log('函数名:' + addition.name); // anonymous
console.log(addition(1, 2)); // 3

每个JavaScript函数实际上都是一个Function对象。我们可以通过以下代码进行验证:

(function(){}).constructor === Function // true

(()=>'').constructor === Function // true

函数声明

函数声明是我们常用的一种定义函数的方式。

function addition(a, b) {
    return a + b;
}

console.log('函数名:' + addition.name); // 函数名:addition
console.log(addition(1, 2)); // 3

注意,函数声明会被提升到封闭函数或全局范围的顶部。即我们可以在函数声明之前使用该函数:

console.log('函数名:' + addition.name); // 函数名:addition
console.log(addition(1, 2)); // 3

function addition(a, b) {
    return a + b;
}

函数表达式

函数表达式使得我们可以在表达式中定义函数。这也是我们极其常用的一种定义函数表达式的方式。

var addition = function (a, b) {
    return a + b;
};

console.log('函数名:' + addition.name); // 函数名:addition
console.log(addition(1, 2)); // 3

这种定义函数的方式也叫函数直接量

像上面我们是将一个匿名函数赋值给一个变量。此外,我们还可以使用一个命名函数赋值给一个变量:

var addition = function add(a, b) {
    return a + b;
};

console.log('函数名:' + addition.name); // 函数名:add
console.log(addition(1, 2)); // 3
console.log('函数名:' + add(1, 2)); // Uncaught ReferenceError: add is not defined

注意,这里的函数名add只能在函数体中使用,常用作递归调用:

var i = 0;
var recursion = function call() {
    console.log(++i);
    if (i < 3) {
        call();
    }
};

recursion(); // 1 2 3

当然,我们也可以使用变量名addition作为递归调用:

var i = 0;
var recursion = function call() {
    console.log(++i);
    if (i < 3) {
        recursion();
    }
};

recursion(); // 1 2 3

函数表达式与函数声明很类似,它们的主要区别是:

箭头函数

箭头函数是ES2015开始引入的一种新的定义函数的方式。我们可以将箭头函数看作是一种简写紧凑型的“函数表达式”,它和函数表达式一样都不会被提升。但与传统的函数表达式相比,箭头函数有以下几个不同点:

  • 箭头函数不绑定thisarguments
  • 箭头函数不能用作构造函数,即不能使用new来创建对象
  • 箭头函数没有prototype
var addition = (a, b) => {
    return a + b;
};

console.log('函数名:' + addition.name); // 函数名:addition
console.log(addition(1, 2)); // 3

当函数体中只有return语句时,我们还可以使用“简洁体”代替常规的“块体”:

var addition = (a, b) => a + b;

console.log('函数名:' + addition.name); // 函数名:addition
console.log(addition(1, 2)); // 3

但是注意,如果函数体中返回的是对象字面量时,需要把对象字面量包裹在小括号中。否则,大括号中的代码会被解析为代码(对象的属性名会被解析为标签)。

比如下面的函数体会被解析为代码运行,故没有返回值:

var func = () => { foo: 1 };
console.log(func()); // undefined

又比如下面的函数体因被解析为代码,故其中的函数声明必须要指定函数名称:

var func = () => { foo: function() {} };
// Uncaught SyntaxError: Function statements require a function name

对于上面的两个例子,正确的写法是用小括号包裹函数体。

例子一:

var func = () => ({ foo: 1 });
console.log(func()); // {foo: 1}

例子二:

var func = () => ({ foo: function() {} });
console.log(func()); // {foo: ƒ}

ES2015还引入了class关键字,虽然它的实现只是一个语法糖,但配合箭头函数使用,就可以让我们清楚地知道是在定义一个函数还是在定义一个类,这可以避免我们理解上的混乱。