一、函数应用
函数本质上是一种对象,可以将其当做普通对象来使用。
1.回调函数
回调,就是回头调用的意思。主函数的事先做完,回头再调用传进来的那个函数。
回调函数的作用:回调函数一般都用在耗时操作上面:因为主函数不用等待回调函数执行完,可以接着执行自己的代码。比如ajax请求,比如处理文件等。
2.作为返回值
我们在作用域链的案例中,就使用到了函数作为返回值的用法
/**
* 1.函数可以作为参数 回调函数 回头调用 主函数先执行 回调函数再执行
* 2.函数可以作为返回值
*/
function foo(x,y,callback){
console.log(x,y); // 1 2
callback(3,4)
}
function fn(a,b){
console.log(a,b) // 3 4
return a + b // 7
}
foo(1, 2, fn)
// foo(1,2,fn,function(){
// })
console.log('---------------------------------------------------');
var arr = [1,2,3,4,5];
Array.prototype.forEach = function(callback){
for(var i=0;i<this.length;i++){
callback(this[i])
}
}
arr.forEach(function(item){
console.log(item)
})
console.log('---------------------------------------------------');
function A(callback){
callback();
console.log('我是主函数')
}
function B(){
setTimeout(function(){
console.log('我是回调函数')
},1000)
}
A(B); //js事件循环 nodejs 面试
setTimeout(function(){
console.log(1)
},0);
console.log(0);
console.log(2);
console.log('---------------------------------------------------');
// 2.函数可以作为返回值
function foo(){
var a = 10;
return function(){
console.log(a)
}
};
foo()
var res = foo();
console.log(foo()); // [Function (anonymous)]
res(); // 调用返回值 10
console.log('---------------------------------------------------');
var a = 10;
function fn() {
var b = 20
function bar() {
console.log(a + b)
}
return bar // 返回值函数
}
var x = fn(),
b = 200;
x(); // 调用返回值
二、闭包
1.简单讲,闭包就是指有权访问另一个函数作用域中的变量的函数。
MDN 上面这么说:闭包是一种特殊的对象。它由两部分构成:函数,以及创建该函数的环境。环境由闭包创建时在作用域中的任何局部变量组成。
2.闭包的生成有三个必要条件
-
函数嵌套函数
-
内部函数引用了外部函数中的数据(属性、函数)
-
参数和变量不会被回收
这样就形成了一个不会销毁的函数空间
-
产生一个闭包
创建闭包最常见方式,就是在一个函数内部创建另一个函数。
3.优点:不会污染变量 变量会被维持缓存
缺点:造成内存泄漏 造成性能问题
4.闭包的作用域链包含着它自己的作用域,以及包含它的函数的作用域和全局作用域。
在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。
所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
5.闭包的用途
闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。
6.使用闭包的注意点
1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露,这是IE的BUG。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。多个子函数的scope都是同时指向父级,是完全共享的。因此当父级的变量对象被修改时,所有子函数都受到影响。
function func() {
var a = 1, b = 2;
function closure() {
return a + b;
}
return closure;
}
console.log(func()());
console.log('-----------------------------------------------------');
/**
* 调用一次函数 变量减少一次
*/
function foo(){
var a = 10;
function fn(){
a--;
console.log(a)
}
return fn
}
var res = foo();
res();//9
res();//8
res();//7
console.log('-----------------------------------------------------');
function sum(){
var a = 10;
a--;
console.log(a)
}
sum();//9
sum();//9
sum();//9
sum();//9
sum();//9
sum();//9
console.log('-----------------------------------------------------');
function f1() {
var n = 999;
nAdd = function () { n += 1 }
function f2() {
console.log(n);
}
return f2;
}
var result = f1();
result();//999
nAdd();
console.log(nAdd()); // undefined
result();//1000
7.闭包中的this指向问题-初体验
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
var name = "window";
console.log(this) // window
var obj = {
name: "obj",
say: function () {
console.log(this.name) // obj
return function () {
console.log(this.name); //window
};
},
};
var x = obj.say();
x();
</script>
</body>
</html>
三、解决全局作用域
/**
* 1.解决全局作用域 将var改为let let创建自己得局部作用域
* 2.使用立即执行函数创建局部作用域
*
*/
var arr = [];
for(var i=0;i<5;i++){
arr[i] = (function(j){
console.log(j)
})(i)
}
// 0 1 2 3 4
console.log('----------------------------------------------------');
var arr = []
for(var i = 0; i < 5; i++){
arr[i] = (function(j){
console.log(j);
})(i)
}
// var arr = []
// for (var i = 0; i < 10; i++ ){
// arr[i] = i
// console.log(arr[i]);
// }
console.log('--------------------------------------------------');
var arr = [];
for(var i=0;i<5;i++){
arr[i] = (function(j){
return function(){
console.log(j)
}
})(i)
}
arr[1](); // 1
console.log('--------------------------------------------------');
var arr = []
for (var i = 0; i < 5; i++){
arr[i] = (function(j){
return function(){
console.log(j);
}
})(i)
}
arr[3]()