现在我们将学习 JavaScript 中所有关于函数的知识, 从概述到小细节帮助你更好的使用 JavaScript 函数. 愚人码头注: 本文没有一句废话, 对于新手, 可以作为该知识点的入门指南, 对于有经验的开发人员可以作为一次很好的回顾.
JavaScript 中的所有内容都在函数中执行.
函数是一个自包含的代码块, 可以定义一次, 并运行任意次数.
函数可以选择接受参数, 并返回一个值.
JavaScript 中的函数是 对象, 一种特殊的对象: function objects(函数对象).
另外, 函数在 JavaScript 中是一等公民, 因为它们可以被赋值给一个值, 它们可以作为参数传递并用作返回值.
让我们从 "旧的",ES6 / ES2015 之前的语法开始. 这是一个函数声明:
- function dosomething(foo) {
- // do something
- }
在 ES6 / ES2015 流行的当下, 简称为常规函数.
可以将函数分配给变量 (这称为函数表达式):
- const dosomething = function(foo) {
- // do something
- }
命名函数表达式类似, 但在堆栈调用跟踪中更好用, 这在发生错误时很有用 - 它保存函数的名称:
- const dosomething = function dosomething(foo) {
- // do something
- }
ES6 / ES2015 引入了箭头函数, 在使用内联函数时, 它们特别适合用作参数或回调函数:
- const dosomething = foo => {
- //do something
- }
箭头函数与上面的其他函数定义有很大的不同, 我们会在后面的章节中详细介绍.
参数
一个函数可以有一个或多个参数.
- const dosomething = () => {
- //do something
- }
- const dosomethingElse = foo => {
- //do something
- }
- const dosomethingElseAgain = (foo, bar) => {
- //do something
- }
从 ES6 / ES2015 开始, 函数可以具有参数的默认值:
- const dosomething = (foo = 1, bar = 'hey') => {
- //do something
- }
这允许您在不填充所有参数的情况下调用函数:
- dosomething(3)
- dosomething()
ES2017 引入了参数的尾随逗号, 这个功能有助于减少因移动参数时丢失逗号而导致的错误 (例如, 移动中间的最后一个):
- const dosomething = (foo = 1, bar = 'hey') => {
- //do something
- }
- dosomething(2, 'ho!')
您可以将所有参数包装在一个数组中, 并在调用函数时使用展开运算符:
- const dosomething = (foo = 1, bar = 'hey') => {
- //do something
- }
- const args = [2, 'ho!']
- dosomething(...args)
使用许多参数, 记住顺序可能很困难. 这时使用对象解构这个对象允许保留参数名称:
- const dosomething = ({ foo = 1, bar = 'hey' }) => {
- //do something
- console.log(foo) // 2
- console.log(bar) // 'ho!'
- }
- const args = { foo: 2, bar: 'ho!' }
- dosomething(args)
注意这里用的是 { foo = 1, bar = 'hey' }, 用的是等号 , 不是 { foo : 1, bar : 'hey' }.
返回值
每个函数都返回一个值, 默认情况下是 undefined .
任何函数在其代码行结束时或执行流找到 return 关键字时终止执行.
当 JavaScript 遇到 return 关键字时, 它退出函数执行并将控制权交还给其调用者.
如果 return 后面跟一个值, 则该值将作为函数的结果返回:
- const dosomething = () => {
- return 'test'
- }
- const result = dosomething() // result === 'test'
您只能返回一个值.
要模拟返回多个值, 可以返回对象字面量或数组, 并在调用函数时使用解构赋值.
使用数组:
使用对象:
嵌套函数
可以在函数中定义其他函数:
- const dosomething = () => {
- const dosomethingelse = () => {}
- dosomethingelse()
- return 'test'
- }
被嵌套函数的作用域是嵌套它的函数, 不能从外部调用.
对象方法
当用作对象属性时, 函数称为方法:
- const car = {
- brand: 'Ford',
- model: 'Fiesta',
- start: function() {
- console.log(`Started`)
- }
- }
- car.start()
箭头函数中的 "this"
当箭头函数与常规函数用作对象方法时, 有一个重要的行为区别. 考虑这个例子:
- const car = {
- brand: 'Ford',
- model: 'Fiesta',
- start: function() {
- console.log(`Started ${this.brand} ${this.model}`)
- },
- stop: () => {
- console.log(`Stopped ${this.brand} ${this.model}`)
- }
- }
stop() 方法无法正常工作.
这是因为在两个函数声明风格中处理 this 的方式是不同的. this 在箭头函数中指的是封闭的函数上下文, 在这种例子中是 Windows 对象:
this, 是指使用 function() 的宿主对象
这意味着箭头函数不适合用于对象方法和构造函数 (箭头函数构造函数实际上会在调用时引发 TypeError ).
IIFE, 立即调用函数表达式
IIFE 是一个在声明后立即执行的函数:
- ;(function dosomething() {
- console.log('executed')
- })()
您可以将结果分配给变量:
- const something = (function dosomething() {
- return 'something'
- })()
它们非常方便, 因为您无需在定义后单独调用该函数.
函数提升 (Hoisting)
执行代码之前的 JavaScript 会根据某些规则对其进行重新排序.
特别需要记住的一点是函数会被移动到其作用域的顶部. 所以下面的写法是合法的:
- dosomething()
- function dosomething() {
- console.log('did something')
- }
在内部, JavaScript 在调用之前移动函数, 以及在同一作用域内找到的所有其他函数:
- function dosomething() {
- console.log('did something')
- }
- dosomething()
看下面的代码, 如果您使用命名函数表达式, 因为您正在使用 JavaScript 变量 https://www.CSS88.com/archives/10014 , 所以会发生不同的事情. 我们说的变量提升, 其实是变量声明被提升, 但不是值被提升, 因此下面的代码中不是那个函数被提升.
- dosomething()
- const dosomething = function dosomething() {
- console.log('did something')
- }
上面代码不会工作:
上面代码内部发生的事情是这样的:
- const dosomething
- dosomething()
- dosomething = function dosomething() {
- console.log('did something')
- }
let 声明也是如此. var 声明也不起作用, 但有不同的错误:
这是因为 var 声明被提升并初始化为 undefined 作为值, 而 const 和 let 被提升但未初始化.
来源: https://juejin.im/entry/5bff3c2fe51d4525b709b3bd