This article will say some basic knowledge of javascript, this article is very suitable for you to review the basics of javascript and some novice help, please carefully check the code in the article, to help you understand

Differences and simple implementations between Call, apply, and bind

In common

It’s all about changing my “this”

The difference between

1. Whether the function is called

  • Both Call and Apply can call my function
  • Whereas my bind will not call my function, it will return a new function that you must call manually

2. Differences in parameter transfer

  • Call, bind If the function needs to pass parameters, you need to pass the corresponding parameters in turn
  • The apply function passes parameters that need to be wrapped as arrays

The call to realize

Before implementing it, let’s take a look at the definition of this method in MDN

The call() method calls a function with a specified this value and one or more arguments given separately.

That is, we need to implement the following:

  1. I have to be a Function to call this method because call is a method in function.prototype
  2. No argument is passed or the first argument is passed null and this points to the window
  3. Arguments after the first parameter are received as arguments to the calling function
  4. Change this to return the result of calling the function
 // Calling this method must be a Function, as you can see from the method added in function.prototype
  Function.prototype.myCall = function (context) {
    // Check whether my object is null or has no value passed in, if so, pointing to window
    context = context || window
    // Add a fn attribute to my object. The value of fn is the function that calls this method
    context.fn = this
    // Deconstruct my parameter with the three-point operator and intercept the argument after the first parameter
    const args = [...arguments].slice(1)
    // Call my method with the corresponding array of arguments destructed as arguments
    constresult = context.fn(... args)// This function is placed on my object, call finished, can be deleted
    delete context.fn
    // Returns the execution result
    return result
  }
  var name = 'yaojin'
  const obj = {
    name: 'remote close'
  }
  function showName (age) {
    console.log(age)
     // The parameter is acceptable to input 18
    console.log(this.name)
  }
  // Call this function normally
  showName(18) // yaojin

  / / by myCall
  showName.myCall(obj, 18)/ / distance near
}
Copy the code

The realization of the apply

The implementation of Apply is the same as that of Call, except that apply passes an array of parameters

var name = 'yaojin'

  function showName (age, money) {
    console.log(age)
    console.log(money)
    // The parameter is acceptable to input 18
    console.log(this.name)
  }

  const obj = {
    name: 'remote close'
  }

  Function.prototype.myApply = function (context) {
    if (typeof this! = ='function') throw new TypeError('Error');

    context = context || window
    context.fn = this
    let result
    If so, read the second argument, which is an array or an error will be reported
    if (arguments[1]) { result = context.fn(... arguments[1])}else {
      // If no parameter is passed, the function is called normally
      result = context.fn()
    }
    delete context.fn

    return result
  }
  showName() // This points to Windwo reading yaojin
  showName.myApply(obj, 18) // This points to obj
Copy the code

The realization of the bind

The main difference between bind and call and apply is that it returns a function, so the implementation returns a function and changes its “this” reference, which can be specified or, if called by new, “this” refers to its newly created object

Function.prototype.myBind = function(context) {
      let _this = this // Cache the function that calls this function
      let args = [...arguments].slice(1) // Remove the first argument passed in
      var fn = function () {
        let bindArgs = [...arguments] // Save all parameters to an array
        // If called by new,this refers to my function; if not,this refers to the object I passed in with the corresponding argument
        return _this.apply(this instanceof fn ? this : context, args.concat(bindArgs))
      }

      // If I call new, I need to point the prototype of this of my newly created object to the prototype of my function
      fn.prototype = Object.create(this.prototype)
      return fn
    }
    const name = 'yaojin'
    const obj = {
      name: 'remote close'
    }
    function showName (age, address) {
      this.sex = 'male'
      console.log(this.name)
      console.log(age)
      console.log(address)
    }

    showName.myBind(obj, 18) ("Foshan") // This points to obj and prints the distance, and the corresponding parameters can also be printed

    const newFn = showName.myBind(obj, 18)

    var newObj = new newFn('the foshan') // call with new

    console.log(newObj.sex) My new object can inherit the properties and methods of my function
Copy the code

