Closures in JavaScript in web front-end


Closures – Written Exam-11

function fun() {
    
     
	var n = 9; 
	// js 中强行给一个未声明的变量赋值,
	// 程序不会报错
	// 并且会自动在全局创建此变量
	add = function() {
    
     
		n++;
	}; 
	return function() {
    
     
		console.log(n); 
	}; 
};

// 把 fun() 执行的结果赋值给 fn 变量
var fn = fun();

// 此处调用的是全局的 add 函数,
// 因为全局的 add 函数作用域链引用着 fun 函数作用域对象
// 所以修改的是 fun 里面变量的值
add();
fn(); // 10

// 把 fun() 执行的结果赋值给 fn2 变量
// 注意:这里的 fn2 所引用的是 fun() 执行后的地址
// 所以 fn 和 fn2 变量使用的地址是不同,结果也不相同
var fn2 = fun();
fn2(); // 9
add();
add();
fn2(); // 11
fn(); // 10
add();
fn(); // 10

defineReactive function, using closure to encapsulate Object.defineProperty()

function defineReactive(data, key, val) {
    
    
	Object.defineProperty(data, key, {
    
    
		// 可枚举
		enumerable: true,
		// 可以被配置,比如可以被 delete
		configurable: true,
		// getter  
		get() {
    
     
			return val;
		},
		// setter
		set(newValue) {
    
    
			if (val === newValue) return false;
			val = newValue;
		}
	});
};
let obj = {
    
    };
defineReactive(obj, 'a', 10); // 设置 a 属性
console.log(obj.a); // 10 访问 a 的值
obj.a = 100; // 改变 a 的值
console.log(obj.a); // 100 访问改变后 a 的值

Closures – Throttle Functions – Written Exam-10

1. Definition

The function of the throttling function is to execute the function only once within a limited time.
1. Button submission (you can avoid repeated submissions. Of course, this method is not the only one. You can also set the button to be unavailable).
2. When the trigger frequency of scroll, mousehover, mousemove, etc. is high.
The main principle is to set a flag in the closure. This flag is set to true within a limited time. If the function is clicked again, it will be executed. After the setTimeout function is executed, the flag will be set to flase. Execution can continue.


2、html

<!DOCTYPE html>
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=GBK">
	</head>
	<body>
		<div class="box" id="div_box" >
			<button onclick="fn1()">test</button>
		</div>
	</body>
</html>

3、JavaScript

function throttle(fn, delay) {
    
    
	var flag = false;
	var timer = null;
	
	return function() {
    
    
		// 将参数转成数组
		var args = [].slice.call(arguments, 0); 
		var context = this;
		
		// 如果在限定的时间内 flag 是 true 则直接返回,不让执行
		if(flag) return false;
		// 函数正在控制中
		flag = true; 
		// 执行函数
		fn.apply(context, args);
		// 清除定时器
		clearTimeout(timer); 
		timer = setTimeout(function() {
    
    
			// 延时时间过了以后,放开函数控制
			flag = false; 
		}, delay);	
	}
}

function fn() {
    
    
	console.log(123);
}

// 绑定节流函数
var fn1 = throttle(fn, 2000);  

closure definition

Definition-01

A closure is a function that has access to a variable in the scope of another function.


Definition-02

A closure is an expression (usually a function) that has a number of variables and an environment to which these variables are bound, so that these variables are part of the expression.


Definition-03

Closures allow a function to access and operate variables and functions in the scope when it is declared, and can be called even if the scope when it is declared disappears.


Definition-04

A closure is a function defined in another function (parent function) that has access to variables in the parent function. Closures have three scopes of access. own scope, parent scope and global scope.


9 classic usage scenarios of JavaScript closures

1. Return value (most commonly used)

This is easy to understand: name is returned in the form of a closure.

function fn() {
    
    
    var name = "hello";
    return function (){
    
    
        return name;
    };
};
var fnc = fn();
console.log(fnc()); // hello

2. Function assignment

Set the value for the fn function in the closure. The name attribute is memorized in the form of the closure, and hello will be output when executed.

var fn;
function fnc() {
    
    
    var name = "hello";
    // 将函数赋值给fn
    fn = function (){
    
    
        return name;
    };
};
fnc(); // 要先执行进行赋值,
console.log(fn2()); // 执行输出fn2

3. Function parameters

