JavaScript 函数
定义
function
是被设计为执行特定任务的代码块
- 函数像其他正常值一样,可以赋值给变量、传递给另一个函数,或从其它函数返回,这种函数叫做头等函数。 在 JavaScript 中,所有函数都是头等函数(first class)
- 将函数作为参数或返回值的函数叫作高阶函数
- 作为参数的函数称为回调函数
- 在函数中返回一个对象的函数称为工厂函数
一个完整的函数由function关键字
、函数名
、参数列表
、函数体
组成,示例如下:
js
function sum(a, b) {
return a + b
}
使用函数时,直接通过函数名()
来调用,声明的函数必须调用才能真正被执行
js
sum(1, 2) // 3
函数使用中涉及到的参数有两种:
- 形参:声明函数时括号内的参数
- 实参:调用函数时括号内的参数
函数形参中,还涉及参数默认值的概念:即不传值时,参数默认有值而非undefined
js
// es6新增
function sum(x = 0, y = 0) {
return x + y
}
// es5
function sum(x, y) {
x = x || 0
y = y || 0
return x + y
}
函数体中,由return
关键字来返回结果(函数会立即中断执行),返回值包括三种:
- 正常值
- 函数
undefined
(无return
关键字)
js
// 返回正常值
function add(a, b) {
return a + b // 返回正常值数据,即两个数的和
}
// 返回函数
function createAdder(x) {
return function(y) {
return x + y // 返回另一个函数,该函数接受一个参数并返回与x的和
}
}
// 无return关键字, 默认返回undefined
function doSomething() {
// 函数体中没有 return 语句
console.log('Doing something...')
}
aguments与rest
函数形参又分为两种:动态参数、剩余参数
动态参数(arguments
)
arguments
是一个伪数组,只存在于函数中(不包括箭头函数)arguments
用于动态获取函数的实参
js
function sum() {
let sum = 0
for (let i = 0; i < arguments.length; i++) {
sum += arguments[i]
}
return sum
}
// arguments只接受多个参数,其他传参方法无效
console.log(sum(1, 4, 7, 2, 5, 8, 3, 6, 9)) // 45
剩余参数(rest
)
剩余参数允许我们将一个不定数量的参数表示为一个数组
...
是语法符号,置于最末函数形参之前,用于获取剩余的实参,是一个真数组
js
function getSum(...other) {
console.log(other) // [1,2,3]
}
getSum(1, 2, 3)
// 拓展写法
function getSum(a, b, ...other) {
console.log(a) // 1
console.log(b) // 2
console.log(other) // [3, 4, 5, 6]
}
getSum(1, 2, 3, 4, 5, 6)
length与name
在 JavaScript 中,函数实例也有一个length
属性,返回函数的参数长度,即函数定义中正式参数的数量
js
function greet(name, greeting) {
console.log(greeting + ', ' + name + '!')
}
console.log(greet.length) // 2
有几个特殊情况:
- 宿主对象:在某些情况下,如使用浏览器的宿主对象(如DOM元素的事件处理函数),
length
属性可能不会按照预期工作,因为这些对象不是通过 JavaScript 函数构造的 - 默认参数:如果函数参数中有默认值,
length
属性将不包括那些参数
js
function greet(name, greeting = 'Hello') {
console.log(greeting + ', ' + name + '!')
}
// length不包括有默认值的参数
console.log(greet.length) // 1
- 剩余参数:如果函数使用了剩余参数,
length
属性将不包括这个参数
js
function greetAll(...names) {
names.forEach(name => console.log('Hello, ' + name + '!'))
}
console.log(greetAll.length) // 0
函数的name
属性 (只读) 表示函数在创建时指定的名称。如果函数是匿名函数,则名称可以是 anonymous
或 ''
(空字符串)
js
const func1 = function () { }
const object = {
func2: function () { },
}
console.log(func1.name) // "func1"
console.log(object.func2.name) // "func2"
函数作用域
函数作用域是指在函数内部定义的变量(包括函数参数和内部声明的变量)只能在这个函数内部访问和使用。当函数执行完毕,这些变量将被销毁,并且无法从函数外部访问
- 函数内变量访问原则:在能够访问到的情况下先局部, 局部没有再找全局(就近原则)
- 如果函数内部,变量没有声明,直接赋值,则为定义为全局变量
函数作用域结合实际例子更好理解(后文有更详细的作用域介绍)
- 先访问局部,再访问全局
javascript
let a = 1
function fn1() {
let a = 2
let b = '22'
fn2()
function fn2() {
let a = 3
fn3()
function fn3() {
let a = 4
console.log(a) //4
console.log(b) //'22'
}
}
}
fn1()
- 函数内部,变量没有声明,直接赋值,则为全局变量
javascript
let num = 1
console.log(num) // 1
function fn(a) {
console.log(num) // 3
num = 2 // 给全局变量num赋值为2
console.log(num) // 2
}
num = 3
console.log(num) // 3
fn(num)
console.log(num) // 2
匿名函数
匿名函数指的是没有具体名字的函数。匿名函数使用方式分为两种:函数表达式、立即执行函数
- 函数表达式
js
let fn = function () {
// 函数体
}
fn() // 调用
立即执行函数
- 避免全局变量之间的污染,无需调用,立即执行
- 通过定义一个匿名函数,创建了一个新的函数作用域,相当于创建了一个私有的命名空间,该命名空间的变量和方法,不会破坏污染全局的命名空间
js
//形式一
(function () { console.log(11) })();
//形式二
(function () { console.log(11) }());
箭头函数
箭头函数是更简短的函数写法并且不绑定this
,箭头函数的语法比函数表达式更简洁
- 箭头函数更适用于那些本来需要匿名函数的地方
- 箭头函数没有
arguments
动态参数,但有剩余参数...args
js
const getMousePosition = (x, y) => ({ x, y }) // 意思是 x:x, y:y
基本语法
- 基本写法
js
const fn = () => {
// 函数体
}
- 只有一个参数可以省略小括号
js
array.forEach(item => {
// 函数体
})
- 若函数体只有一行代码,可以写到一行上,默认带有
return
js
array.forEach(item => console.log(item))
- 语法加括号的函数体返回对象字面量表达式
js
const fn = () => ({name: 'zs', age: 18})
箭头函数this
- 普通函数的
this
指向调用者 - 箭头函数不会创建自己的
this
,它只会从自己的作用域链的上一层沿用this
- 使用箭头函数前,需要考虑函数中
this
指向。在回调函数使用箭头函数时,this
为全局的window
,因此 DOM 事件回调函数不推荐使用箭头函数
js
// 示例一
const obj = {
name: 'seven',
age: 18,
sayHi: function () {
console.log(this) // obj
const fn = () => {
console.log(this) // obj
}
fn()
}
}
obj.sayHi()
// 示例二
btn.addEventListener('click', () => {
console.log(this) // window
})
// 示例三
btn.addEventListener('click', function () {
setTimeout(() => {
this.style.color = 'yellow' // btn
})
})