Closure and this point

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

  1. this in ordinary functions
 function fn(){
    console.log(this);
  }
  fn();  //Equivalent to the following window fn();
  window.fn();

  1. 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

  1. 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

  1. 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

  1. 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		

Keywords: Javascript Front-end Vue.js

Added by shivers on Sat, 15 Jan 2022 21:12:43 +0200