Suche…


Einführung

Funktionen in JavaScript bieten organisierten, wiederverwendbaren Code, um eine Reihe von Aktionen auszuführen. Funktionen vereinfachen den Codierungsprozess, verhindern redundante Logik und machen Code leichter nachvollziehbar. In diesem Thema werden die Deklaration und Verwendung von Funktionen, Argumenten, Parametern, Rückgabeanweisungen und Gültigkeitsbereich in JavaScript beschrieben.

Syntax

  • Funktionsbeispiel (x) {return x}

  • var beispiel = funktion (x) {return x}

  • (Funktion () {...}) (); // Sofort aufgerufener Funktionsausdruck (IIFE)

  • var Instanz = neues Beispiel (x);

  • Methoden

  • fn.apply (valueForThis [, arrayOfArgs])

  • fn.bind (valueForThis [, arg1 [, arg2, ...]])

  • fn.call (valueForThis [, arg1 [, arg2, ...]])

  • ES2015 + (ES6 +):

  • const Beispiel = x => {return x}; // Pfeilfunktion explizite Rückkehr

  • const Beispiel = x => x; // Pfeilfunktion implizite Rückkehr

  • const example = (x, y, z) => {...} // Mehrere Argumente für die Pfeilfunktion

  • (() => {...}) (); // IIFE mit einer Pfeilfunktion

Bemerkungen

Informationen zu den Pfeilfunktionen finden Sie in der Dokumentation zu den Pfeilfunktionen .

Funktioniert als Variable

Eine normale Funktionsdeklaration sieht folgendermaßen aus:

function foo(){
}

Eine so definierte Funktion ist von jedem Ort innerhalb ihres Kontextes über ihren Namen zugänglich. Manchmal kann es jedoch nützlich sein, Funktionsreferenzen wie Objektreferenzen zu behandeln. Beispielsweise können Sie einer Variablen ein Objekt basierend auf einer Reihe von Bedingungen zuweisen und später eine Eigenschaft von dem einen oder dem anderen Objekt abrufen:

var name = 'Cameron';
var spouse;

if ( name === 'Taylor' ) spouse = { name: 'Jordan' };
else if ( name === 'Cameron' ) spouse = { name: 'Casey' };

var spouseName = spouse.name;

In JavaScript können Sie dasselbe mit Funktionen tun:

// Example 1
var hashAlgorithm = 'sha1';
var hash;

if ( hashAlgorithm === 'sha1' ) hash = function(value){ /*...*/ };
else if ( hashAlgorithm === 'md5' ) hash = function(value){ /*...*/ };

hash('Fred');

Im obigen Beispiel ist hash eine normale Variable. Es wird einer Funktion eine Referenz zugewiesen, wonach die von ihr referenzierte Funktion wie in einer normalen Funktionsdeklaration mit Klammern aufgerufen werden kann.

Das obige Beispiel verweist auf anonyme Funktionen ... Funktionen, die keinen eigenen Namen haben. Sie können Variablen auch verwenden, um auf benannte Funktionen zu verweisen. Das obige Beispiel könnte wie folgt umgeschrieben werden:

// Example 2
var hashAlgorithm = 'sha1';
var hash;

if ( hashAlgorithm === 'sha1' ) hash = sha1Hash;
else if ( hashAlgorithm === 'md5' ) hash = md5Hash;

hash('Fred');

function md5Hash(value){
    // ...
}

function sha1Hash(value){
    // ...
}

Oder Sie können Funktionsreferenzen aus den Objekteigenschaften zuweisen:

// Example 3
var hashAlgorithms = {
    sha1: function(value) { /**/ },
    md5: function(value) { /**/ }
};

var hashAlgorithm = 'sha1';
var hash;

if ( hashAlgorithm === 'sha1' ) hash = hashAlgorithms.sha1;
else if ( hashAlgorithm === 'md5' ) hash = hashAlgorithms.md5;

hash('Fred');

Sie können die Referenz einer von einer Variablen gehaltenen Funktion einer anderen zuweisen, indem Sie die Klammern weglassen. Dies kann zu einem Fehler führen, der leicht zu begehen ist: der Versuch, den Rückgabewert einer Funktion einer anderen Variablen zuzuweisen, aber versehentlich die Referenz der Funktion zuzuweisen.

// Example 4
var a = getValue;
var b = a; // b is now a reference to getValue.
var c = b(); // b is invoked, so c now holds the value returned by getValue (41)

function getValue(){
    return 41;
}

Ein Verweis auf eine Funktion ist wie jeder andere Wert. Wie Sie gesehen haben, kann einer Variablen eine Referenz zugewiesen werden, und der Referenzwert dieser Variablen kann anschließend anderen Variablen zugewiesen werden. Sie können Verweise auf Funktionen wie jeden anderen Wert übergeben, z. B. das Übergeben einer Referenz an eine Funktion als Rückgabewert einer anderen Funktion. Zum Beispiel:

// Example 5
// getHashingFunction returns a function, which is assigned
// to hash for later use:
var hash = getHashingFunction( 'sha1' );
// ...
hash('Fred');


// return the function corresponding to the given algorithmName
function getHashingFunction( algorithmName ){
    // return a reference to an anonymous function
    if (algorithmName === 'sha1') return function(value){ /**/ };
    // return a reference to a declared function
    else if (algorithmName === 'md5') return md5;
}

function md5Hash(value){
    // ...
}

Sie müssen einer Variablen keine Funktionsreferenz zuweisen, um sie aufzurufen. Dieses Beispiel baut auf Beispiel 5 auf und ruft getHashingFunction auf. Anschließend wird die zurückgegebene Funktion sofort aufgerufen und der Rückgabewert an hashedValue übergeben.

// Example 6
var hashedValue = getHashingFunction( 'sha1' )( 'Fred' );

