JS basic function advanced

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>

Keywords: Javascript Front-end

Added by mlefebvre on Fri, 28 Jan 2022 03:21:06 +0200