A directory

What’s the difference between a free front end and a salted fish

directory
A directory
The preface
Iii Final Realization
 3.1 write a call
 3.2 write a apply
 3.3 write a bind
The Arguments object
Five call
 5.1 the original call
 5.2 write a call
6 the apply
 6.1 native apply
 6.2 write a apply
Seven bind
 7.1 native bind
 7.2 write a bind
Eight topics
 8.1 This points to Question 1
 8.2 This points to question 2
Ix References

The preface

Returns the directory

Interviewer: Write a call/apply/bind by hand.

If a worker wants to do a good job, he must sharpen his tools first. Let’s first understand what the difference is between these three:

The use of the call

function Product (name, price) {
  this.name = name;
  this.price = price;
}

function Food (name, price) {
  Product.call(this, name, price);
  this.category = 'food';
}

const food = new Food('cheese'.5);
console.log(food.name); // 'cheese'
Copy the code
  • callThe first argument is to change the object to which the function is pointing, and the following arguments are of the formarg1, arg2...In the form of
  • applyBasic with:callThe difference is that the second argument is an array[arg1, arg2...]
  • bindChange:thisThe scope returns a new function that will not be executed immediately

Iii Final Realization

Returns the directory

Here’s a list of goals to achieve today:

  1. handwrittencall
  2. handwrittenapply
  3. handwrittenbind

3.1 write a call

Returns the directory

Function.prototype.myCall = function(context = globalThis) {
  // Set fn as the method to call myCall
  context.fn = this;

  // Get the remaining parameters
  const otherArg = Array.from(arguments).slice(1);

  // Call this method, passing in the rest of the arguments
  context.fn(otherArg);

  // Pass the execution result of this method to result
  let result = context.fn();

  // Delete this variable
  delete context.fn;

  // Return result
  return result;
};

this.a = 1;

const fn = function() {
  this.a = 2;
  console.log(this.a);
}

fn.myCall(fn);
Copy the code

3.2 write a apply

Returns the directory

Function.prototype.myApply = function(context = globalThis, arr) {
  // Set fn as the method to call myCall
  context.fn = this;

  let result;

  // If there are arguments, pass them in
  // Return the result to result
  if (arr) {
    result = context.fn(arr);
  } else { // Do not pass
    result = context.fn();
  }

  // Delete this variable
  delete context.fn;

  // Return result
  return result;
};

this.a = 1;

const fn = function() {
  this.a = 2;
  console.log(this.a);
}

fn.myApply(fn);
Copy the code

3.3 write a bind

Returns the directory

