一:闭包
1.什么是闭包
JS 中函数会产生闭包。
闭包是函数本身和该函数声明时所处的环境状态的组合。
函数能够 “记忆” 其定义时所处的环境,即使函数不在其定义的环境中被调用,也能访问定义时所处环境的变量。
// 定义一个全局变量
var name = 'ABC';
// 创建一个函数
function fun() {
// 定义局部变量
var name = 'sw';
// 返回一个局部函数
return function() {
console.log(name);
};
}
// 调用外部函数,就能得到局部函数,用变量 inn 来接收
var inn = fun();
// 执行 inn 函数,就相当于在 fun 函数的外部,执行了局部函数
inn(); // "sw"
2.闭包的特点
-
作为一个函数变量的一个引用,当函数返回时,其处于激活状态。
-
一个闭包就是当一个函数返回时,一个没有释放资源的栈区。
简单的说,Javascript允许使用内部函数---即函数定义和函数表达式位于另一个函数的函数体内。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。
优点:可以访问局部变量。
缺点:局部变量一直占用内存,内存占用严重,还容易造成内存泄漏(内存被占用,剩余的内存变少,程序加载、处理速度变慢)
闭包的功能:记忆性、模拟私有变量(相当于把函数的数据封装了)。
3.闭包的用途
-
封装私有变量:通过使用闭包,可以创建私有变量,这些变量只能在函数内部访问,而外部无法直接访问。这样可以避免全局命名冲突和数据被意外修改。
-
实现模块化:通过使用闭包,可以创建模块化的代码结构,将相关的变量和函数封装在一个闭包中,避免全局污染,并提供了一种封装和隔离代码的方式。
-
保存函数的状态:闭包可以保存函数的状态,即使函数被多次调用,每次调用都可以保留之前的状态。这对于一些需要记住之前操作结果的函数非常有用。
-
实现回调和异步操作:闭包可以用于实现回调函数和处理异步操作。通过将回调函数作为闭包传递给其他函数,可以在特定事件发生或异步操作完成时执行回调函数。
-
实例练习:
//实现计数器功能,每次调用函数都会增加计数器的值。 function counter() { var count = 0; function increment() { count++; console.log(count); } return increment; } var myCounter = counter(); myCounter(); // 输出 1 myCounter(); // 输出 2 myCounter(); // 输出 3 //实现累加器功能,每次调用函数都会将传入的参数与之前的累加结果相加。 function accumulator() { var sum = 0; function add(num) { sum += num; console.log(sum); } return add; } var myAccumulator = accumulator(); myAccumulator(5); // 输出 5 myAccumulator(3); // 输出 8 myAccumulator(10); // 输出 18 var arr = [] for (var i = 0; i < 3; i++) { (function fn(i) { var i; arr[i] = function () { console.log(i) } })(i) } arr[0]()//0 arr[1]()//1 arr[2]()//2
二:回调函数
指将一个函数作为参数传递给另一个函数,并在特定事件发生或特定条件满足时调用该函数。回调函数常用于处理异步操作,例如定时器、事件处理、网络请求等。
function doSomething(callback) {
// 执行一些操作
// ...
// 在操作完成后调用回调函数
callback();
}
function callbackFunction() {
console.log("回调函数被调用了!");
}
// 调用doSomething函数,并将callbackFunction作为回调函数传递
doSomething(callbackFunction);
function fn(arg){ }
当实参是一个number时,arg形参就按照数字来使用。
function fn(arg) {
var re = arg + 200
console.log(re)
}
fn(200)
当实参是一个数组时,arg形参就按照数组来使用。
function fn(arg) {
var re = arg[1]
console.log(re)
}
fn([12, 20, 40]) //20
当实参是一个对象时,arg形参就按照函数来使用。
function fn(arg) {
var re = arg["age"]
console.log(re)
}
var obj = { age: 18 }
fn(obj) //18
当实参是一个fm函数时,arg形参就按照函数来使用。
function fn(arg, arg2) {
var arg= function fm() { console.log(23) }
console.log(arg.length, arguments.length)//
console.log("sw")
arg()
console.log("ws")
}
function fm() { console.log(22); console.log("33") }//回调函数
fn(fm, 200, 300)
运行结果:
0 3
sw
23
ws
实例练习:
function fn(num, callback) {
var result = num * 2;
callback(result);
}
function callbackFunction(result) {
console.log("结果是:" + result);
}
fn(5, callbackFunction); // 输出 结果是:10
function getUserData(callback) {
setTimeout(function() {
var userData = { name: "John", age: 25 };
callback(userData);
}, 2000);
}
function callbackFunction(userData) {
console.log("用户数据:", userData);
}
getUserData(callbackFunction); // 用户数据: { name: "John", age: 25 }
三:函数自调用
函数自调用的一般语法形式是将函数定义包裹在一对圆括号中,并在末尾添加另一对圆括号来立即执行函数。
以下是一个简单的函数自调用的示例:
(function() {
console.log("这是一个自调用函数!");
})();
在上面的示例中,函数被定义为一个匿名函数,并使用一对圆括号将其包裹起来。最后的一对圆括号 ()
调用了这个函数,使其立即执行。在控制台中会输出 "这是一个自调用函数!"。
函数自调用的主要用途是创建一个独立的作用域,避免变量污染全局命名空间。它还可以用于封装代码块,实现模块化和私有变量的概念。
函数自调用可以接受参数,并在调用时传递参数。例如:
(function(name) {
console.log("欢迎," + name + "!");
})("sw");
作用:
1.为变量赋值
var age = 12;
var sex = '男';
var title = (function () {
if (age < 18) {
return '小朋友';
} else {
if (sex == '男') {
return '先生';
} else {
return '女士';
}
}
})();
2.将全局变量变为局部变量
var arr = [];
for (var i = 0; i < 5; i++) {
(function (i) {
arr.push(function () {
console.log(i);
});
})(i);
}
for (var j = 0; j < arr.length; j++) {
arr[j]();
}
四:对象的方法
JavaScript对象的方法是指对象中定义的函数。对象方法允许在对象上执行特定的操作或功能。
如何定义对象方法?
对象方法可以通过在对象字面量中定义函数来创建。
var myObject = {
myMethod: function() {
// 方法的代码
}
};
如何调用对象的方法:
对象方法可以通过对象名称和方法名称来调用。例如:
myObject.myMethod();
在上面的示例中,myMethod
是 myObject
对象的方法,通过 myObject.myMethod()
来调用。
对象的成员,保存的只要不是函数,就称为属性,是函数,就称为方法。
任何函数运行一定有一个对象在调用。
全局的所有变量和函数都是window对象的成员。
实例练习:
var myObject = {
add: function(a, b) {
return a + b;
}
};
var result = myObject.add(5, 3);
console.log(result); // 输出 8