Ein Hinweis zum Heben

Beachten Sie, dass Variablen, die Funktionen referenzieren, im Gegensatz zu normalen Funktionsdeklarationen nicht "gehisst" werden. In Beispiel 2 sind die Funktionen md5Hash und sha1Hash am unteren Rand des Skripts definiert, jedoch sofort verfügbar. Unabhängig davon, wo Sie eine Funktion definieren, "hebt" der Interpreter sie ganz nach oben und ist sofort verfügbar. Dies ist bei Variablendefinitionen nicht der Fall, daher wird folgender Code beschädigt:

var functionVariable;

hoistedFunction(); // works, because the function is "hoisted" to the top of its scope
functionVariable(); // error: undefined is not a function.

function hoistedFunction(){}
functionVariable = function(){};

Anonyme Funktion

Definieren einer anonymen Funktion

Wenn eine Funktion definiert ist, geben Sie ihr oft einen Namen und rufen sie dann mit diesem Namen auf:

foo();

function foo(){
    // ...
}

Wenn Sie eine Funktion auf diese Weise definieren, speichert die Javascript-Laufzeitumgebung Ihre Funktion im Speicher und erstellt dann einen Verweis auf diese Funktion mit dem Namen, den Sie ihr zugewiesen haben. Dieser Name ist dann innerhalb des aktuellen Bereichs verfügbar. Dies kann eine sehr bequeme Methode sein, um eine Funktion zu erstellen, aber Sie müssen einer Funktion keinen Namen zuweisen. Folgendes ist auch absolut legal:

function() {
    // ...
}

Wenn eine Funktion ohne Namen definiert ist, wird sie als anonyme Funktion bezeichnet. Die Funktion wird im Arbeitsspeicher gespeichert, aber die Laufzeitumgebung erstellt für Sie nicht automatisch einen Verweis darauf. Auf den ersten Blick mag es so aussehen, als ob eine solche Sache keine Verwendung hätte, es gibt jedoch mehrere Szenarien, in denen anonyme Funktionen sehr bequem sind.

Zuweisen einer anonymen Funktion zu einer Variablen

Anonyme Funktionen werden häufig verwendet, um sie einer Variablen zuzuweisen:

var foo = function(){ /*...*/ };

foo();

Diese Verwendung anonymer Funktionen wird in Funktionen als Variable ausführlicher behandelt

Anonyme Funktion als Parameter für eine andere Funktion bereitstellen

Einige Funktionen akzeptieren möglicherweise einen Verweis auf eine Funktion als Parameter. Diese werden manchmal als "Abhängigkeitseinspritzungen" oder "Rückrufe" bezeichnet, da sie es der Funktion ermöglichen, Ihren Code "anzurufen", wodurch Sie die Möglichkeit haben, das Verhalten der aufgerufenen Funktion zu ändern. Mit der Map-Funktion des Array-Objekts können Sie beispielsweise jedes Element eines Arrays durchlaufen und dann ein neues Array erstellen, indem Sie auf jedes Element eine Transformationsfunktion anwenden.

var nums = [0,1,2];
var doubledNums = nums.map( function(element){ return element * 2; } ); // [0,2,4]

Es wäre langwierig, schlampig und überflüssig, eine benannte Funktion zu erstellen, die Ihren Geltungsbereich mit einer Funktion überschneidet, die nur an dieser Stelle benötigt wird, und den natürlichen Fluss und das Lesen Ihres Codes unterbrechen (ein Kollege würde diesen Code verlassen müssen, um Ihren Code zu finden Funktion, um zu verstehen, was los ist).

Rückgabe einer anonymen Funktion aus einer anderen Funktion

Manchmal ist es nützlich, eine Funktion als Ergebnis einer anderen Funktion zurückzugeben. Zum Beispiel:

var hash = getHashFunction( 'sha1' );
var hashValue = hash( 'Secret Value' );

function getHashFunction( algorithm ){

    if ( algorithm === 'sha1' ) return function( value ){ /*...*/ };
    else if ( algorithm === 'md5' ) return function( value ){ /*...*/ };

}

Sofortiges Aufrufen einer anonymen Funktion

Im Gegensatz zu vielen anderen Sprachen ist das Gültigkeitsbereich in Javascript auf Funktionsebene und nicht auf Blockebene. (Siehe Funktionsumfang ). In einigen Fällen muss jedoch ein neuer Bereich erstellt werden. Es ist zum Beispiel üblich, einen neuen Gültigkeitsbereich zu erstellen, wenn Sie Code über ein <script> -Tag hinzufügen, anstatt zuzulassen, dass Variablennamen im globalen Gültigkeitsbereich definiert werden (wodurch die Gefahr besteht, dass andere Skripts mit Ihren Variablennamen kollidieren). Eine gängige Methode, um mit dieser Situation umzugehen, ist das Definieren einer neuen anonymen Funktion und das sofortige Aufrufen dieser Funktion, sodass Sie Variablen im Rahmen der anonymen Funktion sicher ausblenden können, ohne Ihren Code Dritten durch einen durchgesickerten Funktionsnamen zugänglich zu machen. Zum Beispiel:

<!-- My Script -->
<script>
function initialize(){
    // foo is safely hidden within initialize, but...
    var foo = '';
}

// ...my initialize function is now accessible from global scope.
// There's a risk someone could call it again, probably by accident.
initialize();
</script>

<script>
// Using an anonymous function, and then immediately
// invoking it, hides my foo variable and guarantees
// no one else can call it a second time.
(function(){
    var foo = '';
}()) // <--- the parentheses invokes the function immediately
</script>

Selbstreferenzielle anonyme Funktionen