What does the New keyword implement?

  1. Create an empty object, and this object is what I want to display (let’s say my new object is obj)
  2. Point the implicit prototype of my newly created object to the constructor’s display prototype (obj.proto === xxx.protpType)
  3. Use apply to change the this reference of my constructor, pass my corresponding parameter to my constructor, call it, and finally return the corresponding result
  4. And the last thing I want to notice is, all of these return value issues, if there’s any other object returned in the constructor, then that object will be returned, if there’s no other object returned, my newly created object will be returned, and this in my constructor will refer to my newly created object

The following is a code parody of the new implementation

<script type="text/javascript">
    function _new() {
        // Create an empty object
        let target = {};
        // Expand the argument I passed and assign it to a new array, the first of which is my constructor and the others are the corresponding arguments in the constructor
        let [constructor.args] = [...arguments];
        // The implicit prototype of the newly created object points to the display prototype of the constructor, allowing the newly created object to inherit the methods and properties of the constructor
        target.__proto__ = constructor.prototype;
        // Call the constructor and point this of my constructor to my newly created object, pass in the argument, and assign the function return value to result;
        let result = constructor.apply(target, args);
        // Determine if my result is an object, if so return the object, if not I return my newly created object;
        if (result && (typeof (result) === "object" || typeof (result) === "function")) {
            return result;
        }
        return target;
    };
    // A custom constructor that takes two parameters
    function Person(name, age) {
        this.name = name;
        this.age = age;
    };
    // To call the new method I created, I pass in the constructor name and the corresponding two parameters
    const yaojin = _new(Person,"Remote close".18);
    // Finally print the output
    console.log(yaojin.__proto__ === Person.prototype);
    console.log(yaojin);
</script>
Copy the code

What is a closure?

A lot of people say that a closure is a function, but I understand it as an object. In fact, you can see it in the console from the debugger as an object, and it contains local variables that are referenced

An object in the console called Closure is the Closure, and you can see that it has two properties: my corresponding variable name (key) and its value (value).

So how do closures come about?

Three conditions need to be met for closure generation

The first conditional function must be nested, that is, there must be at least two functions to generate the closure (as you can see in the figure above, there are two)

The second condition is that it refers to a local variable of my external function.

The third condition is that I have to call a function outside of me

What does a closure do?

Closure function mainly through the scope chain let me internal function can access to the outer function’s local variables, or the global environment can let me reference to internal function variables (specific you can, for example, to the interviewer), is in order to prolong the lifecycle of the I variable, because without the existence of the closure, I complete, the function of local variables will give release!

Disadvantages of closures

There are pros and cons to this. Closures can extend the lifetime of a variable, but if a local variable is not released after the function is executed, it will leak memory

 function fn(){
    let yaojin = 'remote close';
    function me(){
        console.log(yaojin)
    }
    return me;
 }
let test = fn();   // The object to which it points is kept in heap memory
test = null; // Make the object it points to empty if it is no longer used
Copy the code

Talk about the direction of this

Normally, the way the function is executed determines what this refers to

  1. Direct call
var name = 'remote close'
function fn (name) {
    console.log(this)
    console.log(this.name)
  }
  fn() // This points to the output of the window
Copy the code
  1. The object
let obj = {
    name: 'yaojin',
    fn
  }
obj.fn() // This points to obj and outputs yaojin
Copy the code
  1. The new call
function Person (name) {
    this.name = name
  }
  yaojin = new Person('remote close') // The constructor's this points to yaojin
Copy the code
  1. Call, apply, bind
var name = 'remote close'
  let obj = {
    name: 'yaojin',
    fn
  }
  let obj1 = {
    name: 'yaojin666'
  }
  function fn (name) {
    console.log(this)
    console.log(this.name)
  }
  fn.call(obj) / / points to obj
  fn.apply(obj)/ / points to obj
  const fn2 = fn.bind(obj)
  fn2()/ / points to obj
Copy the code

In special cases,this points to

  1. Arrow function
