Skip to content

函数 ​

一、函数的声明和调用 ​

声明函数: 封装独立的功能

调用函数: 享受封装的成果

参数: 形式参数、实际参数

返回值:**return

注意:

  • 函数的命名规则与变量的命名规则一致,最好做到见名知意,动词居多(表示行为)
  • 函数定义完后不会执行,必须调用才会执行

计算和 ​

javascript
function sumN() {
	var sum = 0

	for (var i = 0; i < arguments.length; i++) {
		sum += arguments[i]
	}

	return sum
}

console.log(sumN(10, 20, 30)) // 60

格式化数据 ​

javascript
function formatCount(count) {
	var result = 0

	if (count > 10_0000_0000) {
		result = (count / 1_0000_0000).toFixed(2) + '亿'
	} else if (count > 10_0000) {
		result = (count / 1_0000).toFixed(2) + '万'
	} else {
		result = count.toFixed(2)
	}

	return result
}

var num1 = 9990
var num2 = 999_0000
var num3 = 999_0000_000

console.log(formatCount(num1)) // 9990
console.log(formatCount(num2)) // 999.00万
console.log(formatCount(num3)) // 99.90亿

二、函数的递归调用 ​

函数调用其自身的行为

优点: 代码简洁

缺点: 性能不高,函数调用时占用过多栈内存

循环实现 x 的 n 次方 ​

javascript
function pow1(x, n) {
	var result = 1

	for (var i = 0; i < n; i++) {
		result *= x
	}

	return result
}

console.log(pow1(2, 3)) // 8

递归实现 x 的 n 次方 ​

javascript
function pow2(x, n) {
  if (n === 1) retuen x

  return x * pow2(x, n-1)
}

console.log(pow(2, 3)) // 8

斐波那契数列:1 1 2 3 5 8 13 21 34 55 ...

循环实现斐波那契数列 ​

javascript
function fibonacci1(n) {
	if (n === 1 || n === 2) return 1

	var n1 = 1
	var n2 = 1
	var result = 0

	for (var i = 3; i <= n; i++) {
		result = n1 + n2
		n1 = n2
		n2 = result
	}

	return result
}

console.log(fibonacci1(5)) // 5

递归实现斐波那契数列 ​

javascript
function fibonacci2(n) {
	if (n === 1 || n === 2) return 1

	return fibonacci2(n - 1) + fibonacci2(n - 2)
}

console.log(fibonacci2(5)) // 5

三、局部和全局变量 ​

全局变量: 全局定义的变量可以在定义之后的任何范围被访问

局部变量: 函数内部定义的变量只有在函数内部才能被访问

外部变量: 函数内部访问函数外部的变量

块级作用域: ES5 之前没有块级作用域

函数作用域: ES5 之前函数代码块会形成自己的作用域

javascript
// 全局变量
var message = 'this is a message'

for (var i = 0; i < 10; i++) {
	console.log(message) // this is a message

	var count = 10

	console.log('代码块内部打印count:', count) // 代码块内部打印count:10
}

// 全局作用域内可以访问到代码块里的变量-没有块级作用域
console.log('代码块外部打印count:', count) // 代码块外部打印count:10

function foo() {
	// 函数内部访问message,message即为外部变量
	console.log(message) // this is a message

	// 局部变量
	var num = 20
	console.log('函数内部打印num:', num) // 函数内部打印num:20
}

// 函数外部访问不到函数内部的变量-函数具有函数作用域
console.log('函数外部打印num:', num) // Uncaught ReferenceError: num is not defined

四、函数表达式的写法 ​

写法: var foo = function () { 代码... }

函数声明和函数表达式的区别:

  1. 语法不同:
    • 函数声明:在主代码流中声明为单独语句的函数
    • 函数表达式:在一个表达式中或另一个语法结构中创建的函数
  2. JavaScript 创建函数的时机不同:
    • 函数表达式是在代码到达时被创建,并且仅从此刻起可以
    • 函数声明在被定义之前就可以调用,这是因为内部算法的缘故,当 JavaScript 准备运行脚本时会在脚本中寻找全局函数声明并创建这些函数

函数声明

javascript
foo() // this is foo function

function foo() {
	console.log('this is foo function')
}

函数表达式

javascript
bar() // Uncaught TypeError: bar is not a function

var bar = function () {
	console.log('this is bar function')
}

五、函数的头等公民 ​

函数作为头等公民 ​

  • 函数可以赋值给变量 (函数表达式写法)
javascript
var foo = function () {
	console.log('foo')
}

foo() // foo
  • 函数可以传递给另一个函数
javascript
function foo1() {
	console.log('foo')
}

var foo2 = foo1
foo2() // foo
  • 函数可以作为另一个函数的参数
javascript
function foo() {
	console.log('foo')
}

function bar(fn) {
	fn()
}

bar(foo)
  • 函数可以作为另一个函数的返回值
javascript
function sayHello() {
	return function hi() {
		console.log('hi')
	}
}

var fn = sayHello()

fn()
  • 函数可以存储到数据结构中
javascript
var obj = {
	name: 'mocha',
	eating: function () {
		console.log('eating~')
	},
}

obj.eating()

函数式编程 ​

  • 函数可以作为头等公民的编程语言即为函数式编程语言(JavaScript)

函数的回调 ​

  • 将函数作为另一个函数的参数传入到另一个函数中
  • 在另一个函数中,对于传入的函数进行调用的过程就是函数的回调

匿名函数 ​

  • 传入一个函数时,如果没有给函数名也没有定义对应变量的函数就是匿名函数

高阶函数 ​

  • 函数可以接收另一个函数作为参数就是高阶函数
  • 函数返回另一个函数也是高阶函数

六、立即执行函数 ​

IIFE: 函数定义后被立即执行

javascript
var iifeFunction = (function (num) {
	console.log('立即打印', num)
	return 'this is a IIFE'
})(10)(
	// 立即执行函数:在立即执行函数中定义的变量有自己的作用域
	function () {
		var message = 'hello message1'
		console.log(message)
	}
)()

其他写法

javascript
;(function () {})() + (function foo() {})() - (function foo() {})()
!(function foo() {})()

应用场景一: 防止全局变量污染

javascript
// person1.js
var personOneModule = function () {
	var modules = {}
	var message = 'hello first message'
	modules.message = message
	return modules
}

// person2.js
var personSecondModule = (function () {
	var modules = {}
	var message = 'hello seconde message'
	modules.message = message
	return modules
})(
	// person1-utils.js
	function () {
		console.log(personOneModule.message.length)
		console.log(personSecondModule.message.length)
	}
)()
javascript
<script src="person1.js"></script>
<script src="person2.js"></script>
<script src="person1-utils.js"></script>

<script>
  console.log(personOneModule.message)
  console.log(personSecondModule.message)
</script>

应用场景二: 解决没有作用域

html
<button class="btn">按钮1</button>
<button class="btn">按钮2</button>
<button class="btn">按钮3</button>
<button class="btn">按钮4</button>

<script>
	var btnEls = document.querySelectorAll('.btn')
	for (var i = 0; i < btnEls.length; i++) {
		var btn = btnEls[i](function (index) {
			// 形成闭包
			btn.onclick = function () {
				console.log(`按钮${index + 1}发生了点击`)
			}
		})(i)
	}
</script>