Manchmal ist es hilfreich, wenn eine anonyme Funktion auf sich selbst verweist. Beispielsweise muss die Funktion sich möglicherweise selbst rekursiv aufrufen oder Eigenschaften hinzufügen. Wenn die Funktion jedoch anonym ist, kann dies sehr schwierig sein, da sie die Kenntnis der Variablen erfordert, der die Funktion zugewiesen wurde. Dies ist die nicht ideale Lösung:

var foo = function(callAgain){
    console.log( 'Whassup?' );
    // Less then ideal... we're dependent on a variable reference...
    if (callAgain === true) foo(false);
};

foo(true);

// Console Output:
// Whassup?
// Whassup?

// Assign bar to the original function, and assign foo to another function.
var bar = foo;
foo = function(){
    console.log('Bad.')
};

bar(true);

// Console Output:
// Whassup?
// Bad.

Die Absicht hier war, dass die anonyme Funktion sich rekursiv aufruft, aber wenn sich der Wert von foo ändert, wird der Fehler möglicherweise schwer zu verfolgen sein.

Stattdessen können wir der anonymen Funktion einen Verweis auf sich selbst geben, indem Sie ihr einen privaten Namen geben:

var foo = function myself(callAgain){
    console.log( 'Whassup?' );
    // Less then ideal... we're dependent on a variable reference...
    if (callAgain === true) myself(false);
};

foo(true);

// Console Output:
// Whassup?
// Whassup?

// Assign bar to the original function, and assign foo to another function.
var bar = foo;
foo = function(){
    console.log('Bad.')
};

bar(true);

// Console Output:
// Whassup?
// Whassup?

Beachten Sie, dass der Funktionsname auf sich selbst beschränkt ist. Der Name ist nicht in den äußeren Bereich gelaufen:

myself(false); // ReferenceError: myself is not defined

Diese Technik ist besonders nützlich, wenn rekursive anonyme Funktionen als Callback-Parameter behandelt werden:

5
// Calculate the fibonacci value for each number in an array:
var fib = false,
    result = [1,2,3,4,5,6,7,8].map(
        function fib(n){
            return ( n <= 2 ) ? 1 : fib( n - 1 ) + fib( n - 2 );
        });
// result = [1, 1, 2, 3, 5, 8, 13, 21]
// fib = false (the anonymous function name did not overwrite our fib variable)

Sofort aufgerufene Funktionsausdrücke

Manchmal möchten Sie nicht, dass Ihre Funktion als Variable zugänglich ist / gespeichert wird. Sie können einen sofort aufgerufenen Funktionsausdruck (kurz IIFE) erstellen. Dies sind im Wesentlichen selbstausführende anonyme Funktionen . Sie haben Zugriff auf den umgebenden Bereich, aber die Funktion selbst und alle internen Variablen sind von außen nicht zugänglich. Zu IIFE ist Folgendes zu beachten: Selbst wenn Sie Ihre Funktion benennen, werden IIFE nicht wie Standardfunktionen angehoben und können nicht mit dem Funktionsnamen aufgerufen werden, mit dem sie deklariert sind.

