How to generate closures?
There are two special cases of scope application
- Function is passed as an argument
- Function is returned as a return value
// Function as return value function create() { const a = 100 return function () { console.log(a) } } const fn = create() const a = 200 fn() // 100 // Functions are passed as arguments function print(fn) { const a = 200 fn() } const a = 100 function fn() { console.log(a) } print(fn) // 100
The free variable of a function depends on where the function is defined, not where it is executed
this
this is generally used in ordinary functions, object methods, call, apply, bind, class, and arrow functions
- this in ordinary functions
function fn(){ console.log(this); } fn(); //Equivalent to the following window fn(); window.fn();
- this in object method
let pox={ name:'Xiao Hong', run:function(){ console.log(this.name)//this } } pox.run();// pox little red
pox calls run, so this in the run method points to
let obj={name:'Xiao Ming'} let pox={ name:'Xiao Hong', run:function(){ console.log(this.name) } } // this. In object methods Points to the caller of the method. pox.run();// pox little red pox.run.call(obj)// Xiao Ming pox.run.apply(obj);// Xiao Ming pox.run.bind(obj)();//Xiao Ming
At the same point, call/apply/bind () can change this to point to the first parameter
Difference: bind() needs to be executed manually
function foo(){ // argument = [parameter] class array / pseudo array let arg=arguments; let arr=[4,5,6] // arg.push(4) borrow array // Array.prototype.push.call(arg,4) // arg==[1,2,3,4] Array.prototype.push.apply(arg,arr) // arg==[1,2,3,4,5,6] // Array.prototype.push.bind(arg)(4) // arg==[1,2,3,4] console.log(arg);//[1,2,3] } foo(1,2,3)
Differences: the second parameter of call is a single value, and the second parameter of apply() is an array
- this in class points to the real column object after new
class Person{ constructor(name,age){ this.name=name; this.age=age } say(){ console.log(`My name is ${this.name}Age is ${this.age}`) } } let lsy=new Person('Li Shile',21); lsy.say();// My name is Li Shile. My age is 21 console.log(lsy);// {name: 'Li Shile', age:21}
this in class points to the real column object after new
- exceptional case
this in the object method points to the current object (because the current object executes the method).
This in the setTimeout function is equivalent to this in an ordinary function, because the function triggered by setTimeout is not executed by an external object.
The function in setTimeout is an arrow function, and this is the current object. Because this in the arrow function is always this in the parent context
- It should be noted that
- The value of this is determined during execution and cannot be determined during definition
Handwritten bind:
// Simulate bind Function.prototype.bind1 = function () { // Disassemble parameters into arrays const args = Array.prototype.slice.call(arguments) // Get this (the first item in the array) const t = args.shift() // fn1.bind(...) FN1 in const self = this // Returns a function return function () { return self.apply(t, args) } } function fn1(a, b, c) { console.log('this', this) console.log(a, b, c) return 'this is fn1' } const fn2 = fn1.bind1({x: 100}, 10, 20, 30) const res = fn2() console.log(res)
this summary (important)
In ordinary functions, this points to window.
In object method, this points to the current object.
In call apply bind, this points to the incoming object.
Invoking in the method in class, this points to the instance object.
Arrow function, this is this in the parent context
-
Application scenarios of closures
Closure application scenarios encapsulate the private properties and methods of objects
Hide data
Make a simple caching tool
// Closures hide data and only provide API s function createCache() { const num=100 const data = {} // The data in the closure is hidden and not accessed by the outside world return { num:num, set: function (key, val) { data[key] = val }, get: function (key) { return data[key] } } } const c = createCache() console.log(c.num)//num is now a c private attribute c.set('a', 100) //set is now the private method of c console.log( c.get('a') )
Closure application scenario closure action callback function
<body> <a href="#" id="as1">20</a> <a href="#" id="as2">40</a> </body> <script> function changeSize(size){ return function(){ document.body.style.fontSize=size+'px'; } } var size20=changeSize(20); var size40=changeSize(40); document.getElementById('as1').onclick=size20; document.getElementById('as2').onclick=size40; </script>
Closure application scenario 3, function throttling and anti chattering
<body> <!-- Function anti chattering refers to the delay after stopping triggering when the function is triggered by high frequency n Second to execute the function, (That is, each trigger clears the delay function and starts timing again),Generally used resize scroll,mousemove --> <!-- Function throttling principle delay when function is started at high frequency n It will be executed again after seconds. Anti shake is mainly triggered by the user after a time and delayed for a period of time, Throttling will trigger an event within the specified event --> </body> <script> // Function throttling: to ensure that a function can be executed at most once in a specific time. // Function anti shake: the function is executed after it is not called again within a specific time. //Anti shake var debounce = function(func, delay) { var timer = null return function() { var that = this; var args = arguments; if(timer) { clearTimeout(timer); } timer = setTimeout(function() { func.apply(that, args); }, delay) } } ipt.addEventListener('keyup', debounce(function(e){ console.log(e.target.value); }, 400)) </script>
supplement
// Closures can cause page performance problems and may lead to memory leaks in ie function a(){ var num =10; return function(){ return ++num; } } // var inc =a(); // console.log(inc()); // console.log(inc()); // inc=null; //You can also write a() to get the current function and call it again //Because the generated function inc is also a closure, this closure accesses the variable num again console.log(a()()); console.log(a()()); //After each complex function call is completed, a new closure will be formed, and the variables in the parent function will always be in memory, // Equivalent to cache, beware of consumption