JavaScript functions are first-class language' elements in the sense that they are plain objects.
Functionis the constructor (i.e., runtime type) of function objects.Rule(s)
- The absence of static typing in JavaScript suppresses any control about functions' arguments and returned objects: their types and number.
- Functions may return values while they do not declare any
return.const f = function () { /* <=> 'return;' <=> 'return undefined;' */ }; console.assert(f instanceof Function); console.assert(typeof f === 'function'); console.assert(f.constructor === Function);Example
const my_function = function (my_parameter) { // Forbidden in strict mode (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments): // console.log(arguments.callee); return ++my_parameter; }; console.log(my_function(0)); // '1' is displayed...Arguments' default values
Rule(s)
- Functions support default values for (right-most) arguments as in C++, Java, etc.
Example
// 'Run' as a static function in a class: static Run(name = "FranckBarbier", job = "Trainer") { …Anonymous functions
Rule(s)
- Anonymous functions have no name. Similar to lambda expressions, they are introduced for on-the-fly needs.
- In JavaScript, one may use inside a function the predefined
argumentsvariable.arguments[0]represents the first argument (if any),arguments[1]represents… Etc.Example
const f = function (g) { // 'f' is defined... console.log("'arguments' is a predefined array that lets the access to the passed arguments: " + arguments.length); g(); }; f(function () { // 'f' is called with anonymous function as single argument... console.log("This no-name function plays the role of 'g' in 'f'"); });Lambda expressions
Rule(s)
- Similar to Java, C++…, JavaScript supports lambda expressions; they lighten the way by which anonymous functions are handled in the code.
Example
const f = (g, i = 0) => { // 'f' is defined by means of a lambda expression console.log(g(i)); }; // Calling f... f(function (my_i) { // 'f' is called with an anonymous function as parameter return ++my_i; }/*, 1*/); // Calling f, another style... f(my_i => { // 'f' is called with a lambda function as parameter return ++my_i; }/*, 1*/); // Calling f, yet another style... f(my_i => ++my_i/*, 1*/); // Implicit 'return'Variable number of arguments
Rule(s)
- Same to Java, C++…, JavaScript (from JavaScript 6) supports the idea of having a variable number of arguments in the form of arrays.
Example
const h = function (a = -1, ...bs /*, c*/ /* <- error! */) { let sum = a; bs.forEach(b => { console.log("b: " + b); sum += b; }); console.log("Sum: " + sum); }; // Note that default value for 'a' is useless: h(1, 2, 3); // 'Sum: 6' is displayed, i.e., '1' is substituted for 'a' h(...[1, 2, 3]); // <=> 'h(1, 2, 3);'Rule(s)
- In TypeScript, a variable number of parameters is based on the
…syntax as well.Example Lottery.ts.zip
![]()
class Lottery { public static Draw(bonus_number: number, ...numbers: Array<number>) /* Return type is inferred... */ { … } … let result = Lottery.Draw(6, 43, 12, 3, 32, 34, 22); console.assert(result.draw[0] === 43);Meta-functions
Rule(s)
- Meta-functions are part of the
Functionconstructor itself:callandapply.Example
const her_function = function (her_parameter) { console.log("'this': " + this + " 'her_parameter': " + her_parameter); // Forbidden in strict mode (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/): // console.log(arguments.callee); }; // First arg. plays the role of 'this' inside the function while '0' is substituted for 'her_parameter': her_function.call("Catherine", 0); // "'this': Catherine 'her_parameter': 0" is displayed... // First arg. plays the role of 'this' inside the function while '[0]' is a one-element array containing '0' as unique element: her_function.apply("Catherine", [0]); // "'this': Catherine 'her_parameter': 0" is displayed...Generator functions
Rule(s)
- Generator functions are used in conjunction with the possibility of iterating over any object provided that the latter one implements an iterator protocol (see also more on generators … and more on iterators…)
Example Generator.ts.zip
// 'Meal' type has a method named '@@iterator' ('Symbol.iterator' <=> '@@iterator'), which is a generator function: type Meal = { when: string, taste: string, [Symbol.iterator](): IterableIterator<string> }; const meal: Meal = { when: "today", taste: "medium", [Symbol.iterator]: function* (from = "yesterday") { // Key 'Symbol.iterator' (i.e., '@@iterator') is added as 'Generator' object yield from; yield "today"; yield "tomorrow"; } }; const {when: first_part, ...remaining_part} = meal; console.info(first_part); // 'today' console.info(JSON.stringify(remaining_part)); // '{"taste":"medium"}' console.info(Object.getOwnPropertySymbols(meal)[0] === Symbol.iterator); // 'true' const iterator: IterableIterator<string> = meal[Symbol.iterator](); console.info(iterator.next().value); // 'yesterday' // Spread syntax only applies on iterable objects (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax): console.info([...meal]); // '[ 'yesterday', 'today', 'tomorrow' ]' for (const value of meal) console.info(value); // 'yesterday' 'today' 'tomorrow'The case of
thisRule(s)
thismay refer to different objects (includingwindow) depending upon the execution context. JavaScript offers means to control to whatthishas to refer to (see also here…).Example (PURE JavaScript)
const o = {}; Object.defineProperty(o, "simple_array", { value: [null, 0, "ABC"], enumerable: true, configurable: true, writable: true }); o.simple_array_processing = function () { for (let i = 0; i < this.simple_array.length; i++) this.simple_array[i] = null; // Great, 'this' is set to the appropriate "current" object, i.e., 'o'! }; o.simple_array_processing(); // Call... console.log(JSON.stringify(o.simple_array)); // '[null,null,null]' o.simple_array_processing = function () { // Erase prior version... this.simple_array.forEach(function (element) { console.assert(this !== o); console.log("What is 'this'? " + Object.getOwnPropertyNames(this).join(" - ")); } /* ,this */); // Uncommenting leads to 'this === o' }; o.simple_array_processing(); // Call... o.simple_array_processing = function () { // Erase prior version... this.simple_array.forEach(element => { // 'this' in lambda expression is set *IN A STATIC WAY* console.assert(this === o); console.log("What is 'this'? " + Object.getOwnPropertyNames(this).join(" - ")); } /* ,this */); // No need of injecting 'this' as second argument of 'forEach' }; o.simple_array_processing(); // Call...Rule(s)
- Using
bindis a way to inject whatthishas to refer to.Example (PURE JavaScript)
const my_iteration = function (element) { console.assert(this === o); console.log("What is 'this'? " + Object.getOwnPropertyNames(this).join(" - ")); }; o.simple_array_processing = function () { // Erase prior version... this.simple_array.forEach(my_iteration.bind(this)); }; o.simple_array_processing(); // Call...