(function() {
   alert("I've run - but can't be run again because I'm immediately invoked at runtime,
          leaving behind only the result I generate");
}());

Dies ist eine andere Möglichkeit, IIFE zu schreiben. Beachten Sie, dass die schließende Klammer vor dem Semikolon verschoben und direkt nach der schließenden geschweiften Klammer platziert wurde:

(function() {
   alert("This is IIFE too.");
})();

Sie können Parameter einfach an einen IIFE übergeben:

(function(message) {
   alert(message);
}("Hello World!"));

Außerdem können Sie Werte an den umgebenden Bereich zurückgeben:

var example = (function() {
   return 42;
}());
console.log(example); // => 42

Bei Bedarf kann ein IIFE benannt werden. Obwohl es weniger häufig zu sehen ist, hat dieses Muster mehrere Vorteile, z. B. das Bereitstellen einer Referenz, die für eine Rekursion verwendet werden kann, und kann das Debuggen vereinfachen, da der Name im Callstack enthalten ist.

(function namedIIFE() { 
    throw error; // We can now see the error thrown in 'namedIIFE()'
}());

Während das Umschließen einer Funktion in Klammern die häufigste Art ist, dem Javascript-Parser einen Ausdruck zuzuweisen, kann an Stellen, an denen bereits ein Ausdruck erwartet wird, die Notation präziser gemacht werden:

var a = function() { return 42 }();
console.log(a)  // => 42

Pfeilversion der sofort aufgerufenen Funktion:

6
(() => console.log("Hello!"))(); // => Hello!

Funktionsumfang

Wenn Sie eine Funktion definieren, wird ein Bereich erstellt .

Auf alles, was in der Funktion definiert ist, kann außerhalb der Funktion nicht mit Code zugegriffen werden. Nur Code innerhalb dieses Bereichs kann die innerhalb des Bereichs definierten Entitäten sehen.

function foo() {
  var a = 'hello';
  console.log(a);  // => 'hello'
}

console.log(a);  // reference error

Verschachtelte Funktionen sind in JavaScript möglich und es gelten die gleichen Regeln.

function foo() {
  var a = 'hello';
  
  function bar() {
    var b = 'world';
    console.log(a);  // => 'hello'
    console.log(b);  // => 'world'
  }

  console.log(a);  // => 'hello'
  console.log(b);  // reference error
}

console.log(a);  // reference error
console.log(b);  // reference error

Wenn JavaScript versucht, eine Referenz oder Variable aufzulösen, sucht es im aktuellen Bereich danach. Wenn diese Deklaration im aktuellen Gültigkeitsbereich nicht gefunden wird, steigt der Suchbereich nach oben. Dieser Vorgang wird wiederholt, bis die Deklaration gefunden wurde. Wenn der JavaScript-Parser den globalen Gültigkeitsbereich erreicht und die Referenz immer noch nicht finden kann, wird ein Referenzfehler ausgegeben.

var a = 'hello';

function foo() {
  var b = 'world';

  function bar() {
    var c = '!!';

    console.log(a);  // => 'hello'
    console.log(b);  // => 'world'
    console.log(c);  // => '!!'
    console.log(d);  // reference error
  }
}

Dieses Steigverhalten kann auch bedeuten, dass eine Referenz eine ähnlich benannte Referenz im äußeren Bereich "schattieren" kann, da sie zuerst gesehen wird.

var a = 'hello';

function foo() {
  var a = 'world';

  function bar() {
    console.log(a);  // => 'world'
  }
}
6

Die Art und Weise, wie JavaScript den Bereich auflöst, gilt auch für das Schlüsselwort const . Das Deklarieren einer Variablen mit dem Schlüsselwort const bedeutet, dass Sie den Wert nicht erneut zuweisen dürfen. Wenn Sie ihn jedoch in einer Funktion deklarieren, wird ein neuer Gültigkeitsbereich und damit eine neue Variable erstellt.

function foo() {
  const a = true;

  function bar() {
    const a = false;  // different variable
    console.log(a);   // false
  }

  const a = false;    // SyntaxError
  a = false;          // TypeError
  console.log(a);     // true
}

Funktionen sind jedoch nicht die einzigen Blöcke, die einen Gültigkeitsbereich erstellen (wenn Sie let oder const ). let und const Deklarationen haben einen Gültigkeitsbereich für die Anweisung zum nächsten Block. Sehen Sie hier für eine detailliertere Beschreibung.

Binding `this` und Argumente

5.1

Wenn Sie in JavaScript einen Verweis auf eine Methode (eine Eigenschaft, bei der es sich um eine Funktion handelt) nehmen, erinnert sich das Objekt normalerweise nicht an das Objekt, an das es ursprünglich angehängt wurde. Wenn die Methode auf dieses Objekt verweisen muss, ist this nicht möglich, und der Aufruf führt wahrscheinlich zum Absturz.

Sie können die .bind() -Methode für eine Funktion verwenden, um einen Wrapper zu erstellen, der den Wert this und eine beliebige Anzahl führender Argumente enthält.

var monitor = {
  threshold: 5,
  check: function(value) {
    if (value > this.threshold) {
      this.display("Value is too high!");
    }
  },
  display(message) {
    alert(message);
  }
};

monitor.check(7); // The value of `this` is implied by the method call syntax.


var badCheck = monitor.check;
badCheck(15); // The value of `this` is window object and this.threshold is undefined, so value > this.threshold is false

var check = monitor.check.bind(monitor);
check(15); // This value of `this` was explicitly bound, the function works.

var check8 = monitor.check.bind(monitor, 8);
check8(); // We also bound the argument to `8` here. It can't be re-specified.

Wenn er nicht im Strict - Modus verwendet eine Funktion , um das globale Objekt ( window im Browser) , wie this , es sei denn , die Funktion als Methode bezeichnet wird, gebunden ist , oder mit der Methode namens .call Syntax.

window.x = 12; 

function example() {
  return this.x;
}

console.log(example()); // 12

In Strict - Modus this ist undefined durch Standard

window.x = 12; 
    
function example() {
  "use strict";
  return this.x;
}

console.log(example()); // Uncaught TypeError: Cannot read property 'x' of undefined(…)
7

Operator binden

Der Doppelpunkt- Bindungsoperator kann als verkürzte Syntax für das oben erläuterte Konzept verwendet werden:

var log = console.log.bind(console); // long version
const log = ::console.log; // short version

foo.bar.call(foo); // long version
foo::bar(); // short version

foo.bar.call(foo, arg1, arg2, arg3); // long version
foo::bar(arg1, arg2, arg3); // short version

foo.bar.apply(foo, args); // long version
foo::bar(...args); // short version

Mit dieser Syntax können Sie normal schreiben, ohne sich Gedanken darüber zu machen, dass Sie this überall binden müssen.

Konsolenfunktionen an Variablen binden

var log = console.log.bind(console);

Verwendungszweck:

log('one', '2', 3, [4], {5: 5});

Ausgabe:

one 2 3 [4] Object {5: 5}

Warum würdest du das tun?

Ein Anwendungsfall kann der Fall sein, wenn Sie über einen benutzerdefinierten Logger verfügen und für die Laufzeit entscheiden möchten, welcher verwendet werden soll.

var logger = require('appLogger');

var log = logToServer ? logger.log : console.log.bind(console);

Funktion Argumente, Argumentobjekte, Rest- und Spread-Parameter

Funktionen können Eingaben in Form von Variablen annehmen, die innerhalb ihres eigenen Bereichs verwendet und zugewiesen werden können. Die folgende Funktion nimmt zwei numerische Werte an und gibt ihre Summe zurück:

function addition (argument1, argument2){
    return argument1 + argument2; 
}

console.log(addition(2, 3)); // -> 5

arguments Objekt

Das arguments enthält alle Parameter der Funktion, die einen nicht standardmäßigen Wert enthalten . Es kann auch verwendet werden, wenn die Parameter nicht explizit deklariert sind:

(function() { console.log(arguments) })(0,'str', [2,{3}]) // -> [0, "str", Array[2]]

Obwohl die Ausgabe beim Drucken von arguments einem Array ähnelt, handelt es sich tatsächlich um ein Objekt:

(function() { console.log(typeof arguments) })(); // -> object

function (...parm) {} : function (...parm) {}

In ES6 wandelt die ... -Syntax bei der Deklaration der Parameter einer Funktion die Variable rechts davon in ein einzelnes Objekt um, das alle übrigen nach den deklarierten Parametern angegebenen Parameter enthält. Dadurch kann die Funktion mit einer unbegrenzten Anzahl von Argumenten aufgerufen werden, die Bestandteil dieser Variablen werden:

(function(a, ...b){console.log(typeof b+': '+b[0]+b[1]+b[2]) })(0,1,'2',[3],{i:4});
// -> object: 123  

Spread-Parameter: function_name(...varb);

In ES6 kann die ... -Syntax auch beim Aufruf einer Funktion verwendet werden, indem ein Objekt / eine Variable rechts davon platziert wird. Auf diese Weise können die Elemente dieses Objekts als einzelnes Objekt an diese Funktion übergeben werden:

let nums = [2,42,-1];
console.log(...['a','b','c'], Math.max(...nums)); // -> a b c 42

Benannte Funktionen

Funktionen können entweder benannt oder unbenannt sein ( anonyme Funktionen ):

var namedSum = function sum (a, b) { // named
    return a + b;
}

var anonSum = function (a, b) { // anonymous
    return a + b;
}

namedSum(1, 3);
anonSum(1, 3);

4
4

Ihre Namen sind jedoch privat und liegen in ihrem eigenen Bereich:

var sumTwoNumbers = function sum (a, b) {
    return a + b;
}

sum(1, 3);

Nicht abgerufener ReferenceError: Die Summe ist nicht definiert

Benannte Funktionen unterscheiden sich in mehreren Szenarien von den anonymen Funktionen:

  • Beim Debuggen wird der Name der Funktion in der Fehler- / Stack-Ablaufverfolgung angezeigt
  • Benannte Funktionen werden angehoben, anonyme Funktionen jedoch nicht
  • Benannte Funktionen und anonyme Funktionen verhalten sich bei der Rekursion anders
  • Abhängig von der ECMAScript-Version können benannte und anonyme Funktionen die Funktion name Eigenschaft unterschiedlich behandeln

Benannte Funktionen werden gehisst

Bei Verwendung einer anonymen Funktion kann die Funktion nur nach der Deklarationzeile aufgerufen werden, während eine benannte Funktion vor der Deklaration aufgerufen werden kann. Erwägen

foo();
var foo = function () { // using an anonymous function
    console.log('bar');
}

Nicht abgerufener TypeError: foo ist keine Funktion

foo();
function foo () { // using a named function
    console.log('bar');
}

Bar


Benannte Funktionen in einem rekursiven Szenario

Eine rekursive Funktion kann definiert werden als:

var say = function (times) {
    if (times > 0) {
        console.log('Hello!');

        say(times - 1);
    }
}

//you could call 'say' directly, 
//but this way just illustrates the example
var sayHelloTimes = say;

sayHelloTimes(2);

Hallo!
Hallo!

Was ist, wenn irgendwo in Ihrem Code die ursprüngliche Funktionsbindung neu definiert wird?

var say = function (times) {
    if (times > 0) {
        console.log('Hello!');

        say(times - 1);
    }
}

var sayHelloTimes = say;
say = "oops";

sayHelloTimes(2);

Hallo!
Nicht erfasster TypeError: say ist keine Funktion

Dies kann mit einer benannten Funktion gelöst werden

// The outer variable can even have the same name as the function
// as they are contained in different scopes
var say = function say (times) {
    if (times > 0) {
        console.log('Hello!');

        // this time, 'say' doesn't use the outer variable
        // it uses the named function
        say(times - 1);
    }
}

var sayHelloTimes = say;
say = "oops";

sayHelloTimes(2);

Hallo!
Hallo!

Und als Bonus kann die benannte Funktion auch von innen nicht auf undefined werden:

var say = function say (times) {
    // this does nothing
    say = undefined;
    
    if (times > 0) {
        console.log('Hello!');

        // this time, 'say' doesn't use the outer variable
        // it's using the named function
        say(times - 1);
    }
}

var sayHelloTimes = say;
say = "oops";

sayHelloTimes(2);

Hallo!
Hallo!


Der name Eigenschaft von Funktionen

Vor ES6 hatten genannte Funktionen ihre name Eigenschaften auf ihre Funktionsnamen gesetzt und anonyme Funktionen hatten ihre name Eigenschaften auf die leere Zeichenfolge gesetzt.

5
var foo = function () {}
console.log(foo.name); // outputs ''

function foo () {}
console.log(foo.name); // outputs 'foo'

Post ES6, benannten und unbenannten Funktionen setzen beide ihren name Eigenschaften:

6
var foo = function () {}
console.log(foo.name); // outputs 'foo'

function foo () {}
console.log(foo.name); // outputs 'foo'

var foo = function bar () {}
console.log(foo.name); // outputs 'bar'

Rekursive Funktion

Eine rekursive Funktion ist einfach eine Funktion, die sich selbst aufrufen würde.

function factorial (n) {
    if (n <= 1) {
        return 1;
    }
    
    return n * factorial(n - 1);
}

Die obige Funktion zeigt ein grundlegendes Beispiel, wie eine rekursive Funktion ausgeführt wird, um eine Fakultät zurückzugeben.


Ein anderes Beispiel wäre das Abrufen der Summe der geraden Zahlen in einem Array.

function countEvenNumbers (arr) {
    // Sentinel value.  Recursion stops on empty array.
    if (arr.length < 1) {
        return 0;
    }
    // The shift() method removes the first element from an array 
    // and returns that element. This method changes the length of the array.
    var value = arr.shift();

    // `value % 2 === 0` tests if the number is even or odd
    // If it's even we add one to the result of counting the remainder of 
    // the array.  If it's odd, we add zero to it.
    return ((value % 2 === 0) ? 1 : 0) + countEvens(arr);
}

Es ist wichtig, dass solche Funktionen eine Art Sentinel-Wertprüfung durchführen, um unendliche Schleifen zu vermeiden. Wenn im ersten Beispiel n kleiner oder gleich 1 ist, wird die Rekursion angehalten, wodurch das Ergebnis jedes Aufrufs in den Aufrufstapel zurückversetzt werden kann.

Currying

Currying ist die Transformation einer Funktion von n arity oder Argumente in eine Folge von n - Funktionen nehmen nur ein Argument.

Anwendungsfälle: Wenn die Werte einiger Argumente vor anderen verfügbar sind, können Sie die Funktion currying verwenden, um eine Funktion in eine Reihe von Funktionen zu zerlegen, die die Arbeit schrittweise abschließen, sobald jeder Wert ankommt. Das kann nützlich sein:

  • Wenn sich der Wert eines Arguments fast nie ändert (z. B. ein Umrechnungsfaktor), müssen Sie jedoch die Flexibilität bei der Einstellung dieses Werts beibehalten (anstatt ihn als Konstante fest zu codieren).
  • Wenn das Ergebnis einer aktuellen Funktion nützlich ist, bevor die anderen ausgewählten Funktionen ausgeführt werden.
  • Überprüfung des Eintreffens der Funktionen in einer bestimmten Reihenfolge.

Beispielsweise kann das Volumen eines rechteckigen Prismas durch drei Faktoren erklärt werden: Länge ( l ), Breite ( w ) und Höhe ( h ):

var prism = function(l, w, h) {
    return l * w * h;
}

Eine aktuelle Version dieser Funktion würde folgendermaßen aussehen:

function prism(l) {
    return function(w) {
        return function(h) {
            return l * w * h;
        }
    }
}
6
// alternatively, with concise ECMAScript 6+ syntax:
var prism = l => w => h => l * w * h;

Sie können diese Funktionssequenz mit prism(2)(3)(5) aufrufen, das 30 ergeben soll.

Ohne zusätzliche Maschinerie (wie bei Bibliotheken) ist das Currying aufgrund der fehlenden Platzhalterwerte in JavaScript (ES 5/6) nur eingeschränkt syntaktisch flexibel. Während Sie var a = prism(2)(3) , um eine teilweise angewendete Funktion zu erstellen, können Sie prism()(3)(5) .

Verwenden der Return-Anweisung

Die return-Anweisung kann eine nützliche Methode zum Erstellen von Ausgaben für eine Funktion sein. Die return-Anweisung ist besonders nützlich, wenn Sie nicht wissen, in welchem ​​Kontext die Funktion noch verwendet wird.

//An example function that will take a string as input and return 
//the first character of the string.

function firstChar (stringIn){
    return stringIn.charAt(0);
}

Um diese Funktion verwenden zu können, müssen Sie sie an einer anderen Stelle in Ihrem Code an Stelle einer Variablen setzen:

Verwenden des Funktionsergebnisses als Argument für eine andere Funktion:

console.log(firstChar("Hello world"));

Konsolenausgabe wird sein:

> H

Die return-Anweisung beendet die Funktion

Wenn wir die Funktion am Anfang ändern, können wir zeigen, dass die return-Anweisung die Funktion beendet.

function firstChar (stringIn){
    console.log("The first action of the first char function");
    return stringIn.charAt(0);
    console.log("The last action of the first char function");
}

Wenn Sie diese Funktion so ausführen, sieht das so aus:

console.log(firstChar("JS"));

Konsolenausgabe:

> The first action of the first char function
> J

Die Nachricht wird nach der return-Anweisung nicht gedruckt, da die Funktion jetzt beendet ist.

Rückgabeanweisung, die mehrere Zeilen umfasst:

In JavaScript können Sie eine Codezeile normalerweise aus Gründen der Lesbarkeit oder der Organisation in viele Zeilen aufteilen. Dies ist gültiges JavaScript:

var
    name = "bob",
    age = 18;

Wenn JavaScript eine unvollständige Anweisung wie var sieht, erscheint die nächste Zeile, um sich selbst abzuschließen. Wenn Sie jedoch mit der return Anweisung denselben Fehler machen, werden Sie nicht das bekommen, was Sie erwartet haben.

return
    "Hi, my name is "+ name + ". " +
    "I'm "+ age + " years old.";

Dieser Code wird undefined da return selbst eine vollständige Anweisung in Javascript ist. Daher wird nicht die nächste Zeile zur Vervollständigung gesucht. Wenn Sie eine return Anweisung in mehrere Zeilen aufteilen müssen, setzen Sie als nächsten Wert einen Wert, um sie zurückzugeben, bevor Sie sie aufteilen.

return "Hi, my name is " + name + ". " +
    "I'm " + age + " years old.";

Argumente nach Referenz oder Wert übergeben

In JavaScript werden alle Argumente per Wert übergeben. Wenn eine Funktion einer Argumentvariablen einen neuen Wert zuweist, ist diese Änderung für den Aufrufer nicht sichtbar:

var obj = {a: 2};
function myfunc(arg){
    arg = {a: 5}; // Note the assignment is to the parameter variable itself
}
myfunc(obj);
console.log(obj.a); // 2

Jedoch Änderungen an (verschachtelte) Eigenschaften solcher Argumente, werden den Anrufer zu sehen sein:

var obj = {a: 2};
function myfunc(arg){
    arg.a = 5; // assignment to a property of the argument
}
myfunc(obj);
console.log(obj.a); // 5

Dies kann als ein Aufruf von Referenz gesehen werden: obwohl eine Funktion kann nicht die Aufgabe des Anrufers ändern , indem Sie einen neuen Wert zu zuweisen, könnte es den Anrufer Objekt mutieren.

Da primitive Werte wie Zahlen oder Strings nicht unveränderlich sind, gibt eine Funktion keine Möglichkeit, sie zu mutieren:

var s = 'say';
function myfunc(arg){
    arg += ' hello'; // assignment to the parameter variable itself
}
myfunc(s);
console.log(s); // 'say'

Wenn eine Funktion ein als Argument übergebenes Objekt mutieren möchte, das Objekt des Aufrufers jedoch nicht tatsächlich mutieren soll, muss die Argumentvariable neu zugewiesen werden:

6
var obj = {a: 2, b: 3};
function myfunc(arg){
    arg = Object.assign({}, arg); // assignment to argument variable, shallow copy
    arg.a = 5;
}
myfunc(obj);
console.log(obj.a); // 2

Als Alternative zur In-Place-Mutation eines Arguments können Funktionen basierend auf dem Argument einen neuen Wert erstellen und diesen zurückgeben. Der Aufrufer kann es dann sogar der ursprünglichen Variablen zuweisen, die als Argument übergeben wurde:

var a = 2;
function myfunc(arg){
    arg++;
    return arg;
}
a = myfunc(a);
console.log(obj.a); // 3

Rufen Sie an und bewerben Sie sich

Funktionen verfügen über zwei integrierte Methoden, mit denen der Programmierer Argumente und die Variable this unterschiedlich angeben kann: call und apply .

Dies ist nützlich, da Funktionen, die für ein Objekt (das Objekt, von dem sie eine Eigenschaft sind) arbeiten, für ein anderes kompatibles Objekt erneut zugewiesen werden können. Außerdem können Argumente auf einmal als Arrays angegeben werden, ähnlich dem Spread-Operator ( ... ) in ES6.

let obj = {
    a: 1,
    b: 2,
    set: function (a, b) {
        this.a = a;
        this.b = b;
    }
};

obj.set(3, 7); // normal syntax
obj.set.call(obj, 3, 7); // equivalent to the above
obj.set.apply(obj, [3, 7]); // equivalent to the above; note that an array is used

console.log(obj); // prints { a: 3, b: 5 }

let myObj = {};
myObj.set(5, 4); // fails; myObj has no `set` property
obj.set.call(myObj, 5, 4); // success; `this` in set() is re-routed to myObj instead of obj
obj.set.apply(myObj, [5, 4]); // same as above; note the array

console.log(myObj); // prints { a: 3, b: 5 }
5

ECMAScript 5 führte neben call() und apply() eine weitere Methode namens bind() , um this Wert der Funktion explizit auf ein bestimmtes Objekt festzulegen.

Es verhält sich ganz anders als die beiden anderen. Das erste zu bind() Argument ist der this Wert für die neue Funktion. Alle anderen Argumente stellen benannte Parameter dar, die in der neuen Funktion dauerhaft festgelegt werden sollten.

function showName(label) {
    console.log(label + ":" + this.name);
}
var student1 = {
     name: "Ravi"
};
var student2 = {
     name: "Vinod"
};

// create a function just for student1
var showNameStudent1 = showName.bind(student1);
showNameStudent1("student1"); // outputs "student1:Ravi"

// create a function just for student2
var showNameStudent2 = showName.bind(student2, "student2");
showNameStudent2(); // outputs "student2:Vinod"

// attaching a method to an object doesn't change `this` value of that method.
student2.sayName = showNameStudent1;
student2.sayName("student2"); // outputs "student2:Ravi"

Standardparameter

Vor ECMAScript 2015 (ES6) kann der Standardwert eines Parameters auf folgende Weise zugewiesen werden:

function printMsg(msg) {
  msg = typeof msg !== 'undefined' ? // if a value was provided 
        msg :                        // then, use that value in the reassignemnt
        'Default value for msg.';    // else, assign a default value
  console.log(msg);
}

ES6 stellte eine neue Syntax bereit, bei der die oben abgebildete Bedingung und Neuzuordnung nicht mehr erforderlich ist:

6
function printMsg(msg='Default value for msg.') {
    console.log(msg);
}
printMsg(); // -> "Default value for msg."
printMsg(undefined); // -> "Default value for msg."
printMsg('Now my msg in different!'); // -> "Now my msg in different!"

Dies zeigt auch, dass, wenn ein Parameter beim Aufruf der Funktion fehlt, der Wert als undefined beibehalten wird. Dies kann durch die explizite Angabe im folgenden Beispiel (mithilfe einer Pfeilfunktion ) bestätigt werden:

6
let param_check = (p = 'str') => console.log(p + ' is of type: ' + typeof p);

param_check(); // -> "str is of type: string"
param_check(undefined); // -> "str is of type: string"

param_check(1); // -> "1 is of type: number"
param_check(this); // -> "[object Window] is of type: object"

Funktionen / Variablen als Standardwerte und Wiederverwendung von Parametern

Die Werte der Standardparameter sind nicht auf Zahlen, Strings oder einfache Objekte beschränkt. Eine Funktion kann auch als Standardwert festgelegt werden. callback = function(){} :

6
function foo(callback = function(){ console.log('default'); }) {
    callback();
}

foo(function (){
    console.log('custom');
});
// custom

foo();
//default

Es gibt bestimmte Eigenschaften der Operationen, die mit Standardwerten ausgeführt werden können:

  • Ein zuvor deklarierter Parameter kann als Standardwert für die Werte der kommenden Parameter wiederverwendet werden.
  • Inline-Operationen sind zulässig, wenn einem Parameter ein Standardwert zugewiesen wird.
  • Variablen, die im gleichen Bereich der zu deklarierenden Funktion vorhanden sind, können in ihren Standardwerten verwendet werden.
  • Funktionen können aufgerufen werden, um ihren Rückgabewert als Standardwert bereitzustellen.
6
let zero = 0;
function multiply(x) { return x * 2;}

function add(a = 1 + zero, b = a, c = b + a, d = multiply(c)) {
    console.log((a + b + c), d);
}

add(1);                // 4, 4
add(3);                // 12, 12
add(2, 7);             // 18, 18
add(1, 2, 5);          // 8, 10
add(1, 2, 5, 10);      // 8, 20 

Wiederverwenden des Rückgabewerts der Funktion im Standardwert eines neuen Aufrufs:

6
let array = [1]; // meaningless: this will be overshadowed in the function's scope
function add(value, array = []) {
  array.push(value);
  return array;
}
add(5);         // [5]
add(6);         // [6], not [5, 6]
add(6, add(5)); // [5, 6]

arguments Wert und Länge, wenn Parameter beim Aufruf fehlen

Das arguments Array-Objekt behält nur die Parameter bei, deren Werte nicht Standard sind, dh die beim Aufruf der Funktion explizit angegeben werden:

6
function foo(a = 1, b = a + 1) {
    console.info(arguments.length, arguments);
    console.log(a,b);
}

foo();        // info: 0 >> []     | log: 1, 2
foo(4);       // info: 1 >> [4]    | log: 4, 5
foo(5, 6);    // info: 2 >> [5, 6] | log: 5, 6

Funktionen mit einer unbekannten Anzahl von Argumenten (variadische Funktionen)

Um eine Funktion zu erstellen, die eine unbestimmte Anzahl von Argumenten akzeptiert, gibt es zwei Methoden, die von Ihrer Umgebung abhängen.

5

Wenn eine Funktion aufgerufen wird, enthält sie ein Array-ähnliches Argumentobjekt , das alle an die Funktion übergebenen Argumente enthält. Indizieren oder iterieren führt beispielsweise zu den Argumenten

function logSomeThings() {
    for (var i = 0; i < arguments.length; ++i) {
        console.log(arguments[i]);
    }
}

logSomeThings('hello', 'world');
// logs "hello"
// logs "world"

Beachten Sie, dass Sie bei Bedarf arguments in ein tatsächliches Array konvertieren können. siehe: Array-ähnliche Objekte in Arrays konvertieren

6

Ab ES6 kann die Funktion mit dem Rest- Parameter ( ... ) mit ihrem letzten Parameter deklariert werden. Dadurch wird ein Array erstellt, das die Argumente von diesem Punkt an enthält

function personLogsSomeThings(person, ...msg) {
   msg.forEach(arg => {
       console.log(person, 'says', arg);
   });
}

personLogsSomeThings('John', 'hello', 'world');
// logs "John says hello"
// logs "John says world"

Funktionen können auch auf ähnliche Weise, der Spread-Syntax , aufgerufen werden

const logArguments = (...args) => console.log(args)
const list = [1, 2, 3]

logArguments('a', 'b', 'c', ...list)
// output: Array [ "a", "b", "c", 1, 2, 3 ]

Diese Syntax kann verwendet werden, um eine beliebige Anzahl von Argumenten an einer beliebigen Position einzufügen, und sie kann mit jedem Iterator verwendet werden ( apply akzeptiert nur Array-ähnliche Objekte).

const logArguments = (...args) => console.log(args)
function* generateNumbers() {
  yield 6
  yield 5
  yield 4
}

logArguments('a', ...generateNumbers(), ...'pqr', 'b')
// output: Array [ "a", 6, 5, 4, "p", "q", "r", "b" ]

Rufen Sie den Namen eines Funktionsobjekts ab

6

ES6 :

myFunction.name

Erklärung zu MDN . Ab 2015 arbeitet in nodejs und allen gängigen Browsern außer IE.


5

ES5 :

Wenn Sie einen Verweis auf die Funktion haben, können Sie Folgendes tun:

function functionName( func )
{
    // Match:
    // - ^          the beginning of the string
    // - function   the word 'function'
    // - \s+        at least some white space
    // - ([\w\$]+)  capture one or more valid JavaScript identifier characters
    // - \(         followed by an opening brace
    //
    var result = /^function\s+([\w\$]+)\(/.exec( func.toString() )
    
    return result ? result[1] : ''
}

Teilanwendung

Ähnlich wie beim Currying wird die Teilanwendung verwendet, um die Anzahl der an eine Funktion übergebenen Argumente zu reduzieren. Anders als beim Currying muss die Anzahl nicht um eins verringert werden.

Beispiel:

Diese Funktion ...

function multiplyThenAdd(a, b, c) {
    return a * b + c;
}

... kann verwendet werden, um eine weitere Funktion zu erstellen, die sich immer mit 2 multipliziert und dann den übergebenen Wert um 10 erhöht.

function reversedMultiplyThenAdd(c, b, a) {
    return a * b + c;
}

function factory(b, c) {
    return reversedMultiplyThenAdd.bind(null, c, b);
}

var multiplyTwoThenAddTen = factory(2, 10);
multiplyTwoThenAddTen(10); // 30

Der Teil "Anwendung" der Teilanwendung bedeutet einfach das Festlegen von Parametern einer Funktion.

Funktionszusammensetzung

Das Zusammensetzen mehrerer Funktionen zu einer ist eine gängige Praxis bei der Programmierung.

Komposition macht eine Pipeline, durch die unsere Daten übertragen und modifiziert werden, indem sie einfach an der Funktionskomposition arbeitet (genau wie das Zusammenfügen von Teilen einer Spur) ...

Sie beginnen mit einigen Verantwortungsfunktionen:

6
 const capitalize = x => x.replace(/^\w/, m => m.toUpperCase());
 const sign = x => x + ',\nmade with love';

und einfach eine Transformationsspur erstellen:

6
 const formatText = compose(capitalize, sign);

 formatText('this is an example')
 //This is an example,
 //made with love

NB Composition wird durch eine Utility-Funktion erreicht compose wie in unserem Beispiel normalerweise compose .

Die Implementierung von compose ist in vielen JavaScript-Hilfsprogrammbibliotheken ( lodash , rambda usw.) vorhanden. Sie können jedoch auch mit einer einfachen Implementierung beginnen, z.

6
 const compose = (...funs) =>
   x =>
   funs.reduce((ac, f) => f(ac), x);


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow