本章是讲解函数的重点章节,不仅详细描述了函数的语法,构成,形参和实参
,还讲解了底层的运行机制,栈内存和堆内存
函数数据类型 function
函数就是一个方法或者一个功能体,函数就是把实现某个功能的代码放到一起,进行封装,以后想要操作或者实现这个功能,主需要调用我们封装的函数(减少页面中重复的代码,提高代码的使用率,低耦合高内聚)
耦合度:比如有对夫妻,妻子非常的依赖丈夫,没有丈夫就活不下去,这就是高耦合的表现。如果一个函数只能在某些很极端的条件下才能使用,或者搬到另外一个地方用就用不了,通用性和移植性比较差那就是高耦合函数
比如下面我们把函数
比喻成一个微波炉
-
微波炉要放什么食物(形参)
-
微波炉怎么加热食物(实现功能)
-
食物加热后变成什么样(return值)
function WeiBoRu(food) { console.log('加热食物中~~'); finallyFood = String(food) + 'ok'; return finallyFood } console.log(WeiBoRu('牛奶')); // 加热食物中~~ // 牛奶ok
形参和实参
-
形参实参基本形式
// 定义在函数体内的参数叫做形参 function fn([形参1, 形参2, ...]) { value = 形参1 + 形参2 return value } // 调用函数传入的参数叫做实参, 10 和 20 都是实参 fn(10, 20)
-
形参和实参的关系
-
形参数 大于 实参数字
function hello(num1, num2) { return num1 + num2 } hello(1, 2, 3, 4); // 结果是3, 后面的 3 和 4 都会被抛弃
-
形参数 小于 实参数字
function hello(num1, num2) { alert(num1 + num2) } hello(1); // 输出 NaN,num1是1,num2是undefined,数字+undefined = NaN
-
arguments
当我们不知道用户传入多少个实参,可以在函数内使用一个关键字 arguments
,其包含所有实参的一个伪数组
function fn(value) {
console.log(value);
console.log(arguments)
}
// 调用,传入多个参数
fn(1, 2, 3, 4, 5, 6)
伪数组:
具有数组的 length 方法,能获得长度,但是arguments的原型是Object,没有数组的方法
有名/匿名函数
-
有名函数
function fn(a, b) { console.log(a, b) }
-
匿名函数(函数表达式和立即执行函数)
// 1.函数表达式 let fn = function() {} document.document.onclick() = function() {} // 2. 立即执行函数 (function(a, b){}(a, b)); (function(a, b){})(a, b);
函数底层运行机制
-
创建函数(凡是引用数据类型,都会创建堆内存),浏览器开辟一块全新的堆堆存,并把函数体内的代码以字符串的形式保存在堆中
-
运行函数
- 运行函数会开辟一块全新的栈内存用来
自上而下执行函数
(代码都是在栈中执行的) - 基本数据类型比较简单,所以会直接在函数执行的栈内存中存放
- 这个栈内存有属于自己的私有作用域,外部是访问不到里面的变量
- 函数运行结束后会return一个值,并传给外部接收的变量(没设置则为undefined)
- VO阶段属于变量值存储阶段,AO属于函数执行阶段
- 运行函数会开辟一块全新的栈内存用来
li按钮下表经典题
为什么用for循环给每个按钮注册点击事件,点击 i 之后的值一直是5
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<button>按钮5</button>
let btnList = document.querySelectorAll('button');
for (var i = 0; i < btnList.length; i++) {
btnList[i].addEventListener('click', function () {
console.log(this.i);
})
}
- 原因:
- for 循环每次给按钮的 onclick 添加回调函数
- 都只是创建一个堆,并并且函数内的代码以字符串格式丢进去,并没有执行
- 当我们点击一个按钮的时候,回调函数会开辟一个新的私有内存栈,执行字符串里的代码
- 由于当前作用域没有 i 这个值,就往上一层作用域里面找,i的值已经是5了
解决方案①
给每个按钮添加一个属性,index,并把i的值赋予它
let btnList = document.querySelectorAll('button');
for (var i = 0; i < btnList.length; i++) {
btnList[i].index = i;
btnList[i].addEventListener('click', function () {
console.log(this.index);
})
}
任意数求和经典题
无论传入什么数,都能求和
function sum() {
let total = null;
for (let i in arguments) {
let num = parseFloat(arguments[i]); // 排除 '123aaa' 这种情况
!isNaN(num) ? total += num : null // 通过NaN判断是不是数字
}
return total
}