preface


The purpose of this article is to put a finishing touch on the map function that was not written out in the last interview. Its content takes map function as a line to sort out many knowledge points involved in it and give me the feelings and thoughts when learning and writing. Since what I feel and think, it must be inevitable that there are some personal opinions, I hope you are not stingy to correct, but also hope light spray!!

The map function is a black box


I remember when I first knew JS map function

[1,2,3]. Map (e, I, arr) => {return2*e; / / minus [2]})Copy the code

Having studied C briefly in college, the first time I saw this use I felt quite magical. I had no idea how it worked, just a rough idea of how you wanted to create a new array based on the original array, just write the logic in the callback function. It’s like a black box to me. But unconsciously, some concepts (the relationship between already and not/active and passive) are blurred in my subconscious mind.

Sorry, map function implementation does not work


  • I finally got a job interview from this black box. The interviewer asked me to write the map function by hand. I was at a loss! Although I feel like I can kick it off, there’s always something wrong. There’s a reason you didn’t do it when you were put on the floor and rubbed.
  • On the one hand, when writing this article, I realized that I had covered all the knowledge points needed to implement MAP, but I only used it as a theoretical guide, without connecting it with practice. Let me put what I’ve learned to use today.
  • On the other hand, there are some misconceptions about some concepts. Although these misconceptions seem insignificant, they really affect me a lot. So let this article be a farewell to these uninvited guests.

Interest groups behind the MAP black box


According to my personal entry into JS mind, if you have some knowledge of the following, even if you are not very skilled, you can easily implement map function. (This is just a brief explanation for implementing map, please refer to other literature for details)

Data types and storage

Basic data types and reference data types are different in JS. When we assign A value from A variable that stores A value of A primitive data type to another variable B, the essence is value passing. The two variables store two independent values. However, if the reference data type is address passing in nature, then the two variables store the address of the same data, so A and B will affect each other.

  • A function is a reference data type that is stored in heap memory and is referred to by assigning it to a variable that stores the starting address of the function in heap memory.
  • Here also want to pull more, about assignment, deep, shallow copy problems, comparative study can quickly master. Also speaking of storage has to mention garbage recycling mechanism, can secretly learn, string.

2. Functions are first-class citizens

We know that JS is a multi-paradigm language, which includes functional programming. So functions in JS just like any other reference data type can be stored in arrays, passed as function parameters, assigned to variables, assigned as object property values, etc.

  • As the property value of the object

    If we define an object f and assign a function myFn to the attribute fn in f, then our f.fn attribute already refers to the function and can be called through f.fn().

  • Pass it as a function parameter

    Here we declare a fn function that takes a function as an argument and executes it. We declare a callback function. Callback is then passed to fn as an argument, and the fn function is executed. As a result, the callback is executed in fn.If you really understand this part, the golden bell jar of the Map function will be the last FIG leaf for you.

3. Prototype and prototype chain/new constructor calls

Var arr = [1,2,3] creates an Array and assigns it to the variable arr, essentially the same way var arr = new Array(1,2,3). (There is also a new constructor call that you should know about.) The Array represented by arR can then be called an instance of Array, with the _proto_ attribute pointing to the prototype object of the array. prototype constructor.

  • Now let’s take a step at the mystery of Map

  • When accessing an attribute, the system searches for the attribute in this instance object (ARR) first. If the attribute is not found, the system searches for the attribute in the prototype object (array. prototype) to which the pointer points. That’s right. The most common map function we use is array.prototype. map.
  • To get a little bit more elaborate here, let’s create an array and assign its starting address to h, similarly to g. But h is not equal to g. For reference data types, the g and H variables store the starting address of the data in heap memory, and there are two data addresses in memory at the same time, so they are not equal. The object arr._proto_ points to is the same reference data type in the heap as the array. prototype object. Arr. Map finds array.prototype. map pointing to functions that must therefore be equal.
  • A bit more, reading and modifying properties of objects is very different from reading and modifying scoped variables. If you’re interested, you can study it, and you’ll soon master it.

4

JS function this pointing problem is no longer outlined, roughly divided into four rules plus a special arrow function. [1,2,3].map (callback) = array.prototype.map (callback); We then pass the callback function as an argument to the map function for later calling and executing the related logic, but how do we find the original array in the function called? That’s right by this in the function.

  • By the implied transformation in the this pointing rule (this is essentially an object in the execution context created when the function is executed, so the pointing of this is determined by the call point), when we call the function pointing to a.fin (), this in the function refers to object A. In the same way, when implementing a map function to find the original array, the map function this refers to the instance array itself. [1,2,3].map() this refers to the array.

5. Callback functions

