函数
函数的定义与创造
定义:
在堆内存中开一个空间,将函数体内的代码,保存到堆内存中,将堆内存的地址保存变量名(函数名),最后将这个变量名存储到栈内存中
调用:
根据变量名(函数名)中的地址找到对应的函数,
然后再调用栈中开一个新的空间(函数的执行空间),
在执行空间中 对函数的形参进行赋值,
在执行空间中 进行变量的预解析,
在执行空间中 执行函数的代码,
销毁当前函数的执行空间.
创建:
声明式定义
语法:function 变量名 (参数){'需要运行的代码'}
//利用声明式创建函数
function fn() {
console.log('我是利用声明式定义的')
}
//调用函数
fn()
赋值式定义
语法: let 变量名 = function (参数) {'需要运行的代码'}
//利用赋值式创建函数
let fn = function () {console.log('我是利用赋值式创建的')}
//调用函数
fn()
永不销毁的执行空间
什么是永不销毁的执行空间(如何创建一个永不销毁的执行空间)
1.正常书写一个函数
2.在这个函数内 向外返回一个引用数据类型
3.当满足上述条件时,这个函数的执行空间将不会被销毁
function fn(){
const obj = {
name:'fn函数的name',
age:'不知道'
}
return obj
}
const newObj = fn()
console.log(newObj)
//将newObj 的值修改后就与函数内部的对象切断联系,那么这个函数的执行空间就会被销毁
//newObj = null
闭包
什么是闭包
闭包是指有权访问外层函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建一个内层函数,通过内层函数访问外层函数的局部变量,利用闭包可以突破作用链域
闭包的特性:
函数内再嵌套函数
内部函数可以引用外层的参数和变量
函数的执行空间不会被销毁
如何创建一个闭包
创建闭包的最常见的方式就是在一个函数内创建一个内层函数,通过内层函数访问外层函数的局部变量
function outer(){
let a = 100
let obj = {
name:'outer函数',
age:'随意'
}
function inner(){
console.log(a)
console.log(obj)
}
//返回一个函数
return inner
}
const newFn = outer()
console.log(newFn)//得到一个函数(inner)
newFn()
闭包的优点:
1.可以避免全局污染
2.可以读取函数内部的变量,并将这些变量保存到内存中
闭包的缺点:
加大内存的使用,可能会造成内存泄漏
解决办法:
在退出函数之前,将不使用的变量删除.
案例
function fun(n, o) {
console.log(o);
const obj = {
fun: function (m) {
return fun(m, n);
},
};
return obj;
}
var a = fun(0); // undefined
a.fun(1); // 0
a.fun(2); // 0
a.fun(3); // 0
解题思路
/**
* var a = fun(0)
* 调用全局函数 fun (QF001), 并传递了一个实参 0, 所以对应的两个形参 n === 0; o === undefined
*
* 函数内部代码开始执行
* 1. console.log(o) undefined
* 2. 创建一个 对象 obj, 内部有一个属性名为 fun 值为一个函数
* 3. 将这个 对象 obj 返回到函数外边 (变量 a 接受了 这个 对象, 所以 将来 变量a 可以调用内部的 fun)
*
* a.fun(1)
* 调用的是 对象 obj 内部的 fun (QF999) 函数, 并传递了一个 实参 1, 所以对应的一个形参 m === 1
* 开始执行函数内部代码
* return fun(m, n) 注意!!! 这个函数是全局函数 fun(QF001). 如果想要调用对象内部的 应该是 对象.属性名()
* 并传递了两个实参
* m === 1
* n === 0 (函数QF999 的作用域中没有, 所以需要去上一层作用域查找, 也就是 函数QF001, 在这个函数中找到了一个形参n, 它的值为0)
* 函数开始执行时就会执行一句 console.log(o) 我们传递的是数字 0
*
* a.fun(2)
* 调用的是 对象 obj 内部的 fun(QF999), 并传递一个 实参 2, 所以对应的一个形参 m === 2
* 开始执行函数内部代码
* return fun(m, n) 传递的两个实参 m === 2; n === 0 (n 怎么来的参考 45行注释)
* 函数开始执行: console.log(o) 我们传递的是数字 0
*
* a.fun(3)
* 调用的是 对象 obj 内部的 fun(QF999), 并传递一个 实参 3, 所以对应的一个形参 m === 3
* 开始执行函数内部代码
* return fun(m, n) 传递的两个实参 m === 3; n === 0 (n 怎么来的参考 45行注释)
* 函数开始执行: console.log(o) 我们传递的是数字 0
*/