Continue with the previous article "How to Write High-Quality JS Code" This time I will sort out the knowledge points of javascript functions.
2. Use functions
Functions provide programmers with main abstract functions and implementation mechanisms. Functions can independently implement multiple different features in other languages, such as procedures, methods, constructors, and even classes or modules.
2.1 Understand the differences between function calls, method calls and constructor calls
For object-oriented programming, the constructor of functions, methods and classes are three different concepts.
Usage mode:
1. Function call
The code copy is as follows:
function hello(username){
return "hello" + username;
}
2. Method call
The code copy is as follows:
var obj = {
hello : function(){
return "hello , " + this.username;
},
username : "floraLam"
};
ohj.hello();//"hello , floraLam"
This variable is bound to the object because the hello method is defined in the obj object. We can also assign a copy of the same function reference in another object and get the same answer.
The code copy is as follows:
var obj2 = {
hello : obj.hello(),
username : "floraLam"
};
3. Use the constructor
The code copy is as follows:
function User(name,passwordHash){
this.name = name;
this.passwordHash = passwordHash;
}
Calling User using the new operator is considered a constructor.
The code copy is as follows:
var u = new User("floraLam","123");
Unlike function calls and method calls, the constructor call takes a completely new object as the value of this variable and implicitly returns this new object as the call result. The main responsibility of the constructor is to initialize the new object.
2.2 Proficient in advanced functions
Higher-order functions are nothing more than functions that take functions as parameters or return values, and use functions as parameters (usually called callback functions, because higher-order functions "subsequently call" it) is a particularly powerful and expressive idiom, and is also widely used in js programs.
Consider the standard sort method of arrays. In order to work for all arrays, the sort method requires the caller to decide how to compare any two elements in the array.
The code copy is as follows:
function compareNumber(x,y){
if(x < y){
return -1;
}
if(x > y){
return 1;
}
return 0;
}
[3,1,4,1,5,9].sort(compareNumbers);//[1,1,3,4,5,9]
The code copy is as follows:
[3,1,4,1,5,9].sort(function(x,y){
if(x < y){
return -1;
}
if(x > y){
return 1;
}
return 0;
});//[1,1,3,4,5,9]
The above example uses an anonymous function to further simplify.
Learning to use higher-order functions can often simplify code and eliminate tedious boilerplate code. For simple conversion of string arrays, we can use a loop to implement it like this:
The code copy is as follows:
var names = ["Fred","Wilma","Pebbles"];
var upper = [];
for(var i = 0,n = names.length ;i< n;i++){
upper[i] = names[i].toUpperCase();
}
upper;//["FRED","WILMA","PEBBLES"];
Using the convenient map method of arrays, you can eliminate loops and convert elements one by one using just one local function.
The code copy is as follows:
var names = ["Fred","Wilma","Pebbles"];
var upper = names.map(function(name){
return name.toUpperCase();
});
upper;//["FRED","WILMA","PEBBLES"];
In addition, for example, we want to create several methods to create different strings with common implementation logic, and each loop creates a string by connecting the calculation results of each independent part.
The code copy is as follows:
function bulidString(n,callback){
var result = "";
for(var i = 0 ; i < n ;i++){
result += callback(i);
}
return result;
}
var alphabet = bulidString(26,function(i){
return String.fromCharCode(aIndex + i);
});
alphabet;//"abcdefghijklmnopqrxtuvwxyz";
var digits = buildString(10,function(i){ return i;})
digits;//"0123456789"
var random = buildString(9,function(){
random += String.fromCharCode(Math.floor(Math.random()*26)+aIndex
});
random;//"yefjmcef"(random)
This will give readers a clearer understanding of what the code can do without in-depth implementation details.
Remark
JavaScript returns the formula for random numbers (between mns) of the specified range: Math.random()*(nm)+m
At the same time, pay attention to the requirements of the question and whether it is required to return a positive integer.
2.3 Call mode
Calling a function will pause the execution of the current function and pass control rights and parameters to the new function. In addition to the formal parameters defined at the time of declaration, each function receives two new additional parameters: this and arguments.
This is a very important parameter, and its value is determined by the calling pattern.
Here are 4 very important calling patterns in JavaScript:
a. Method invocation pattern
b. The function invocation pattern
c. The constructor invocation pattern
d. Apply call pattern the apply invocation pattern
There are differences in how these patterns initialize key parameters this
1. Method invocation method
When a function is a method of an object, we call it a method. When a method is called, this is bound to the called object.
The code copy is as follows:
var myObj={
val:0,
increment:function(inc){
this.val+=typeof inc ==="number"? inc:1;
},
get_val:function(){return this.val;}
}
myObj.increment();// 1
myObj["increment"](2);//3
summary:
1. The method in which the context of the object they belong to can be obtained through this is called a public method
2. When using a function with a . or subscript expression, it is the method call mode, and this object is bound to the previous object.
3. A function can use this to access an object, so it can retrieve the object's value or change the object's value. Bind this to the object occurs when called.
2. The function invocation pattern
When a function is not an object's property, it is called as a function. When a function is called as a function calling pattern, this is bound to the global object. This is a JavaScript design error and continues.
The code copy is as follows:
function add(x,y){
return x+y;
}
myObj.double=function(){
var that=this;
var helper=function(){
that.val=add(that.value,that.value);
//The wrong way of writing may be like this, why is it wrong? Because when the function is called as an internal function, this has been bound to the wrong object, and the global object does not have a val property, so the incorrect value is returned.
//this.val = this.val+this.val;
}
helper();
}
myObj.double();//6
3. The constructor invocation pattern
JavaScript is a language based on prototype inheritance, which means that objects can directly inherit attributes from other objects, and the language is classless.
If you call a function with new, you will get a new object that hides the prototype member connected to the function, and this will also be bound to the new object.
The new prefix also changes the behavior of the return statement. This is not the recommended programming method either.
The code copy is as follows:
var Foo = function(status){
this.status = status;
}
Foo.prototype.get_status = function(){
return this.status;
}
//Construct a Foo instance
var myFoo = new Foo("bar");
myFoo.get_status();//"bar"
4. Apply call the pattern the apply invocation pattern
Because JavaScript is a functional object-oriented language, functions can have methods.
The Apply method has two parameters. The first is to bind the value to this, and the second is the parameter array. That is to say, the Apply method allows us to build an array and use it to call the function, which allows us to select the value of this and also allows us to select the value of the array.
The code copy is as follows:
var array = [3,4];
var sum = add.apply(null,array); // 7
var statusObj = {status:"ABCDEFG"};
Foo.prototype.pro_get_status = function(prefix){
return prefix +"-"+this.status;
}
var status = Foo.prototype.get_status.apply(statusObj);// "ABCDEFG"
var pro_status = Foo.prototype.get_status.apply(statusObj,["prefix"]);// "prefix -ABCDEFG"
Typically, the receiver of a function or method (level bound to the value of this special keyword) is determined by the caller's syntax. In particular, the method call syntax binds the method to this variable by the lookup object. However, sometimes it is necessary to call functions using a custom receiver. At this time, you need to use the call method or bind method to customize the receiver to call the method
2.4 Extract methods with defining recipients using bind method
Since the method is no different from the attributes whose values are functions, it is also easy to extract the method of the object and extract the function as a callback function and pass it directly to the higher-order function.
But it is also easy to forget to bind the extracted function to the extracted object.
The code copy is as follows:
var buffer = {
entries: [],
add :function(s){
this.entries.push(s);
}
}
var source = ["867","-","5309"];
source.forEach(butter.add);//error:entries is undefined
At this time, the recipient of butter.add is not the butter object. The receiver of the function depends on how it is called, and the forEach method is called in the global scope, so the implementation of the forEach method uses the global object as the default receiver. Since there is no entries attribute in the global object, this code throws an error.
The forEach method allows the caller to provide an optional parameter as the receiver of the callback function.
The code copy is as follows:
var source = ["867","-","5309"];
source.forEach(butter.add,butter);
But not all higher-order functions are careful and thoughtful to provide users with the receiver of callback functions.
There are two solutions:
1) Create an explicit buffer object method to call add encapsulation function. Regardless of how the encapsulation function is called, it always ensures that its parameters are pushed into the target array.
The code copy is as follows:
var source = ["867","-","5309"];
source.forEach(function(s){
butter.add(s);
});
2) The bind method of the function object requires a receiver object and generates an encapsulation function that calls the original function with the method called by the receiver object.
The code copy is as follows:
var source = ["867","-","5309"];
source.forEach(butter.add.bind(buffer));
Remark
buffer.add.bind(buffer) creates a new function instead of modifying the buffer.add function:
buffer.add === buffer.add.bind(buffer); //false
The above is all about this article, I hope you like it.