function fn1 () {
      console.log(this.name)
      return () = > {
        console.log(this.name)
      }
    }

    var name = 'yaojin'

    const obj = {
      name: 'remote close'
    }

    const newFn = fn1.call(obj) // set fn1's this to obj
    newFn() // The function returned is an arrow function whose this points to obj
Copy the code

The arrow function’s this checks whether the outer function has a function. If so, the outer function’s this is the inner arrow function’s this; if not, this is the window.

  1. The callback function

Timer callback: this points to the window DOM event listener callback: this points to the corresponding DOM element of the binding event

What is a constructor

In JavaScript, functions called with the new keyword are called constructors. Their function names usually start with a capital letter

JavaScript doesn’t actually have constructors, only constructor calls to functions. Constructors are just called to cater to other languages.

Because JavaScript only creates a constructor with a new call, whereas other languages don’t create a constructor with new at all, it has its own unique syntax, and we only create a constructor with new, so we call it a constructor call to a function

Functions and Disadvantages

Constructor function lies in the fact that made me an instance of the object can be inherited the constructor of the attributes and methods, but it’s the same object instance, unable to share the attributes and methods, meaning that when I am by the new constructor creates instance object, I think these objects inherit a the same way, if they are written in the constructor of I, So these two methods are not the same, it will create new space in the heap, which will be a waste of memory!

// Create a constructor
    function Person (name, age) {
      this.name = name
      this.age = age
      this.hello = function () {
        console.log('Hello, remote near')}}const yaojin = new Person('remote close'.18)
    const yj = new Person('remote nearly 666'.18)
    console.log(yaojin.hello === yj.hello)//false

    // Store the common methods and attributes in Prototype
    Person.prototype.say = function () {
      console.log('Near you.')}console.log(yaojin.say === yj.say)//true
Copy the code

So there’s the prototype chain, putting all the methods and properties I have in common on one of my instances in a Prototype object! This way, you can find the corresponding properties and methods step by step through the prototype chain!

What is a prototype chain?

The prototype refers to the function’s prototype property and the object’s __proto__ property, but it’s important to note that since my function is also an object, it has the two properties I just described

The prototype attribute is an Object that has at least two attributes: constructor and __proto__, except object.prototype!

The value of the constructor attribute points to its constructor itself

	// Create a constructor
	function Person (name, age) {
	  this.name = name
	  this.age = age
	}
	
	// Prototype is an object
	console.log(Person.prototype instanceof Object)//true
	
	// The constructor attribute points to its constructor itself
	console.log(Person.prototype.constructor === Person)//true
	
	// The Function constructor's __proto__ value points to function.prototype
	console.log(Function.__proto__ === Function.prototype)//true
	
	// The constructor's prototype Object whose __proto__ value refers to Object.prototype
	console.log(Person.prototype.__proto__ === Object.prototype)//true
	
	const yaojin = new Person('remote close'.18)
	// You can see that the object created by new has its __proto__ pointing to its constructor's prototype
	console.log(yaojin.__proto__ === Person.prototype)//true
	
	The yaojin object itself does not have the say method, which follows the prototype chain and is eventually found in its constructor, prototype
	Person.prototype.say = function () {
	  console.log('Near you.')}Copy the code

The __proto__ attribute of an object has four values

1. The constructor’s __proto__ value for Function refers to function.prototype

2. An object created by new whose value points to the prototype of its constructor

3. The prototype Object of all constructors, whose value points to Object.prototype

Object. Prototype __proto__ refers to null

And it is this chain of __proto__ attributes that forms the prototype chain

If the prototype constructor doesn’t have one, it will look for its own property. If the prototype constructor doesn’t have one, it will look for object. prototype. If it doesn’t have one, it will return undefined

Prototype chain figure

The prototype chain diagrams circulating on the Internet can give you a better idea

Talk about scopes and scope chains

Scope you can think of as the place where code is stored, and it determines the accessible scope of variables and objects

Scopes are divided into global scopes and local scopes

Global scope

As long as it can be accessed and used anywhere, the object or variable has the characteristics of global scope

Any variable or object that has global scope is simply adding the corresponding variable and method to the Window object

