函数
一、函数的声明和调用
声明函数: 封装独立的功能
调用函数: 享受封装的成果
参数: 形式参数、实际参数
返回值:**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 () { 代码... }
函数声明和函数表达式的区别:
- 语法不同:
- 函数声明:在主代码流中声明为单独语句的函数
- 函数表达式:在一个表达式中或另一个语法结构中创建的函数
- 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>