Use a closure to return a function, use this function as a parameter of another function, execute this function in another function, and finally output hello.

function fn(){
    
    
    var name = "hello";
    return function callback() {
    
    
        return name;
    };
};
var fun = fn(); // 执行函数将返回值(callback函数)赋值给fnc
function func(f) {
    
    
    // 将函数作为参数传入
    console.log(f()); // 执行函数,并输出
};
func(fun); // 执行输出fun

4. IIFE (self-executing function)

Directly pass the encapsulated function fn1 to fn2 in the self-executing function, and call it as a parameter to get the result hello.

(function (){
    
    
	var name = "hello";
    var fn1 = function (){
    
    
        return name;
    };
    // 直接在自执行函数里面调用fn2,将fn1作为参数传入
    fn2(fn1);
})();
function fn2(f){
    
    
    // 将函数作为参数传入
    console.log(f()); // 执行函数,并输出
};

5. Circular assignment

If closure is not used, the situation will be different.

// 每秒执行1次,分别输出1-10
for(var i = 1; i <= 10; i++){
    
    
    (function (j){
    
    
        // j来接收
        setTimeout(function (){
    
    
            console.log(j);
        }, j * 1000);
    })(i); // i作为实参传入
}

6. getters and setters

Use the setter to output hello for the first time and then output world. This can be encapsulated into a public method to prevent properties and functions that you do not want to expose from being exposed to the outside.

function fn() {
    
    
	var name = 'hello',
    setName = function (n){
    
    
        name = n;
    },
    getName = function (){
    
    
        return name;
    };

    // 将setName,getName作为对象的属性返回
    return {
    
    
        setName,
        getName
    };
};
var fn1 = fn(); // 返回对象,属性setName和getName是两个函数
console.log(fn1.getName()); // getter
fn1.setName('world'); // setter修改闭包里面的name
console.log(fn1.getName()); // getter

7. Iterator (execute the function once and get a value from the bottom)

null

var arr = ['aa','bb','cc'];
function incre(arr) {
    
    
    var i = 0;
    return function (){
    
    
		// 这个函数每次被执行都返回数组arr中 i下标对应的元素
		return arr[i++] || '数组值已经遍历完';
    }
}
var next = incre(arr);
console.log(next()); // aa
console.log(next()); // bb
console.log(next()); // cc
console.log(next()); // 数组值已经遍历完

8. First distinction (with the same parameters, the function will not be executed repeatedly)

null

var fn = (function (){
    
    
	var arr = []; // 用来缓存的数组
	return function (val){
    
    
		if(arr.indexOf(val) == -1) {
    
     // 缓存中没有则表示需要执行
			arr.push(val); // 将参数push到缓存数组中
			console.log('函数被执行了', arr);
			//这里写想要执行的函数
      	} else {
    
    
			console.log('此次函数不需要执行');
		}
		console.log('函数调用完打印一下,方便查看已缓存的数组:', arr);
	};
})();
fn(10);
fn(10);
fn(1000);
fn(200);
fn(1000);

9. Cache

For example, if there is no cache for the sum operation, the calculation will be repeated every time it is called. The cache will be used to search for the results that have already been executed. If the search is found, it will be returned directly without recalculation.

var fn = (function (){
    
    
	var cache = {
    
    }; // 缓存对象
	var calc = function (arr){
    
     // 计算函数
		var sum = 0;
		// 求和
		for(var i = 0; i < arr.length; i++){
    
    
			sum += arr[i];
		}
		return sum;
	};

	return function (){
    
    
		var args = Array.prototype.slice.call(arguments,0); // arguments转换成数组
		var key = args.join(","); // 将args用逗号连接成字符串
		var result, 
			tSum = cache[key];
		if(tSum){
    
     // 如果缓存有   
			console.log('从缓存中取:', cache); // 打印方便查看
			result = tSum;
		} else {
    
    
			// 重新计算,并存入缓存同时赋值给result
			result = cache[key] = calc(args);
			console.log('存入缓存:', cache); // 打印方便查看
		}
		return result;
	}
})();
fn(1, 2, 3, 4, 5);
fn(1, 2, 3, 4, 5);
fn(1, 2, 3, 4, 5, 6);
fn(1, 2, 3, 4, 5, 8);
fn(1, 2, 3, 4, 5, 6);

Link

Produced by Great World

Guess you like

Origin blog.csdn.net/weixin_51157081/article/details/122087629