function name () {
  var yaojin = 'remote close'
  console.log(name)
  function showAge() {
    console.log(age) // Can be accessed anywhere in the global scope
    console.log(name)
  }
  showAge()
}
var age = 18
console.log(window.name) // Function under the global scope
console.log(window.age)// Global scope variables
name()
Copy the code

As you can see from the above code, I reprint the outer functions inside the function, which are also accessible, and the corresponding functions and variables read from the window are also accessible, which is a feature of the global scope

Local scope

A local scope is the opposite of a global scope. It is only accessible in a specific region. Local scopes can be subdivided into function scopes and block-level scopes (ES6).

  1. Function scope

Function scope, as the name implies, is only valid within a function. Variables and functions defined in a function are accessible only within the function itself, not globally, except through closures

function name () {
  var yaojin = 'remote close'
  console.log(yaojin) // Variables in the function scope cannot be accessed globally
}	
name()
console.log(yaojin) / / an error
console.log(address) / / an error
Copy the code

We can see that variables and functions in a local scope are not accessible everywhere, and this is the biggest difference between global and local

  1. Block-level scope

ES6 introduced the new let and const commands, which allow us to create block-level scopes. Variables and objects defined by let and const are limited to the current code block. Those wrapped in curly braces belong to the same block, and there is no promotion of variables

function name () {
   console.log(yaojin) / / an error
   function test () {
       console.log(yaojin1) / / an error
   }
   test()
   let yaojin1 = 'yaojin2070' // The variable will not be promoted
}
const yaojin = 'yaojin'// The variable will not be promoted
name()
Copy the code

:::tip scope is used to isolate variables. Only specific variables can be accessed from different scopes to avoid variable abuse :::

The scope chain

Scope chain is composed of multiple scopes. It is a chain structure formed from inside to outside. Its function is to find a rule of variables

var yaojin = 'remote close'
  function check () {
  function check1 () {
	  console.log(yaojin) // Finally found in the global through the scope chain, print near
  }
  check1()
}
check()
Copy the code

If the global scope is not found, an error is reported. If the global scope is not found, an error is reported

Promotion of variables and functions

To promote a variable or function is to promote it to the top of its scope

Promotion of variables

The promotion of a variable is just the promotion of the declaration, that is, it does not promote the content as well

function test () {
   console.log(yaojin) / / print undefined
   var yaojin = 'yaojin'
}
test()
Copy the code

As can be seen from the code, we print before the yaojin variable definition, but it does not report an error. This is because there is a promotion of the variable, but the promotion of the variable only elevates the declaration, which means that the final code is as follows:

function test () {
    var yaojin
    console.log(yaojin) / / print undefined
    yaojin = 'yaojin'
}
test()
Copy the code

:::tip From the variable promotion we need to pay attention to, we will try to write the variable at the top of a scope in the future code, so that it is convenient to view themselves, but also convenient to maintain :::

Function increase

Function promotion raises the whole, it raises the whole function to the top of its scope

test()
  function test () {
    console.log('The function improves, even though I execute the function at the top.')}Copy the code

You can see that the code does not report an error, but instead calls normally, which is the promotion of the function

Note that:

  1. First, make it clear that there is a declaration followed by an assignment
console.log(yaojin)
yaojin = 'remote close'
var yaojin
Copy the code

As you can see, var Yaojin is promoted to the top of the scope, and it is important to note that the same declaration can only exist once

  1. First there is the promotion of variables, then there is the promotion of functions
console.log(yaojin)// Prints a function
var yaojin = 'remote close'
function yaojin () {
  console.log(1)}console.log(yaojin)// Print near
Copy the code

Some people may look at this and think, is not the function promoted, in fact, it is not, but the function promotion is the overall promotion, it will also improve the defined part, so in the case of the variable with the same name, you can understand that the function promotion is greater than the variable promotion

This is the code above

var  yaojin = function () {
  console.log(1)}console.log(yaojin)// Prints a function
yaojin = 'remote close'
console.log(yaojin)// Print near
Copy the code
  1. Variables defined by let and const do not have variable promotion