JS learning the first time to contact the callback function, once felt that I quite understand the callback, later found that they really do not understand, still think they understand! Now let’s take a look at the map callback in action.

  • I’ve always thought of callbacks as active, but in fact the incoming callbacks are passive. Think of a time when we define a function to implement some function, and then pass the parameter to execute that function. But a callback function is essentially a function declaration, and the logic is executed because the callback function is then passed arguments and called, which is called.

  • So there’s already and there’s not. The native map function is defined, and when the map function is called to implement the relevant logic, Its internal execution passes each element of the array (item/ element value, index/ element index, arR/original array) into the callback function callback and calls it as callback(item, index, arr). Therefore, we know that the callback will be passed the specified arguments and invoked. Therefore, when we only need to declare the callback function passed in, we can take the callback function parameter as the value of the corresponding array element, and implement the related logic on this basis. In effect, the parameters in the declared callback are treated as the parameters (item, index, arR) passed in when the map execution calls the callback internally

  • In fact, the above two points are summed up in the past we always declare the function first, then pass the parameter call. Now, when we understand the map function, we are confronted with the fact that it has been determined that when a callback is called into a map, it will be called inside the map function, and that the callback is invoked by the state passing in a fixed argument. So we can say that we have already established that the callback will be automatically executed internally, just short of declaring the callback and passing it into the map for execution. So the current understanding of a callback function is that it will be called.

  • As shown above, we define a sumTwoItemFlag function that takes a callback and passes objects A and B to that callback for execution, so when we execute sumTwoItemFlag we pass in a declared callback and do the logic in the callback. These are the arguments that were passed in when the callback was called, and we already know that the arguments in the callback are the a and B objects in sumTwoItemFlag. Based on this, we simply pass in the callback as a or B, and execute the desired logic.
  • It’s essentially the opposite. But it can achieve the normal logic of declaration first and call later in our minds, and it’s much more flexible. Although the callback function is executed with fixed parameters, the map callback function is flexible, so you can flexibly implement the array operation according to the different callbacks passed by individuals, which is really a big profit! Call back awesome!!
  • Implementing JSONP with Promises is a bit trickier. (This part seems repetitive and wordy, but you chose to use it as emphasis.)

Handwritten code


I believe that after reading the content you have a very clear understanding of map. In fact, I think that if you can master the above, then the majority of handwritten methods should not be a problem. So let me post the code to write the map. (Writing an article is really a tiring job, post it out, write not move!)

Map implementation

Array.prototype.myMap = function(callback, context) {
    var arr = this;
    var res = [];
    context = context ? context : window;
    for(let i = 0; i < arr.length; i++) {
        let tem = callback.call(context, arr[i], i, arr);
        res.push(tem); 
    }
    return res;
}
Copy the code

Reduce the implementation of the

I’m sure you can implement a Reduce function with just a little bit of ingenuity.

Array.prototype.myReduce = function(callback) { var arr = this; var res; <! (typeof(callback)); / / If (typeof(callback)! == "function") throw new Error("not a function"); if(arguments.length < 2 && arr.length === 0) throw new Error("empty array with no initial value"); if(arguments.length < 2 && arr.length === 1) return arr[0]; if(arguments.length > 1 && arr.length === 0) return arguments[1]; res = arguments.length > 1? arguments[1] : arr.shift(); for(let i = 0; i < arr.length; i++) { res = callback(res, arr[i], i, arr); } return res; }Copy the code

Map Reduce implementation

Array.prototype._myMap = function(callback, context) {
    context = context ? context : window;
    return this.reduce((accum, item, index, arr) => 
        [...accum, callback.call(context, item, index, arr)]
    , []);
}
Copy the code

conclusion


  • Don’t get into the bull ‘s-eye. I believe you can see that the above is just a simple version of the map function implementation, about this method to implement the map function, its boundary case is really too much. I was lucky enough ((┬ _ ┬)) to dive in and try to implement an ideal map. The result is too much time with too little effect. After reading the source code, I feel really stupid!
  • The direction of study cannot be mistaken! Why do you call yourself stupid? When I implemented it, I was still manually testing boundary cases with native maps. After spending a lot of time, I finally decided that I couldn’t handle it and had to look at the source code. After reading the source code began to doubt life. In fact, if you think about it carefully, you can understand that there is no need to implement a perfect map. What can you say if you copy a perfect map? Want to understand to see the source ah, still there with a * * as intent to detect the truth from the surface, or manual. On the other hand, the interviewer may ask this question to test your basic skills, but it may not be perfect. So when learning, do not get the wrong direction, not to get into the wrong point.
  • Want to explore the true face of a technology, if you do not understand, really can not do it, to learn the source code. That’s the only consolation. When I was learning Webpack, I also wanted to understand the true appearance of this black box. At that time, IT was also a manual exploration from the table into the box, but finally I couldn’t go on, so I called it a day. Fortunately, I had gained something at that time. This article will strengthen my determination to study the source code as a variety of black boxes in the future.

Looking forward to


  • I still feel a little unskilled in arrow function, so I’m going to study it again.
  • Next, I want to explore the true appearance of Webpack again. At present, I want to start with the source code. If it is too difficult, I will supplement the pre-knowledge involved, and then continue to attack the source code.
  • Yesterday, when I was watching the crawler practice in node development, I was surprised to find that I could understand the logic business of module invocation mixed with some callbacks that I had been vaguely familiar with before. I was no longer half-covered. It feels like writing articles is really a good way to output from the previous pure input. It can not only make new friends, but also comb and summarize the knowledge learned. Now we’ve gone from pure input to want output, and we’ll keep going. But also deeply understand, according to the conservation of energy, these outputs are based on the previous input, so the future days should not forget to charge it!!
  • I thought THAT QQ screenshots would be kept in the local, but when WRITING this article, I was surprised to find that dragging QQ screenshots into the editing page would actually have the address of the picture, and in non-local circumstances after entering the URL really have the picture, I feel I really know nothing about the network. After a rough thought (a shot in the dark), it is likely that the successful screenshot will put the picture into the database storing my QQ corresponding data, and then you can access the picture through the URL. And then you want to know. There is such an unknown operation behind the QQ screenshots we used to take for granted. It’s really time to pay more attention to the things we take for granted in daily life.