JavaScript 中的函数(一)函数的形式有哪些
本文最后更新于 283 天前,如有失效请评论区留言。

前言

函数作为 JavaScript 的一等公民,这篇文章主要梳理下 JavaScript 中有多少种函数

在 JavaScript 中,每个函数其实都是一个Function对象

构造函数

使用 new Function 创建一个函数

var multiply = new Function("x", "y", "y", "return x * y");
console.log(multiply(2,3,4))

函数声明

function getName() {
  console.log("gavin");
}

getName()

//输出
> "gavin"

函数声明具有变量提升的特性,变量提升是变量和函数声明会被提升到它们所在作用域的顶部,但只有声明会被提升,而赋值不会。

所以 getName() 可以在声明之前调用,也可以放在声明之后

函数表达式

具名函数表达式

与函数声明类似,我们把函数赋值给一个变量,这个就是函数表达式

var showName = function getName() {
  console.log("gavin");
};

console.log(showName.name)

// 输出
> getName

具名函数表达式可以用于在函数内部代指其本身,如递归调用自己,或者在调试器堆栈跟踪中识别该函数

匿名函数表达式

var showName = function() {
  console.log("gavin");
};

showName()
console.log(showName.name)

//输出
> gavin
> showName

JavaScript 中的函数表达式没有提升,不像函数声明会提升到作用域最前边,所以不能这样去用

showName()

var showName = function() {
  console.log("gavin");
};

//输出 
> TypeError: showName is not a function

被函数表达式赋值的那个变量会有一个 name 属性,如果你把这个变量赋值给另一个变量的话,这个 name 属性的值也不会改变。
如果函数是一个匿名函数,那 name 属性的值就是被赋值的变量的名称(隐藏值)。
如果函数不是匿名的话,那 name 属性的值就是这个函数的名称(显性值)。

立即执行函数

IIFE(Immediately Invoked Function Expression),这种定义的函数允许在函数定义的时候立即执行

(function () {
  console.log("gavin");
})()

// 输出
> gavin

函数分为两块,

  1. 第一部分是里面的匿名函数(也可以是具名函数),并且用() 运算符闭合起来,将函数声明变成一个表达式
  2. 第二部分是外面的 (),作用是创建一个立即执行函数表达式,通过它,JavaScript 引擎将立即执行该函数。

立即执行函数为什么会存在?

创建私有作用域

因为我们的程序可能包括很多来自不同源文件的函数和全局变量,因此限制全局变量的数量非常重要。如果我们有一些不再使用的初始化代码,我们可以使用 IIFE 模式

例如,立即执行函数外面,我们定义了一个全局变量,匿名函数里面我们定义的变量不会干扰到外部变量

var a = 3;

(function () {
  var a = 2
  console.log("gavin");
})()

console.log(a)

// 输出
> gavin
> 3

防止变量提升

下面这段代码在 ES6 之前,是一个比较常见的问题,当点击按钮是,打印的都是 3,原因就是 var 声明的变量 i 在全局作用域或函数作用域中是共享的,当点击按钮的时候使用还是全局变量 i,此时变量 i 已经变成了 3

for (var i = 0; i < 3; i++) {
  const button = document.createElement("button");
  button.innerText = `Button ${i}`;
  button.onclick = function () {
    console.log(i);
  };
  document.body.appendChild(button);
}
console.log(i);

// 输出
> 3

怎么解决这个问题呢,ES6 之后直接使用 let 定义变量 i ,这样每次迭代都会创建一个新的变量,当然我们也可以使用立即执行函数来解决这个问题

for (var i = 0; i < 3; i++) {
  const button = document.createElement("button");
  button.innerText = `Button ${i}`;
  // IIFE 写法
  (function (ii){
    button.onclick = function() {
      console.log(ii)
    }
  })(i)
  document.body.appendChild(button);
}

console.log(i);

可以看到里面的这段 IIFE 函数,这样每一个按钮都有自己的作用域,ii 参数捕获了当前迭代的 i 值,避免了共享变量导致的问题

尽管 IIFE 在特定情况下很有用,但在现代 JavaScript 中,由于引入了 letconst 关键字以及模块化系统,使用 IIFE 的需求已经减少。尤其是在 ES6 及以后的版本中,块级作用域的引入减少了对 IIFE 的依赖。

函数表达式的形式

如果你遇到下面这些写法,现在能区分它们是什么类型的了

// 函数声明
function foo() {}

// 函数表达式
(function bar() {});

// 函数表达式
x = function hello() {};

if (x) {
  // 函数表达式
  function world() {}
}

// 函数声明
function a() {
  // 函数声明
  function b() {}
  if (0) {
    //函数表达式
    function c() {}
  }
}

方法 or 函数?

当一个函数是一个对象的属性时,称之为方法

从 ECMAScript 2015 开始,在对象初始器中引入了一种更简短定义方法的语法,这是一种把方法名直接赋给函数的简写方式

var obj = {
  getName: function () {
    return "gavin"
  },
  setName: function () {
    /* code */
  },
};
console.log(obj.getName());

// 输出
> "gavin"

上面这种使用匿名函数,也可以用具名函数,跟上面的函数表达式是一样的用法

var obj = {
  getName: function showName () {
    return "gavin"
  },
  setName: function () {
    /* code */
  },
};
console.log(obj.getName.name);
console.log(obj.setName.name);

// 输出
> "showName" 
> "setName"

也可以被简写如下

var obj = {
  getName() {
    return "gavin"
  },
  setName() {
    /* code */
  },
};

这种情况下是不能使用匿名函数的,必须是具名函数

以上就是本节的全部内容,主要介绍了几种常见的函数形式,希望后面在实际程序代码中遇到这样的写法不会迷茫

版权声明:除特殊说明,博客文章均为Gavin原创,依据CC BY-SA 4.0许可证进行授权,转载请附上出处链接及本声明。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