函数的定义
函数的的执行过程
1.函数的定义
1.1在堆里开辟一个空间
1.2把函数体内所有的代码当作字符串存储在这个空间中
1.3把空间地址赋值给栈里的变量(函数名)
2.函数调用
按照存储的地址找到函数存储的空间
在调用栈(不是栈内存)里再次开辟一个函数执行空间
在函数执行空间内进行 形参赋值
在函数执行空间内进行 与解析
把函数存储空间里的代码复制一份拿到函数执行空间 里面执行
代码全部执行完毕,这个新开辟的函数执行空间销毁
所以当函数调用过多,会报内存不够.
定义在函数内部的变量,
会随着函数执行完毕,函数执行空间的销毁而销毁掉。
一个不会被销毁的函数执行空间
函数的每一次执行会创造一个函数执行空间
当函数内部返回一个 复杂数据类型 的时候, 并且函数外部还有变量在接收
这个函数执行空间不会被销毁
全局作用域对应的栈内存;关闭页面的时候会被销毁;
私有作用域的对应的栈内存;一般情况下,函数执行完成,对应的栈内存就会销毁,
当返回值是一个引用数据类型时,不会被销毁;
闭包
形成闭包的条件
一个不会被销毁的函数执行空间
函数内部 直接 或者 间接 的返回一个函数
内部函数操作(访问、赋值)着外部函数的变量
当三个条件都满足的时候
我们管内部的函数叫做外部函数的 闭包函数
闭包的特点:
1.保护变量私有化
优点:不去污染全局
缺点:外部不能访问,需要闭包函数
2.可以在函数外部访问函数内部的变量
优点:不局限于私有变量
缺点:外部访问需要闭包函数
3.变量的生命周期
优点:变量的生命周期被延长了
缺点:一个不会被销毁的函数空间
致命的缺点:一个不会被销毁的函数空间
内存占用太多,浏览器就崩了,内存溢出,内存泄漏,
闭包慎用
function fn() {
var num = 100;
return function a() {
// 访问外部函数fn的私有变量 num
// 并且把num的值返回
return num;
};
}
// 此时 res 接受的是 fn函数内部的a 函数
// 我们管res或者a 叫做fn的闭包函数
const res = fn();
// 拿到函数的私有变量 num
console.log(res());
// res存储的不再是fn函数内部返回的函数了
// fn的执行空间被销毁了
res = 50;
柯里化函数
一种函数的封装形式
把一个函数的两个参数拆开成为两个函数,每一个函数一个参数
多个参数的时候,把第一个参数单独提取出来
柯里化函数主要为了把参数拆开,主要做的事主要为模块化服务的
// 封装:使用正则去验证用户名
function fn(reg, name) {
return reg.test(name);
}
// 使用的时候
const reg = /[^_]\w{5,11}/;
const res = fn(reg, "guojing");
console.log(res);
// 就这么一点事为什么要封装函数?
// 在模块开发的时候,每一个模块尽量不向外暴露变量,而是向外暴露函数,返回方法
// 如果验证别的,每次都要传reg
/ const res2 = fn(reg, "huangrong");
console.log(res2);
// 换一种方式来写
// 以闭包的形式进行封装、
function testName(reg) {
return function (username) {
return reg.test(username);
};
}
// 将来我使用的时候
// res接收的是 函数内部 返回的函数
const resfn = testName(/[^_]\w{5,11}/);
// 真正进行代码开发的时候;
const res3 = resfn("guojing");
console.log(res3);
用闭包解决循环绑定事件问题
export default function Function08() {
useEffect(() => {
const wrapDom = document.getElementById("btnwrap");
const btns = wrapDom.getElementsByTagName("button");
// es6 let语法 es6转es5也是用闭包的语法,性能问题
for (let i = 0; i < btns.length; i++) {
btns[i].onclick = function () {
console.log(i);
};
}
function fn(index) {
return function () {
console.log("我执行了", index);
};
}
// 用闭包解决循环绑定事件问题
for (var i = 0; i < btns.length; i++) {
// btns[i].onclick = fn(i);
btns[i].onclick = (function (index) {
// 随着循环,每一次这个自执行函数都会执行掉
// 这个被return 出去的函数才是事件处理函数呢
return function () {
console.log("我执行了", index);
};
})(i);
}
}, []);
// 变量提升
return (
<div id="btnwrap">
<button>1</button>
<button>2</button>
<button>3</button>
</div>
);
}