Nowadays, all kinds of frameworks and tools “run amok”, everywhere in the principle and source code, more cross-end technology needs us to explore, but if the basic skills are not good, learn what is half the effort, the effect is very bad, take time at the same time to blow confidence. This article, the first (10) in the series of “light talk front end” planned by me, aims to share the native JavaScript knowledge with you systematically and logically, helping you to easily understand the knowledge system and better understand and memorize. I will do my best to live up to expectations.

Data types, data storage, and encapsulation.

Why do we say “encapsulate” and not “encapsulate data”? Because we encapsulate more behavior.

Same old rule — start at the beginning and work your way up.

An anecdotal evidence

About seven years ago, I joined a once famous CDC (user research and experience design), is still very young at that time, the team for the sake of taking care of “novice” like me, opened a “pig run” training project, give me some topic, by comparing young leaders to explain, one of the theme is “renju”.

The middle of the matter is not to say, the summary is: did not write out (lazy, also do not know how to write).

Arrived explain that day, can’t hand in, also do not have what punishment, obediently listen to big guy explain.

I forgot the specific content. At the end of the talk, someone asked me, “This is a packaged one, and then try to change it into” six chess, eight chess, ten chess “. Then I really can, and I was impressed.

In fact, later on, it’s not that complicated, just write a way to implement the board, and then make the number of squares and rules into configurable variables. Although not complex, it reflects a very important feature of function – encapsulation and reuse.

function

A function is a mathematical concept that we all learned in high school that expresses a relationship between a data set and a target value.

Functions in JavaScript are similar in that they express a relationship between parameters and return values. The relationship depends on the code inside the function. Like this:

function add(x,y){
    return x + y
}
Copy the code

It’s a function of the sum of two numbers.

Of course, functions in the programming world have fewer constraints and can have no arguments or return values.

let a,b;
function init(){
    a = 1
    b = 2
}
Copy the code

This function, when called, requires no arguments and returns no value, but it changes the data in the global scope.

Given the definition and characteristics of functions, when do we need to use them?

The first reaction, of course, is “encapsulation”.

Encapsulate what? “The behavior”

Why encapsulate? Using a piece of code to achieve “a purpose”

Three key words come up — encapsulation, behavior, and a purpose

These three are not isolated; their effects are complementary.

Encapsulating a function that is easy to maintain and reuse, with a clear purpose, has a clear behavior, and, of course, with a good name, the icing on the cake, makes the logic of the code clearer, easier to read, and easier to test.

The function of family

The above paragraph gets right to the point, and now it’s time to look at what functions look like.

Naming functions

We’ve already seen named functions, the most common way to define them. The function keyword is followed by the function name, followed by parentheses and optional arguments, and finally the function body.

function add(x,y){
    return x + y
}
Copy the code

Anonymous functions

Functions that have no name are commonly seen in one of the following forms.

Functional expression

let add = function(a,b){
    return a + b
}
Copy the code

event

