Skip to content

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
  })
})
最近更新