高阶函数
高阶函数
是对其他函数
进行操作的函数,它接收函数作为参数或将函数作为返回值输出。
此时fn就是一个高阶函数
函数也是一种数据类型,同样可以作为参数,传递给另外一个参数使用。最典型的就是作为回调函数。
- 举例
<script>
//高阶函数-函数可以作为参数传递
function fn(a, b, callback) {
console.log(a + b);
callback && callback();
}
fn(1, 2, function() {
console.log('我是最后调用的');
});
< / script>
变量作用域
变量根据作用域的不同分为两种:全局变量和局部变量。
- 函数内部可以使用全局变量。
- 函数外部不可以使用局部变量。
心 - 当函数执行完毕,本作用域内的局部变量会销毁。
闭包
-
闭包( closure )
指有权访问另一个函数作用域中变量的函数。简单理解就是,一个作用域可以访问另外一个函数内部的局部变量。 -
fn外面的作用域
可以访问fn内部的局部变量
,闭包的主要作用: 延伸了变量的作用范围。
- 如何产生闭包?
当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时,就产生了闭包 - 闭包到底是什么?
理解一: 闭包是嵌套的内部函数(绝大部分人)
理解二: 包含被引用变量(函数)的对象(极少数人)
注意:闭包存在于嵌套的内部函数中 - 产生闭包的条件?(充要)
(1)函数嵌套
(2)内部函数引用了外部函数的数据(变量/函数)
function fn1 () {
var a = 2
var b = 'abc'
function fn2 () { // 执行函数定义就会产生闭包(不用调用内部函数)
console.log(a)
}
fn2()
}
fn1()
情况一:将函数作为另一个函数的返回值
function fn1() {
var a = 2
function fn2() {
a++
console.log(a)
}
return fn2
}
var f = fn1()
f() // 3
f() // 4
情况二:将函数作为实参传递给另一个函数调用
function showDelay(msg, time) {
setTimeout(function() {
alert(msg)
}, time)
}
showDelay('atguigu', 2000)
理解:
- 使用函数内部的变量在函数执行完后,仍然存活在内存中(
延长了局部变量的生命周期
) - 让函数外部可以
操作(读写)
到函数内部的数据(变量/函数)
问题: - 函数执行完后,函数内部声明的局部变量是否还存在?
一般是不存在,存在于闭中的变量才可能存在 - 在函数外部能直接访问函数内部的局部变量吗?
不能,但我们可以通过闭包让外部操作它
闭包的产生
和销毁
- 产生: 在嵌套内部函数定义执行完时就产生了(不是在调用)
- 死亡: 在嵌套的内部函数成为垃圾对象时
function fn1() {
// 此时闭包就已经产生了(函数提升,内部函数对象已经创建了)
var a = 2
function fn2() {
a++
console.log(a)
}
return fn2
}
var f = fn1()
f() // 3
f() // 4
f = null // 闭包死亡(包含闭包的函数对象成为垃圾对象)
闭包的应用举例∶定义JS模块
- 具有特定功能的js文件
- 将所有的数据和功能都封装在一个函数内部(私有的)
- 只向外暴露一个包信n个方法的对象或函数
- 模块的使用者,只需要通过模块暴露的对象调用方法来实现对应的功能
function myModule() {
//私有数据
var msg = 'My atguigu' //操作数据的函数
function dosomething() {
console.log('dosomething()'+msg.toUppercase())
}
function dootherthing() {
console.log('dootherthing()'+msg.toLowerCase())
}
// 向外暴露对象(给外部使用的方法)
return {
dosomething: doSomething,
do0therthing: dootherthing
}
}
(function() { // 私有数据
var msg ='My atguigu' // 操作数据的函数
function dosomething() {
console.log('doSomething()'+msg.toUpperCase())
}
function dootherthing() {
console.log( 'dootherthing() '+msg.toLowerCase())
}
// 向外暴露对象(给外部使用的方法)
window.myModule2 = {
dosomething: doSomething,
dootherthing: dootherthing
}
})()
闭包缺点
- 函数执行完后,函数内的局部变量没有释放,占用内存时间会变长
- 容易造成内存泄露
解决:及时释放
function fn1() {
var arr = new Array [100000]
function fn2() {
console.log( arr. length)
}
return fn2
}
var f = fn1()
f()
f = null // 让内部函数成为垃圾对象-->回收闭包
访问对象属性[‘属性名’]应用场景
问题: var a = xxx,a内存中到底保存的是什么?
- xxx是
基本数据
,保存的就是这个数据
- xxx是
对象
,保存的是对象的地址值
- xxx是一个变量,保存的xxx的内存内容(可能是基本数据,也可能是地址值)
问题: 什么时候必须使用[‘属性名’]的方式?
- 属性名包含特殊字符:-空格
- 变量名不确定
<script type="text/javascript">
var p = {}
//1.给p对象添加一个属性: content type: text/json
// p.content-type = 'text/json'//不能用
p['content-type'] = 'text/json'
console.log(p['content-type'])
//2.变量名不确定
var propName = 'myAge'
var value = 18
// p.propName =value //不能用
p[propName] = value
console.log(p[propName])
</script>
遍历对象
for…in语句用于对数组或者对象的属性进行循环操作。
for (var k in obj) {
console.log(k); // k变量输出得到的是属性名
console.log(obj[k]); // obj[k]得到是属性值
}