Let link = document.getelementById ('link') link.onclick = function(){// code}Copy the code

Execute function immediately

What does immediate execution mean? So we defined the add function, and we execute that function, or we call it, so we can add(x,y).

Immediate execution is called at the same time as the definition, like this:

(function () {... } ()) // or (function(){... }) ()Copy the code

Enclosing an anonymous function with the familiar call parentheses is an immediate function.

Arrow function

The arrow function is a new member of ES6 and is itself a different type of function from the one defined previously, but it is also an anonymous function and is discussed here.

Specifically, the function I mentioned above.

let add = function(a,b){
    return a + b
}
Copy the code

It can be written like this:

Let add = (a,b) => {return a + b} // let add = (a,b) => a + bCopy the code

The most intuitive feeling is to become simple, what is the specific difference, later ‘dig a dig’ part will be detailed.

The callback function

The callback function can also be classified as anonymous function, but it and ordinary functions appear in a different form, said separately.

Let’s take a very common example.

SetTimeout (()=>{console.log(' execute me ')},1000)Copy the code

This code means that after 1000ms, execute the arrow function inside, where the arrow function appears as a callback. Note that the “when, what” clause means that callback functions are triggered, otherwise they are normal functions.

methods

We usually call a function a “function”, not a “method”, but if a function belongs to an object, it is called a method of that object.

Of course, this is not strictly true. Even functions defined globally can also be called global methods and can be called using Windows. Such as:

const people = {
    run(){
        console.log('I can run')
    }
}
people.run()
Copy the code

So in this code, we’re going to call run a method of people.

Ok, definition, purpose and form of existence, let’s go a little deeper.

The function itself

After introducing the existence form of the function, the function itself has what attributes or methods.

  • Name: indicates the function name
  • Length: number of parameters (no default values, no remaining parameters)
  • Arguments: Object used to store arguments
  • Prototype: Actual save locations for methods like toString() and valueOf()
  • Apply ()/call() : calls functions in a specific context and binds this
  • Bind () : Create an instance of the function and bind this

Let’s take a look at the following two code examples:

apply()/call()

function sum(num1, num2) { return num1 + num2; } function callSum(num1, num2) { return sum.call(this, ... arguments); } function applySum(num1, num2){ return sum.apply(this, [num1, num2]); } the console. The log (callSum (10, 10)); / / 20 console. The log (applySum (10, 10)); / / 20Copy the code

bind()

const color = "red";
const o = {
    color: "blue"
}
function sayColor(){
    console.log(this.color);
}
let objectSayColor = sayColor.bind(o);
objectSayColor(); //blue
Copy the code

One detail to mention here is that all three methods can be used to change the direction of this. The obvious difference is that call() and apply() are direct calls, while bind() just creates.

Now that you have a general idea of functions, let’s dig into something more interesting and useful.

Dig around (including frequent interview questions)

ascension

The concept of promotion is familiar, that is, it can be used before a defined line of code, such as a variable defined with var, but the value may be undefined.

So functions can be promoted. Why? Functions are variables, but instead of holding values of basic types, functions are variables.

In code writing, we can take advantage of this feature, we can write the business code at the head of the file, function definition at the bottom, so that when it is not necessary, we can only look at the logical code, only need to find the relevant code when viewing or modifying the function.

Such as:

run()
function run(){
   console.log('I can run')
}
Copy the code

But this is not necessary, and is not always the case in actual projects, as long as there is such a phenomenon of ascension.

So the question is, is that okay?

run2()
var run2 = function(){
    console.log('I can run')
}
Copy the code

That’s not going to work, it’s going to be a function definition, it’s going to be a variable definition, there’s no run2 method.

Thus it can be seen that although functions are essentially variables, they are different from variable declarations. Variables only “declare” promotion, while functions promote as a whole.

Also note that if there are two functions with the same name, the later declaration overrides the first declaration, not the other way around.

closure

Closures are a very common topic, and there are many debates on the Internet. It’s not important to argue about them, but to understand the point, and then to know how they are used and what they do.

Closures exist in many forms, including a brief list of them:

  • Returns the function

That’s the most intuitive

function sayName(){
    var name="hello";
    return function(){
        return name;
    }
}
var fnc = sayName();
console.log(fnc())//hello
Copy the code

Let’s talk about closures in their simplest form (both based on ES5) :

How many scopes does JavaScript have?

Global scope, function scope

2. Local variables

Variables defined by var in a function are local variables that can only be used in the function and cannot be accessed externally.

So what’s different about this code?

The return value is a function that calls a local variable. 3. The returned function is assigned to the external variable FNC

The result is the FNC function, which uses the variable name from another function (sayName) and prints Hello.

This is what closures do, breaking the bounds of scope and preserving variables in context that should have been destroyed.

So why do some people say that a function is a closure? Closures are not used everywhere functions exist, because functions are the soil where closures exist (defined) and are formed in the form of functions (returned).

Let’s look at some other common forms:

One, the assignment

var fn1; function fn(){ var name="hello"; Fn1 = function(){return name; } } fn() console.log(fn1())Copy the code

Second, the participation

function fn(){ var name="hello"; return function(){ return name; }} var fn1 = fn() function fn2(f){console.log(f()); } fn2(fn1) // Execute output fn2Copy the code

Third, getter/setter

Expose common methods and hide private variables.

Function fn(){var name='hello' setName=function(n){name= n; } getName=function(){ return name; Return {setName, getName}} var fn1 = fn(); console.log(fn1.getName()); //getter fn1.setName('world'); //setter changes name console.log(fn1.getName()) in closure; //getterCopy the code

Four, caching,

The operation result is cached. You do not need to repeat the operation for the same parameter.

var fn = (function () { var arr = []; Return function (val) {if (arr.indexof (val) == -1) {arr.push(val); } else {console.log(" this function does not need to be executed this time "); }}; }) (); fn(10); fn(10); fn(100);Copy the code

I have written another article about closures before, but there are more examples here. Closures are versatile and powerful, and need more attention and summary in order to better understand and master them.

The constructor

This may be confusing to a lot of beginners, but what’s a constructor? What functions need to be constructed?

Don’t get trapped in this trap. There is a fundamental difference between the use of constructors and ordinary functions, and this difference is the key to the puzzle.

Look at the phenomenon first.

Constructors have two characteristics when used:

Capitalize the first letter of the new operator

Uppercase is just formatting, the key is the new operator.

Function People(name,age){this.name = name this.age = age} const liming = new People(' liming ',18) liming // {name: 'Li Ming ', age: 18}Copy the code

The phenomenon here is that you define a function, use the new operator, and generate an object. So what happened behind new?

  • Create a new object
  • Point the object prototype to the constructor’s prototype
  • Point the constructor’s this to the object being created
  • The newly created object is returned if the return value is a primitive type, otherwise the reference type defined in the function is returned

It is because of such a process that the above effect appears.

So, there is no need to confuse constructors with functions. The first step is to use functions to construct an instance of an object.

The difference between an arrow function and a normal function

After ES6, arrow functions appeared, which looked like removing the function keyword and adding arrows (=>) between parentheses and braces, but in reality there are quite a few differences, mainly the limitation of arrow functions, as follows:

  • Can only be anonymous functions
  • Used in a declarative place, there is no such thing as promotion
  • There is no Arguments object for storing arguments
  • Cannot be used to construct object instances, i.e., new
  • There is no this binding, and you cannot change this binding by using bind, apply, call, etc
  • No Prototype object

These are the main ones, not the other uncommon ones.

So much for the definition and features of functions and their use, let’s move on to another topic.

Functional programming

I often hear some great people talk about “programming paradigm”, which means the way of programming. It is the same as a person’s travel, such as driving a car, taking a boat, or taking a plane.

Functional programming is one type of programming paradigm.

Let’s start with a little code.

Const beforeList = [1,2,3,4] let afterList = [] for(let I = 0; i<= beforeList.length - 1; If (beforeList[I] > 2){afterlist.push (beforeList[I])}} afterList = beforelist.filter (item=>{return item > 2}) console.log(afterList) // [3,4]Copy the code

Writing one and writing two will give you the same answer, but how are they different?

The second method uses the filter() method and the output is determined by the return value of the callback function.

Oh, I see, functional programming is programming with functions.

That’s true in formal terms, but they fall into two categories of programming: “procedural” and “declarative.”

“Procedural” : follow a process or step (written method 1).

“Declarative” : expresses only what is to be done and does not care about the internal implementation details (notation 2).

In addition, true functional programming meets several criteria.

  • Pure functions

What is “pure”, that is, the operation based on the parameters, the output depends only on the input, the same parameters always return the same result, and do not change things outside the scope.

There is a special word for “not changing things outside the scope of action” called “side effect”, popular understanding, a person caught a cold, go to buy cold medicine, take two times, cold symptoms relieved, but began to loose bowels, loose bowels is the side effect.

  • immutability

Data is immutable, const? Freeze? Inoperable?

No, it means that you do not change the original data directly, but instead create a copy of the data, using the copy for all operations.

Let me give you an example.

Array splice() and slice() methods

splice()

Const beforeList = [1,2,3,4] console.log(beforelist.splice (0,2)) console.log(beforelist.splice (0,2)) The console. The log (beforeList. Splice (0, 2)) / / / / [1, 2] [3, 4] / / []Copy the code
Const beforeList = [1,2,3,4] console.log(beforelist.slice (0,2)) console.log(beforelist.slice (0,2)) The console. The log (beforeList. Slice (0, 2)) / / / / [1, 2] / [1, 2] / [1, 2]Copy the code

The splice() method produces different results after multiple calls to the same parameter, which is not pure and also changes the original data, which is not functional programming characteristics, whereas slice() can achieve the desired effect.

  • Higher-order functions

Functional programming requires the use of higher-order functions.

What is a higher-order function? A function that passes other functions as arguments or returns a value is called a higher-order function.

In practical application, it can be shown as follows:

recursive

Recursion can be understood in two typical scenarios.

1. Almost any loop can be implemented recursively. 2. Tree structure is often used to achieve depth traversal by recursion.

So, recursion is doing the same thing over and over again, but changing the data progressively until there’s no more data to process.

Classic example: the Fibonacci sequence

1, 1, 2, 3, 5, 8, 13, 21…

function fibonacci(n) {
    if (n == 1 || n == 2) {
        return 1
    };
    return fibonacci(n - 2) + fibonacci(n - 1);
}
fibonacci(30)
Copy the code

This is a crude version with a lot of room for optimization, but it’s the most straightforward use to show recursion.

It is worth noting that recursion has certain disadvantages: high time and space consumption, double computation, stack overflow (possibly).

These shortcomings is there a way to do optimization, such as: cache, but JS engines have an underlying optimization scheme is given, and is called “tail recursion optimization”, except that it implemented the code is a requirement, can only be in function performs the last step of the last line (not necessarily) returns a function, and should not do other operations. The performance is as follows:

Function f(x){return g(x); } function f(x){let y = g(x); return y; Function f(x){return g(x) + 1; }Copy the code

Curry.

Currization is the technique of transforming a function that takes multiple arguments into a function that takes a single argument (the first argument of the original function) and returning a new function that takes the remaining arguments and returns the result.

Language is a pale and awkward way to describe this concept. Look at a typical interview question:

The sum (2, 3) = = 5; sum(2)(3) == 5; The sum (2 and 4) = = 9; sum(2)(3)(4) == 9;Copy the code

It may seem confusing at first glance, but we can sort out its features:

  • Each call returns a function that can be called continuously
  • Multiple calls store cumulative values and can be returned
  • Between the return value and the target value is ==, there’s an implicit conversion, toString() is called

Thus, sum can be written as follows:

function sum (... Args) {// No argument if (! args.length) return; Function add (list) {return list.reduce((prev, cur) => {return prev + cur}, 0)} let total = add(args) function k (... Args) {total += add(args) return k}Copy the code

At this point, the implementation of the accumulation of the Curry function is complete, but in practice, there may be more than this one application, so parameters and methods need to be flexible, so can we implement the more general Curry function? The answer is yes.

General Edition (ES6) :

function curry(fn, args) { var length = fn.length; var args = args || []; return function(){ newArgs = args.concat(Array.prototype.slice.call(arguments)); if (newArgs.length < length) { return curry.call(this,fn,newArgs); }else{ return fn.apply(this,newArgs); }}}Copy the code

General Edition (ES6) :

const curry = (fn, arr = []) => (... args) => ( arg => arg.length === fn.length ? fn(... arg) : curry(fn, arg) )([...arr, ...args])Copy the code

Compose (combination)

Compose and Curry seem like close Cousins, because both Compose and Curry use a function to encapsulate the logic that implements interactions between other functions and parameters.

Compose differs in that it decouples logic into multiple functions, and then combines them together in the way of Compose, which processes external data successively through each function to generate results.

const add = num => num + 10 const multiply = num => num * 2 const foo = compose(multiply, add) function compose(... Funcs) {// funcs is converted to an array of incoming methods // No incoming methods, If (funcs.length === 0) {return arg => arg} // If (funcs.length === 1) {return funcs[0]} // if (funcs.length === 1) {return funcs[0]} // Return funcs.reduce((a, b) => (... args) => a(b(... args))) } foo(5) // 30Copy the code

Compose combines the “addition” and “multiplication” operations so that parameter 5 goes through both operations to produce the final result.

To briefly summarize, what are the benefits of functional programming?

  • Easy extension
  • Easy to modular
  • Easy to reuse
  • Easy to test
  • Easy to reasoning

Functional programming has been around for a long time, but in recent years it’s been gaining traction in the front end, as evidenced by popular frameworks like React and Vue.

conclusion

So that’s the end of our discussion of functions.

But one thing seems to be missing, which is, why is function a first-class citizen?

We often say that everything in JavaScript is an “object” and emphasize the importance of archetypes and inheritance. Shouldn’t “objects” be first-class citizens?

In fact, “object” need not be jealous here, it is of course very important, but it can do things function can also do, but function has it does not necessarily have, and let’s look at some features of functions:

  • As a normal function, encapsulation, reuse
  • It has its own scope and has closure properties
  • As a constructor, construct the object instance
  • It can be passed and called as a variable
  • As a function parameter
  • As a function return value
  • Functions themselves are also objects

In view of this, functions are first-class citizens and deserve to be.

But because it has so many features, it’s not easy to use it well and use it differently in different situations.

Here are a few things to practice and think about:

  • “Unpacking” and “sealing” : the granularity of unpacking and the magnitude of encapsulation
  • Flexible: packaging should not be too rigid, as flexible as possible, or similar requirements will be packaged in addition, resulting in certain code redundancy, reusability can not be fully reflected
  • Advanced usage: Advanced usage can achieve many powerful effects and get twice the result with half the effort

So much verbose, still can not cover all aspects of the function, welcome to discuss together, or later have the opportunity to supplement.

Guess what the next one will be? ~

The first-class citizens of the JavaScript world — functions

Series of articles:

【 Talk about the front end 】 good basic skills, easy to learn with me

Small role, big use — variable

Why is everything an object?

[Talking about the front end] Those “unreasonable value” operations

Digital games in JavaScript

【 Talk about front-end 】 “string” jianghu

【 Talk about the front end 】 Before there is “object”

【 Talk about the front end 】 After “object”

Arrays are the cornerstone of advanced data structures