preface

In my previous article, “How this works and how to use it,” I mentioned call and apply.

Their main purpose is to change the direction of this. Call and Apply are not used much in everyday work, except when writing base classes or common library methods.

However, when suddenly encountered, need to think about to turn around. So today, let’s take a good look at the differences between the two approaches and some of the tricks they can use. Finally, you’ll see the method of bind, which has a similar use.

Something Call and Apply have in common

What they all have in common is the ability to change the context in which a function is executed, handing a method from one object to another, and executing it immediately.

Why change the execution context? To give a small example in my life: I don’t have time to cook at ordinary times, but I want to cook a pickled tuk for my children on weekends. But there was no proper pot, and I didn’t want to go out and buy one. So I asked a neighbor to borrow a pot to use, so that both achieve the purpose, and save money, kill two birds with one stone.

The same goes for changing the execution context. Object A has A method, and object B, for some reason, needs the same method. Do we extend A method to object B alone, or do we borrow A method from object A? Of course, it is borrowed from the A object, which completes the requirements and reduces the memory footprint.

In addition, they are written in a similar way. The object that calls call and apply must be a Function. Next, we will talk about the specific way of writing, that is the main difference between them.

The difference between call and apply

The difference between them is mainly reflected in the way the parameters are written. So let’s look at how they’re written.

The call of the writing

Function call (obj, [param1 [, param2 [paramN], [...]]])

The following points need to be noted:

  • The object that calls the call must be a Function.
  • The first argument to call is an object. The caller of Function will point to this object. If not, it defaults to the global object window.
  • Starting with the second argument, you can accept any argument. Each parameter is mapped to the parameter of the Function at the corresponding location. But if you pass in all the arguments as an array, they map to the first argument of the Function as a whole, and then the arguments are null.
Function func (a,b,c) {} func.call(obj, 1,2,3) [1,2,3]) // The parameter func receives is actually [1,2,3],undefined,undefined

The apply of writing

Function.apply(obj[,argArray])

What needs to be noted is:

  • The caller must be a Function and take only two arguments, the first of which has the same rule as call.
  • The second argument, which must be either an array or an array of classes, is converted to an array of classes, passed into the Function, and mapped to the corresponding parameter of the Function. This is an important difference between call and apply.
Apply (obj, [1,2,3]) // func receives arguments that are actually 1,2,3 func. Apply (obj, {0: 1, 1: 2, 2: 3, length: 3}) // The arguments func receives are actually 1,2,3

What is a class array?

Let’s start with arrays, which we’re all familiar with. It can be called from a corner marker, such as array[0]; Has the length attribute length; You can do it either through the for loop or through the forEach method.

So, what is a class array? As the name suggests, it is an object that has the characteristics of an array. For example, the object below is an array of classes.

let arrayLike = {
    0: 1,
    1: 2,
    2: 3,
    length: 3
};

The class array ArrayLike can be called from a corner marker, has a length attribute, and can also be iterated through a for loop.

Class arrays, which are often used, but we don’t usually notice them. For example, the method we use to get a DOM node returns an array of classes. For example, all arguments that you get in a method using arguments are also an array of classes.

However, it is important to note that a class array cannot use methods on the array prototype chain such as forEach, splice, push, etc. It is not a real array after all.

Use of call and apply

Some usage scenarios for CALL and APPLY are listed below. Disclaimer: There is no scenario in this example where Call or Apply is required. It’s just a personal habit.

Call usage scenarios

1. Object inheritance. Take the following example:

function superClass () { this.a = 1; this.print = function () { console.log(this.a); } } function subClass () { superClass.call(this); this.print(); } subClass(); / / 1

Subclass inherits superClass’s print method and a variable through the call method. In addition, the Subclass can extend its own other methods.

2. Borrowing methods. Remember the class array? If it wants to use a method on the Array prototype chain, it can do this:

let domNodes = Array.prototype.slice.call(document.getElementsByTagName("*"));

This allows domNodes to apply all methods under the Array.

Some clever uses of Apply

1, Math. Max. Use it to get the largest item in the array.

let max = Math.max.apply(null, array);

Similarly, to get the smallest item in an array, we could do this:

let min = Math.min.apply(null, array);

2, implement two arrays merge. Before ES6’s extension operator, we could have done it with Array.prototype.push.

let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];

Array.prototype.push.apply(arr1, arr2);
console.log(arr1); // [1, 2, 3, 4, 5, 6]

The use of the bind

And then finally BIND. The interpretation on MDN is that the bind() method creates a new function and sets the this keyword to the supplied value when called. And when a new function is called, the given argument list is the first number of items in the original function’s argument sequence.

Its syntax is as follows:

Function.bind(thisArg[, arg1[, arg2[, ...]]])

The bind method is similar to apply and call in that it also changes the this point in the body of a function. The difference is that the return value of the bind method is a function, and it needs to be called later before it is executed. Apply and call, on the other hand, are called immediately.

Consider the following example:

function add (a, b) { return a + b; } function sub (a, b) { return a - b; } add.bind(sub, 5, 3); Bind (sub, 5, 3)(); bind(sub, 5, 3)(); // return 8

If the first argument to bind is null or undefined, this points to the global object window.

conclusion

The main purpose of call and apply is to change the execution context of an object and to do so immediately. They are written slightly differently in terms of parameters.

Bind can also change the execution context of an object. Unlike Call and Apply, the return value is a function that needs to be called later before it is executed.

Finally, I’d like to share a quick way to remember Call and Apply that I saw on Zhihu:

The cat ate the fish, the dog ate the meat, Ultraman beat the little monster.

Someday the dog wants to eat fish

A cat. Eat fish.

The dog gets the fish

The cat became a fine cat and wanted to fight the monster

Ultraman. Fight little monster. Call (cat, little monster)

Cats can fight little monsters, too

PS: Welcome to pay attention to my official account “Super Brother front-end stack”, to exchange more ideas and technology.