Basic knowledge
Functions are modules that encapsulate reusable code blocks. In JS, functions have features that other languages do not have. Next, we will master the use skills in detail.
Declaration definition
In JS, a Function is also an object. A Function is an instance of the creation of a Function class. The following example is convenient to understand that a Function is an object.
let hd = new Function("title", "console.log(title)"); hd('wgchen'); // wgchen
The standard syntax is to use function declarations to define functions
function hd(num) { return ++num; } console.log(hd(3));
Object literal attribute function
let user = { name: null, getName: function (name) { return this.name; }, //Abbreviated form setName(value) { this.name = value; } } user.setName('wgchen'); console.log(user.getName()); // wgchen
The global function will be declared in the window object, which is incorrect. It is recommended to use the module in the following chapters
console.log(window.screenX); // 1040
When we define the screenX function, we override the window screenX method
function screenX() { return "wgchen"; } console.log(screenX()); // wgchen
When let/const is used, the window will not be pressed in
let hd = function() { console.log("wgchen"); }; window.hd(); //window.hd is not a function
Anonymous function
Function is an object, so you can assign a value to point to the pointer of the function object. Of course, the pointer can also be passed to other variables. Note that it should be followed by; end.
Next, assign an anonymous function to a variable using a function expression
let hd = function(num) { return ++num; }; console.log(hd instanceof Object); //true let cms = hd; console.log(cms(3)); // 4
The function declared in the standard has higher priority. The parser will extract the function first and put it at the top of the code tree. Therefore, the position of the function declared in the standard is not limited, so the following code can be executed normally.
console.log(hd(3)); function hd(num) { return ++num; };
Standard declarations take precedence over assignment declarations
console.log(hd(3)); //4 function hd(num) { return ++num; } var hd = function() { return "hd"; };
Anonymous functions are widely used in programs
function sum(...args) { return args.reduce((a, b) => a + b); } console.log(sum(1, 2, 3)); // 6
Execute function immediately means execute immediately when a function is defined
Can be used to define private scopes to prevent contamination of global scopes
"use strict"; (function () { var web = 'wgchen'; })(); console.log(web); //web is not defined
Using let/const has the block scope feature, so the following methods can also be used to generate private scopes
{ let web = 'wgchen'; console.log(web); // wgchen } console.log(web); // Uncaught ReferenceError: web is not defined
Function promotion
The function will also be promoted to the front, and the priority line will be increased in the var variable
console.log(hd()); // wgchen function hd() { return 'wgchen'; }
Variable function definitions are not promoted
console.log(hd()); // wgchen function hd() { return 'wgchen'; } var hd = function () { return 'blog'; }
Formal parameter argument
A formal parameter is a parameter set when a function is declared, and an actual parameter is a value passed when a function is called.
- When the number of formal parameters is greater than the actual parameters, the formal parameter value without parameters is undefined
- When the number of arguments is greater than the formal parameter, the more arguments will be ignored and no error will be reported
// N1 and N2 are formal parameters function sum(n1, n2) { return n1+n2; } // Parameters 2 and 3 are arguments console.log(sum(2, 3)); //5
The value is undefined when no parameter is passed
function sum(n1, n2) { return n1 + n2; } console.log(sum(2)); //NaN
Default parameters
Let's experience the processing method of the previous default parameters by calculating the annual average sales
//Total: total price year: years function avg(total, year) { year = year || 1; return Math.round(total / year); } console.log(avg(2000, 3)); // 667
Using the new version, the default parameters are as follows
function avg(total, year = 1) { return Math.round(total / year); } console.log(avg(2000, 3));
Let's experience the processing method of the new version of default parameters by sorting,
In the following example, the default value asc is used when the type parameter is not passed.
function sortArray(arr, type = 'asc') { return arr.sort((a, b) => type == 'asc' ? a - b : b - a); } console.log(sortArray([1, 3, 2, 6], 'desc'));
The default parameter should be placed at the end
//total: price, Discount: discount, dis: discount after discount function sum(total, discount = 0, dis = 0) { return total * (1 - discount) * (1 - dis); } console.log(sum(2000, undefined, 0.3));
Function parameters
Functions can be passed as parameters, which is also a syntax rule supported by most languages.
<body> <button>subscribe</button> </body> <script> document.querySelector('button').addEventListener('click', function () { alert('Thank you for your subscription'); }) </script>
Functions can be passed as arguments
function filterFun(item) { return item <= 3; } let hd = [1, 2, 3, 4, 5].filter(filterFun); console.log(hd); // [1,2,3]
arguments is the set of all parameters obtained by the function
The following is an example of summation using arguments
function sum() { return [...arguments].reduce((total, num) => { return (total += num); }, 0); } console.log(sum(2, 3, 4, 2, 6)); //17
Presentation syntax is more recommended
function sum(...args) { return args.reduce((a, b) => a + b); } console.log(sum(2, 3, 4, 2, 6)); //17
Arrow function
Arrow function is a short form of function declaration. It is not recommended to use arrow function when using recursive call, constructor and event handler.
If there are no parameters, you can use null extension
let sum = () => { return 1 + 3; } console.log(sum()); //4
When the function body is a single expression, return processing is not required, and the system will automatically return the calculation result of the expression.
let sum = () => 1 + 3; console.log(sum()); //4
Multiparameter passing is separated by commas, just like normal declaration functions
let hd = [1, 8, 3, 5].filter((item, index) => { return item <= 3; }); console.log(hd);
Parentheses can be omitted when there is only one parameter
let hd = [1, 8, 3, 5].filter(item => item <= 3); console.log(hd);
Recursive call
Recursion refers to the way a function calls itself internally.
- It is mainly used for cyclic operation with uncertain quantity
- There must be an opportunity to exit, otherwise it will fall into a dead circle
Experience recursive calls through factorials
function factorial(num = 3) { return num == 1 ? num : num * factorial(--num); } console.log(factorial(5)); //120
Cumulative calculation method
function sum(...num) { return num.length == 0 ? 0 : num.pop() + sum(...num); } console.log(sum(1, 2, 3, 4, 5, 7, 9)); //31
Recursive printing inverted triangle
****** ***** **** *** ** * function star(row = 5) { if (row == 0) return ""; document.write("*".repeat(row) + "<br/>"); star(--row); }
Recursively modify course hits
let lessons = [ { title: "Media query responsive layout", click: 89 }, { title: "FLEX Elastic box model", click: 45 }, { title: "GRID grid system ", click: 19 }, { title: "Detailed explanation of box model", click: 29 } ]; function change(lessons, num, i = 0) { if (i == lessons.length) { return lessons; } lessons[i].click += num; return change(lessons, num, ++i); } console.table(change(lessons, 100));
Callback function
Functions called by other functions at a certain time are called callback functions, such as functions that handle keyboard and mouse events.
<button id='hd'>button</button> <script> document.getElementById('hd').addEventListener('click', () => alert('Call through callback function')); </script>
Incremental calculation using callback function
let hd = ([1, 2, 3]).map(item => item + 10); console.log(hd)
Expand syntax
The display syntax or point syntax reflects the collection / release feature. When it is used as a value, it is put, and when it is used as a receiving variable, it is received.
let hd = [1, 2, 3]; let [a, b, c] = [...hd]; console.log(a); //1 console.log(b); //2 console.log(c); //3 [...hd] = [1, 2, 3]; console.log(hd); // [1, 2, 3]
The presentation syntax can be used instead of arguments to receive any number of parameters
function hd(...args) { console.log(args); } hd(1, 2, 3, "wgchen"); // [1, 2, 3, "wgchen"]
It can also be used to receive some parameters
function hd(site, ...args) { console.log(site, args); // wgchen (3) [1, 2, 3] } hd("wgchen", 1, 2, 3);
use... You can accept multiple parameters passed in and combine them into an array. The following is the calculation of the combination using point syntax.
function sum(...params) { console.log(params); return params.reduce((pre, cur) => pre + cur); } console.log(sum(1, 3, 2, 4));
When multiple parameters The parameter must be placed later, and the shopping cart product discount is calculated below
function sum(discount = 0, ...prices) { let total = prices.reduce((pre, cur) => pre + cur); return total * (1 - discount); } console.log(sum(0.1, 100, 300, 299));
Label function
Use the function to parse the label string. The first parameter is the array of string values, and the other parameters are label variables.
function hd(str, ...values) { console.log(str); //["site", "-", "", raw: Array(3)] console.log(values); // ["wgchen", "blog"] } let name = 'wgchen',url = 'blog'; hd `site ${name}-${url}`;
this
When a function is called, this is implicitly passed to the function. It refers to the associated object when the function is called, also known as the context of the function.
function call
In the global environment, this is the reference of window object
<script> console.log(this == window); //true </script>
When using strict mode, this is undefined in the global function
var hd = 'wgchen'; function get() { "use strict" return this.hd; } console.log(get()); //Strict mode will generate error Cannot read properties of undefined (reading 'hd')
Method call
When the function is a method of an object, this points to the object
You can create objects in many ways. Here is how to create objects using constructors.
Constructor
When a function is new, it is a constructor. Generally, the constructor contains properties and methods. The context in the function points to the instance object.
The constructor is mainly used to generate objects. By default, this refers to the current object.
function User() { this.name = "wgchen"; this.say = function() { console.log(this); //User {name: "wgchen", say: ƒ} return this.name; }; } let hd = new User(); console.log(hd.say()); // wgchen
Object Literal
- The hd function in the following example does not belong to the object method, so it points to window
- show belongs to the obj object
let obj = { site: "wgchen", show() { console.log(this.site); // wgchen console.log(`this in show method: ${this}`); //this in show method: [object Object] function hd() { console.log(typeof this.site); //undefined console.log(`this in hd function: ${this}`); //this in hd function: [object Window] } hd(); } }; obj.show();
When using functions in methods, some functions can change this, such as forEach. Of course, you can also use apply / call / bind described later
let Lesson = { site: "wgchen", lists: ["js", "css", "mysql"], show() { return this.lists.map(function(title) { return `${this.site}-${title}`; }, this); } }; console.log(Lesson.show()); // ['wgchen-js', 'wgchen-css', 'wgchen-mysql']
You can also define variables that reference this in the parent scope
let Lesson = { site: "wgchen", lists: ["js", "css", "mysql"], show() { const self = this; return this.lists.map(function(title) { return `${self.site}-${title}`; }); } }; console.log(Lesson.show());
Arrow function
The arrow function does not have this. It can also be understood that this in the arrow function will inherit the context when defining the function. It can be understood that it points to the same this as the outer function.
If you want to use this in the context of the function definition, use the arrow function.
The execution environment of the anonymous function in the following example is global, so this points to window.
var name = 'wgchen'; var obj = { name: 'blog', getName: function () { return function () { return this.name; } } } console.log(obj.getName()()); // Return to window Value of name wgchen
In the past, anonymous function calls were used to process defined variables and then used in anonymous functions.
var name = 'wgchen'; var obj = { name: 'blog', getName: function () { var self = this; return () => { return this.name; } } } console.log(obj.getName()()); //Return to window Value of name blog
After using the arrow function, this is the context in which the function is defined. It can also be understood as this in the parent scope when defining
var name = 'wgchen'; var obj = { name: 'blog', getName: function () { return () => { return this.name; } } } console.log(obj.getName()()); // blog
The result of using arrow function in event is not what we want
- The event function can be understood as the object onclick setting value, so this is the current object when the function is declared
- However, when using the arrow function, this is the context of the declared function
Let's experience how this points to an element object when using a normal event function
When using a normal function, this is the current DOM object
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>wgchen</title> </head> <body> <button desc="wgchen">button</button> </body> <script> let Dom = { site: "blog", bind() { const button = document.querySelector("button"); button.addEventListener("click", function() { alert(this.getAttribute("desc")); }); } }; Dom.bind(); </script> </html>
Here is how this points to the context object when using the arrow function
<body> <button desc="wgchen">button</button> </body> <script> let Dom = { site: "blog", bind() { const button = document.querySelector("button"); button.addEventListener("click", event => { alert(this.site + event.target.innerHTML); }); } }; Dom.bind(); </script>
When binding the event handler with handleEvent, this points to the current object instead of the DOM element.
<body> <button desc="wgchen">button</button> </body> <script> let Dom = { site: "blog", handleEvent: function(event) { console.log(this); }, bind() { const button = document.querySelector("button"); button.addEventListener("click", this); } }; Dom.bind(); </script>
apply/call/bind
Changing this pointer can also be understood as an object borrowing method, which is like borrowing something from a neighbor in life.
Principle analysis
this in the constructor is an empty object by default, and then the constructor processes the empty object to have value.
function User(name) { this.name = name; } let hd = new User("wgchen");
You can change the empty object in the constructor, that is, let the constructor this point to another object.
function User(name) { this.name = name; } let wgchen = {}; User.call(wgchen, "blog"); console.log(wgchen.name); // blog
apply/call
call and apply are used to display the context of the setting function. The functions of the two methods are the same. They bind the object to this, but they are different in passing parameters.
- apply uses an array to pass parameters
- call needs to pass parameters separately
- Unlike bind, call/apply executes the function immediately
Introduction to grammar usage
function show(title) { alert(`${title+this.name}`); } let lisi = { name: 'Li Si' }; let wangwu = { name: 'Wang Wu' }; show.call(lisi, 'wgchen'); show.apply(wangwu, ['blog']);
Use call to set function context
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>wgchen</title> </head> <body> <button message="wgchen">button</button> <button message="blog">button</button> </body> <script> function show() { alert(this.getAttribute('message')); } let bts = document.getElementsByTagName('button'); for (let i = 0; i < bts.length; i++) { bts[i].addEventListener('click', () => show.call(bts[i])); } </script> </html>
Find the maximum value in the array
let arr = [1, 3, 2, 8]; console.log(Math.max(arr)); //NaN console.log(Math.max.apply(Math, arr)); //8 console.log(Math.max(...arr)); //8
Implement constructor property inheritance
"use strict"; function Request() { this.get = function(params = {}) { //Combination request parameters let option = Object.keys(params) .map(i => i + "=" + params[i]) .join("&"); return `get data API:${this.url}?${option}`; }; } //Article controller function Article() { this.url = "article/index"; Request.apply(this, []); } let hd = new Article(); console.log( hd.get({ row: 10, start: 3 }) ); //Course controller function Lesson() { this.url = "lesson/index"; Request.call(this); } let js = new Lesson(); console.log( js.get({ row: 20 }) );
Make display and hide panel
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>wgchen</title> </head> <style> * { padding: 0; margin: 0; } body { display: flex; justify-content: center; align-items: center; width: 100vw; height: 100vh; } dl { width: 400px; display: flex; flex-direction: column; } dt { background: #e67e22; border-bottom: solid 2px #333; height: 50px; display: flex; justify-content: center; align-items: center; cursor: pointer; } dd { height: 200px; background: #bdc3c7; font-size: 5em; text-align: center; line-height: 200px; } </style> <body> <dl> <dt>wgchen</dt> <dd>1</dd> <dt>blog</dt> <dd hidden="hidden">2</dd> </dl> </body> <script> function panel(i) { let dds = document.querySelectorAll("dd"); dds.forEach(item => item.setAttribute("hidden", "hidden")); dds[i].removeAttribute("hidden"); } document.querySelectorAll("dt").forEach((dt, i) => { dt.addEventListener("click", () => panel.call(null, i)); }); </script> </html>
bind() is to bind a function to an object
For example, a.bind(hd) can be understood as binding a function to HD object, namely HD a().
- Unlike call/apply, bind does not execute immediately
- bind is a copy function that returns a new function
bind is the behavior of the copy function
let a = function() {}; let b = a; console.log(a === b); //true // bind is the new copy function let c = a.bind(); console.log(a == c); //false
Precautions for binding parameters
function hd(a, b) { return this.f + a + b; } //Using bind generates a new function let newFunc = hd.bind({ f: 1 }, 3); //1 + 3 + 2 parameter 2 is assigned to b, that is, a=3,b=2 console.log(newFunc(2));
Use bind in events
<body> <button>wgchen</button> </body> <script> document.querySelector("button").addEventListener( "click", function(event) { console.log(event.target.innerHTML + this.url); // wgchenblog }.bind({ url: "blog" }) ); </script>
Dynamically change the background color of elements. Of course, the following examples can also be processed by arrow function
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>wgchen</title> </head> <style> * { padding: 0; margin: 0; } body { height: 100vh; font-size: 3em; padding: 30px; transition: 2s; display: flex; justify-content: center; align-items: center; background: #34495e; color: #34495e; } </style> <body> https://wgchen.blog.csdn.net </body> <script> function Color(elem) { this.elem = elem; this.colors = ["#74b9ff", "#ffeaa7", "#fab1a0", "#fd79a8"]; this.run = function () { setInterval( function () { let pos = Math.floor(Math.random() * this.colors.length); this.elem.style.background = this.colors[pos]; }.bind(this), 1000 ); }; } let obj = new Color(document.body); obj.run(); </script> </html>