简言
学了这么久的JavaScript,函数在JavaScript中最常用之一,如果你不会函数,你就不会JavaScript。
函数就是Function对象,一个函数是可以通过外部代码调用的一个“子程序”,它是头等(first-class)对象,因为它们可以像任何其他对象一样具有属性和方法。瞧瞧它的定义,注定它能做很多事情。
**函数是函数名、参数和函数体组成,然后由function声明。**我们一般说函数是指普通函数,还有另一种函数叫做生成器函数,这个生成器比较比较高级,生成器函数在执行时能暂停,后面又能从暂停处继续执行,这里不展开描述。
函数
在 JavaScript 中,每个函数其实都是一个Function对象。函数默认返回undefined
定义函数
声明一个函数(Function对象)有很多种方式。如果一个函数中没有使用 return 语句,则它默认返回undefined。要想返回一个特定的值,可以使用return 返回。
function声明
由function声明的函数,函数名会提升这个作用域的顶部,即在函数定义前也能使用。
function name([param[, param[, ... param]]]) { statements }
- name 函数名。
- param 传递给函数的参数的名称。
- statements 组成函数体的声明语句。
函数表达式
由函数表达式创建的函数,函数名不会会提升,即必须在创建之后使用。
var myFunction = function name([param[, param[, ... param]]]) { statements }
- name 函数名,可以省略,省略了后是匿名函数。
- param 传递给函数的参数的名称。
- statements 组成函数体的声明语句。
立即调用函数(IIFE)
当函数只使用一次时,通常使用IIFE (Immediately Invokable Function Expressions)。意思是当这个js文件被执行时调用一次。
(function () {
statements;
})();
- statements 组成函数体的声明语句。
箭头函数表达式(=>)
箭头函数是函数
var fn = ([param] [, param]) => { statements } param => expression
- param 参数名称。
零参数需要用 () 表示。只有一个参数时不需要括号。(例如 foo => 1) - statements or expression
多个声明 statements 需要用大括号括起来,而单个表达式时则不需要。表达式 expression 也是该函数的隐式返回值。
Function构造函数 (不推荐)
函数(Function对象)可以用 new 操作符创建。
把 Function 的构造函数当作函数一样调用 (不使用 new 操作符) 的效果与作为 Function 的构造函数调用一样。
new Function (arg1, arg2, ... argN, functionBody)
-
arg1, arg2, … argN
函数使用零个或多个名称作为正式的参数名称。每一个必须是一个符合有效的 JavaScript 标识符规则的字符串或用逗号分隔的字符串列表,例如“x”,“theValue”或“a,b”。 -
functionBody
一个构成的函数定义的,包含 JavaScript 声明语句的字符串。
函数参数
函数参数(形参)一个重要的概念,它是函数体与外面作用域交互的媒介或桥梁。普通的参数由js各种类型定义,除此之外,它还有this、剩余参数和arguments对象。
形参
普通的参数由js各种类型定义,定义的参数可以在函数内使用,想传啥就传啥。
调用传参时,则按你定义参数的顺序传。
function fnParams(
name,
age = 18,
object = {
label: 'object形参',
},
fn = () => {},
date = new Date(),
arr = []
) {
console.log(name, age, object, fn, date, arr)
}
fnParams()
调用时不传参数,参数为undefined,有默认值则值为默认值。
arguments对象
arguments 是一个对应于传递给函数的参数的类数组对象。
arguments对象是所有(非箭头)函数中都可用的局部变量。你可以使用arguments对象在函数中引用函数的参数。
箭头函数使用arguments在浏览器环境下会报错。
function fnParams(
name,
age = 18,
object = {
label: 'object形参',
},
fn = () => {},
date = new Date(),
arr = []
) {
console.log(name, age, object, fn, date, arr)
console.log(arguments)
}
fnParams('zsk', () => {})
const fn = (name) => {
console.log(name, arguments)
}
fn('zsk')
剩余参数
剩余参数是es6的,剩余参数语法允许我们将一个不定数量的参数表示为一个数组。
如果函数的最后一个命名参数以…为前缀,则它将成为一个由剩余参数组成的真数组,其中从0(包括)到theArgs.length(排除)的元素由传递给函数的实际参数提供。
function(a, b, ...theArgs) {
// ...
}
如上,theArgs就是剩余参数,它是一个数组,包含那些没有对应形参的实参,默认值[],不能更改默认值。
let fn = function (a, ...args) {
console.log(a, args)
}
fn(1, 2, 3)
this
在绝大多数情况下,函数的调用方式决定了 this 的值(运行时绑定)。this 不能在执行期间被赋值,并且在每次函数被调用时 this 的值也可能会不同。可以使用 bind 方法来设置函数的 this 值,而不用考虑函数如何被调用的。箭头函数本身没有this,值为创建时外层上下文对象。
function fn2() {
console.log('fn2::', this)
const arrowFn = (a = 1) => {
console.log('()=>{} ::', this)
}
const fn = function (a = 1) {
console.log('fn::', this)
}
arrowFn()
fn()
let o = {
fn: fn,
}
o.fn()
}
fn2()
bind()、call() 和 apply()方法可以改变this值。
a = 1
const obj = {
a: 2,
}
function fn3() {
// 'use strict'
console.log(this.a)
return this
}
fn3()
fn3.bind(obj)()
fn3()
fn3.bind()()
fn3.call(obj, 1, 2)
fn3()
fn3.call()
fn3.apply(obj, [1, 2])
fn3()
fn3.apply()
函数体
函数体没啥说的,什么都可以写。自己都可以调用。。。,递归就是这么来的。
如果有return 的话,可以返回函数,例如实现闭包、函数柯里化、高阶函数等。
函数属性
另外,函数本身还有一些属性和方法:
- name 返回函数定义的名称。
- length 只读属性,表示函数形参的个数
- prototype 函数的原型对象
- toString() 返回函数完整的源代码字符串
结语
有了函数,js就算玩出花来,也可以有条理性。