Former article: juejin. Cn/post / 693826…
Day 1: Start coding again
So here we go. Remember the convention of the function?
Student: Remember, data is immutable.
Fang: Ok, so I guess you can’t write code now.
Student:?
Fang: Don’t believe me? Let me challenge you. Print the value of each item by traversing array = [‘a’,’b’,’c’]. Let me write it in JS.
Student: Easy
for(let i = 0; i< array.length; i++){
console.log(array[i])
}
Copy the code
Fang: You forgot the appointment so soon? Data is immutable!
Student: I didn’t change array
Fang: I ++ changed the value of I
Student: Ah, that counts
Fang: That’s right. Instead of i++, you answer it again
Student: So I use “for in”
for(let key in array){
console.log(array[key])
}
Copy the code
The key is still changing. The key is equal to 0 at the beginning, 1 at the end, and 2 at the end. Think again.
Student: I have another trick:
array.forEach(item => console.log(item))
Copy the code
Fang: I finally got to the edge, this time “you” did not change the value of the data
Student: So am I right?
Fang: Almost. Array. forEach is a built-in array interface for JAVASCRIPT. Can you write your own forEach? Satisfies the following usages
forEach(array, item => console.log(item))
Copy the code
Student: Don’t use array forEach to write your own forEach…
Fang: well
Student: Can you use while
F: no, while i++ is the same as for
Student: Recursion?
Fang: try
Student: yes
let array = ['a','b','c']
let forEach = (array, fn) => {
if(array.length === 0) return
fn(array[0])
forEach(array.slice(1), fn)
}
forEach(array, item => console.log(item))
Copy the code
Fong: Yes, this time you kept your promise: “Data is immutable”. I wonder why you gave this notation at the end?
Student: I was told to try not to use recursion.
Fang: Let me guess, that person writes JS or Java?
Student: Well, more than one person said that.
Fang: What are the reasons they give?
Student: Easy to “stack overflow”, and “expensive” “waste memory”
Fang: That’s a good point, but that’s just one side of their story. Let’s talk about stack overflow first. Stack overflow requires a “callstack”, right?
Student: Sure
Fang: Did you know that some languages don’t have a Callstack at all? Haskell, for example, doesn’t have a callstack. It uses graphs instead of stacks.
Student: Never heard of it…
Fang: In addition, if we rewrite recursion to tail recursion, or even loop, we can basically eliminate stack overflow.
Student: But if you write recursion as a loop, why not just write a loop?
Fong: you are very keen to find the loophole in my logic, the “tail recursive change loop” here is automatically implemented by the “compiler”! That means programmers focus on writing code and compilers focus on performance optimization.
Student: What is tail recursion?
Fang: I’ll talk about that tomorrow. Today I’ll overturn your mistrust of recursion. Now all you need to know is that by rewriting recursion to tail recursion, with the right compiler, stack overflow is almost no problem.
Student: Wouldn’t a JS or Java compiler work?
Fang: Good question. In fact, compiler and programmer writing is complementary, not constant. Let me ask you first
- Programmers should remember code that performs well, even if readability is abandoned
- Programmers prioritize readability, leaving the compiler to find ways to optimize performance
Which of these two ideas do you support?
Student: I’m not sure, shouldn’t you try to pick the best code?
Fang: Haha, do you think that good code is good?
Student: What does that mean?
Fang: Let me give you an example. You know that ++ I is much better than I ++, right?
Student: Oh? Why is that?
Fang: The reason doesn’t matter. You can read this article or not. Assuming you already know that ++ I is much better than I ++, would you rather write I ++ or ++ I when you write a for loop?
Student: I used to write I ++. Now that you say so, should I write ++ I
If the third statement in the for loop is I ++, the compiler will automatically optimize to ++ I, so you don’t need to memorize so many rules. There are so many optimization tricks on the web that you can memorize a few
Student: The compiler is so smart!
Fang: You don’t want to think that the people who write compilers are much more intelligent than the people who write JS.
Student: Yeah
Fang: There are even times when the quirks you use to improve performance will degrade your program because it won’t be optimized by the compiler. The compiler generally optimizes common writing.
Student: I see
Fang: So programmers should try to write code that conforms to community conventions, and only manually optimize performance at performance bottlenecks. However, due to years of “education” by JS and Java people, newcomers like you have learned to avoid “recursion” as much as possible, so JS and Java compilers don’t need to spend time optimizing the minority writing, which can cause security and debug related problems.
Student: Is recursion “expensive” and “memory wasting” similar misconceptions?
Fang: Yes, if a language feature is used a lot by programmers, the compiler will try to make it faster. Now, can you give up your bias against recursion?
Student: Yes, do I have to give up the JS and Java compilers?
Fang: Yes, the community culture of the two languages is not very compatible with functions, and the major versions of the compiler do not support these optimizations, maybe a future version will.
Student: Let me ask again, “recursion” has no disadvantages?
Fang: Yes, I will talk about it later, but the flaws do not outweigh the disadvantages.
Student: Ok, I’ll write that down, although I’m not completely convinced yet.
Fang: Where did we get here? Oh, from “You can’t write recursion in the first place.” So I give you the second problem, write a function to reverse the string, can not violate the “data immutable” convention oh.
Student: I can write recursively
reverse = (string) => { if(string.length <= 1){return string} let last = string[string.length-1] let head = String. Substr (0, string.length-1) return last + reverse(head)Copy the code
Fang: It’s quite fast
Student: Sure enough, I wrote much faster after I dropped my prejudice, but I still felt that efficiency would be slow and memory would be wasted
Fang: You’ll get used to it in a few days, and I’ll show you how to optimize it. Let’s do one more, quicksort
Student: Easy
/*1*/ quickSort = (array) => {
/*2*/ if(array.length <= 1) {return array}
/*3*/ let [pivot, ...rest] = array
/*4*/ let small = rest.filter(i => i<=pivot)
/*5*/ let big = rest.filter(i => i>pivot)
/*6*/ return [...quickSort(small), pivot, ...quickSort(big) ]
/*7*/ }
Copy the code
Student: This is really cool, but I’m still worried about wasting memory. Lines 3, 4, 5, and 6 are all memory copies
Fong: Well, that’s because JS and Java data is mutable, so you can’t reuse data directly. If the data is immutable, let [pivot,…rest] = array can reuse memory directly
Student: It seems so, what about rest.filter(I => I <=pivot)
Fang: This memory is difficult to optimize. But you know, if you’re writing functional, you’re writing five lines of code, and you’re writing instruction, you’re writing 20 lines of code, and functional is all about logical brevity, making the logic nice, and then optimizing it when you hit a performance bottleneck
Student: Ok
Fang: Wait, how come you still don’t seem to fully accept “data immutable” and always want to change the original memory?
Student: It’s only the first day. I’ll get used to it in a few days
All right, let’s stop here for today and continue tomorrow.
Follow-up: juejin. Cn/post / 693919…