Function.prototype.myBind = function(context = globalThis) {
  // Set fn as the method to call myCall
  const fn = this;

  // Get the remaining parameters of the method
  const otherArg = [...arguments].slice(1);

  // Set a new method to return
  const result = function() {

    // Gets an argument to return the method body
    const resultArg = [...arguments];

    // If called by new, bind this to the instance object
    if (this instanceof result) {
      fn.apply(this, otherArg.concat(resultArg));
    } else { // Otherwise bind context as a normal functionfn.apply(context, otherArg.concat(resultArg)); }}// Bind the prototype chain
  result.prototype = Object.create(fn.prototype);

  // Return the result
  return result;
};

this.a = 1;

const fn = function() {
  this.a = 2;
  console.log(this.a);
}

fn.myBind(fn);
fn();
Copy the code

OK, got it? Let’s get on the train and continue our study

The Arguments object

Returns the directory

  • MDN – Arguments

Arguments is an array-like object corresponding to the arguments passed to the function.

function fun(a, b, c) {
  console.log(arguments[0]); / / 1
  console.log(arguments[1]); / / 2
  console.log(arguments[2]); / / 3
}
Copy the code

The Arguments object is not an Array.

It is similar to Array, but does not have any Array attributes other than the Length attribute and index element.

Convert arguments to an array:

// ES5
var arg1 = Array.prototype.slice.call(arguments);
var arg2 = [].slice.call(arguments);

// ES6
var arg3 = Array.from(arguments);
var arg4 = [...arguments];
Copy the code

Arguments can be used to retrieve method body arguments for handwritten call/bind/apply, just as arguments can be used to retrieve second and subsequent arguments for handwritten call array.from (arguments).slice(1).

Five call

Returns the directory

5.1 the original call

Returns the directory

  • MDN – call

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

Note: The syntax and actions of this method are similar to those of apply(), except that call() accepts a list of arguments, while apply() accepts an array of arguments.

  • Grammar:function.call(thisArg, arg1, arg2, ...)
    • thisArg: Optional. infunctionUsed when the function is runthisValue.
    • arg1, arg2, ...: Specifies the parameter list
function Product (name, price) {
  this.name = name;
  this.price = price;
}

function Food (name, price) {
  Product.call(this, name, price);
  this.category = 'food';
}

const food = new Food('cheese'.5);
console.log(food.name); // 'cheese'
Copy the code

5.2 write a call

Returns the directory

First we need to understand the nature of call:

  1. ifobj.call(null), thenthisShould be directedwindow
  2. ifobj1.call(obj2)And who calls it,thisTo whom (here it isobj2A)
  3. callYou can pass in multiple parameters, so you can useargumentsThis is the field to get all the arguments. willargumentsAfter converting the array, get the parameters other than the first one
  4. Set a variable that you can delete when you’re done

In conclusion:

The JS code for hand-written call:

Function.prototype.myCall = function(context = globalThis) {
  // Set fn as the method to call myCall
  context.fn = this;

  // Get the remaining parameters
  const otherArg = Array.from(arguments).slice(1);

  // Call this method, passing in the rest of the arguments
  context.fn(otherArg);

  // Pass the execution result of this method to result
  let result = context.fn();

  // Delete this variable
  delete context.fn;

  // Return result
  return result;
};

this.a = 1;

const fn = function() {
  this.a = 2;
  console.log(this.a);
}

fn.myCall(fn);
Copy the code

A little understanding of its internal process, and then let’s practice:

The anti-shake function is bound to handwritten call

<! DOCTYPEhtml>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0, the maximum - scale = 1.0, user - scalable = no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Write a call</title>
</head>
<body>
  <button class="btn">123</button>

  <script>
    (function() {
      Function.prototype.myCall = function(context) {
        const newContext = context || window;
        newContext.fn = this;
        const otherArg = Array.from(arguments).slice(1);
        newContext.fn(otherArg);
        const result = newContext.fn(otherArg);
        delete newContext;
        return result;
      };

      const debounce = function(fn) {
        let timer = null;
        return function() {
          clearTimeout(timer);
          timer = setTimeout(() = > {
            fn.myCall(this.arguments);
          }, 1000); }}let time = 0;
      const getNumber = function() {
        console.log(++time);
      }

      const btn = document.querySelector('.btn');
      btn.addEventListener('click', debounce(getNumber)); }) ()</script>
</body>
</html>
Copy the code

So we know the handwritten call.

6 the apply

Returns the directory

6.1 native apply

Returns the directory

  • MDN – apply

The apply() method calls a function with a given this value and arguments in the form of an array (or array-like object).

  • Grammar:function.apply(thisArg, [argsArray])
    • thisArg: Mandatory. infunctionUsed when the function is runthis
    • [argsArray]: Optional. An array or array-like object whose array elements are passed as individual argumentsfuncFunction.
const numbers = [5.6.2.3.7];

const max = Math.max.apply(null, numbers);
console.log(max); / / 7

const min = Math.min.apply(null, numbers);
console.log(min); / / 2
Copy the code

6.2 write a apply

Returns the directory

Let’s start by writing apply by hand. Remember that this method is similar to call and is not difficult to understand:

Function.prototype.myApply = function(context = globalThis, arr) {
  // Set fn as the method to call myCall
  context.fn = this;

  let result;

  // If there are arguments, pass them in
  // Return the result to result
  if (arr) {
    result = context.fn(arr);
  } else { // Do not pass
    result = context.fn();
  }

  // Delete this variable
  delete fcontext.fnn;

  // Return result
  return result;
};

this.a = 1;

const fn = function() {
  this.a = 2;
  console.log(this.a);
}

fn.myApply(fn);
Copy the code

Practice with custom Apply + anti-shake:

<! DOCTYPEhtml>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0, the maximum - scale = 1.0, user - scalable = no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>DOM manipulation</title>
</head>
<body>
  <button class="btn">123</button>

  <script>
    (function() {
      Function.prototype.myApply = function(context, arr) {
        const newContext = context || window;
        newContext.fn = this;
        console.log(newContext.fn)
        if(! arr) { result = newContext.fn(); }else {
          result = newContext.fn(arr);
        }

        delete newContext;
        return result;
      };

      const debounce = function(fn, number) {
        let timer = null;
        return function() {
          clearTimeout(timer);
          timer = setTimeout(() = > {
            fn.myApply(this, number);
          }, 1000); }}const getNumber = function(time) {
        console.log(time);
      }

      let number = [1.2.3.4.5];
      const btn = document.querySelector('.btn');
      btn.addEventListener('click', debounce(getNumber, number)); }) ()</script>
</body>
</html>
Copy the code

In this way, we can figure out handwritten apply.

Seven bind

Returns the directory

7.1 native bind

Returns the directory

  • MDN – bind

The bind() method creates a new function, and when bind() is called, this of the new function is specified as the first argument to bind(), and the remaining arguments will be used as arguments to the new function.

  • Grammar:function.bind(thisArg, arg1, arg2, ...)
    • thisArg: acts when a binding function is calledthisThe value that the argument passes to the target function.
    • arg1, arg2, ...: Arguments that are preset into the argument list of the binding function when the target function is called.
  • Return value: a copy of the original function with the specifiedthisValue and initial parameters
const module = {
  x: 42.getX: function() {
    return this.x; }};const unboundGetX = module.getX;
console.log(unboundGetX()); // undefined
UnboundGetX = module.getx
// Make this in getX refer to window
// There is no x method in the window
// Add window. X = 43

const boundGetX = unboundGetX.bind(module);
console.log(boundGetX()); / / 42
// Bind this to module
Copy the code

7.2 write a bind

Returns the directory

Writing bind by hand is a bit complicated, but don’t panic. Read it a few times to get a sense of the pattern:

Function.prototype.myBind = function(context = globalThis) {
  // Set fn as the method to call myCall
  const fn = this;

  // Get the remaining parameters of the method
  const otherArg = [...arguments].slice(1);

  // Set a new method to return
  const result = function() {

    // Gets an argument to return the method body
    const resultArg = [...arguments];

    // If called by new, bind this to the instance object
    if (this instanceof result) {
      fn.apply(this, otherArg.concat(resultArg));
    } else { // Otherwise bind context as a normal functionfn.apply(context, otherArg.concat(resultArg)); }}// Bind the prototype chain
  result.prototype = Object.create(fn.prototype);

  // Return the result
  return result;
};

this.a = 1;

const fn = function() {
  this.a = 2;
  console.log(this.a);
}

fn.myBind(fn);
fn();
Copy the code

Eight topics

Returns the directory

Call, bind, bind, apply, call, bind, bind, bind, call, bind, bind

8.1 This points to Question 1

Returns the directory

var color = 'green';

var test4399 = {
  color: 'blue'.getColor: function() {
    var color = 'red';
    console.log(this.color); }};var getColor = test4399.getColor;
getColor(); // Output what?
test4399.getColor(); // Output what?
Copy the code

A. green B. blue C. green D. blue

8.2 This points to question 2

Returns the directory

var myObject = {
  foo: 'bar'.func: function() {
    var self = this;
    console.log(this.foo);
    console.log(self.foo);
    (function() {
      console.log(this.foo);
      console.log(self.foo);
    })()
  }
}
myObject.func();
Copy the code

What does the program output?

  • A: Bar bar bar bar
  • B: Bar bar bar undefined
  • C: bar bar undefined bar
  • D: undefined bar undefined bar

Answer: C

  1. The first onethis.fooThe outputbarBecause at presentthisPointing to the objectmyObject.
  2. The secondself.fooThe outputbarBecause theselfthisA copy of, with reference tomyObjectObject.
  3. The thirdthis.fooThe outputundefinedBecause of this IIFE (execute function expression immediately)thisPoint to thewindow.

4. The fourth self.foo prints bar. Since the anonymous function has no self in its context, it looks up the scope chain to find self pointing to myObject from the parent function that contains it.

Ix References

Returns the directory

  • MDN – Arguments【 Reading Suggestions: 5min】
  • MDN – call【 Reading Suggestions: 5min】
  • MDN – apply【 Reading Suggestions: 5min】
  • MDN – bind【 Reading Suggestions: 5min】
  • The CALL and apply methods are not used to emulate the BIND method of ES5[Reading Suggestions: 1H]
  • JavaScript deep simulation of call and apply【 Reading Suggestions: 20min】
  • This, apply, call, bind[Recommended Reading: 30min]
  • Interviewer: Can you simulate implementing JS call and apply methods【 Reading Suggestions: 10min】
  • Call apply bind【 Reading Suggestions: 20min】
  • Call apply and bind【 Reading Suggestions: 10min】

Jsliang’s document library is licensed by Junrong Liang under the Creative Commons Attribution – Non-commercial – Share alike 4.0 International License. Based on the github.com/LiangJunron… On the creation of works. Outside of this license agreement authorized access can be from creativecommons.org/licenses/by… Obtained.