Heim  >  Artikel  >  Web-Frontend  >  Detaillierte Antwort auf die Funktion zur sofortigen Ausführung in JavaScript

Detaillierte Antwort auf die Funktion zur sofortigen Ausführung in JavaScript

亚连
亚连Original
2018-05-21 12:01:331040Durchsuche

Der Funktionsmodus zur sofortigen Ausführung in JavaScript ermöglicht die Ausführung Ihrer Funktion sofort nach der Definition. Freunde, die sie benötigen, können sich auf

beziehen In JavaScript erstellt jede Funktion beim Aufruf einen neuen Ausführungskontext. Da innerhalb von Funktionen und Funktionen definierte Variablen die einzigen Variablen sind, auf die intern und nicht extern zugegriffen wird, bietet der von der Funktion bereitgestellte Kontext eine sehr einfache Möglichkeit, private Variablen zu erstellen, wenn die Funktion aufgerufen wird.

function makeCounter() {
  var i = 0;
  return function(){
    console.log(++i);
  };  
}

//记住:`counter`和`counter2`都有他们自己的变量 `i`

var counter = makeCounter();
counter();//1
counter();//2

var counter2 = makeCounter();
counter2();//1
counter2();//2

i;//ReferenceError: i is not defined(它只存在于makeCounter里)

In vielen Fällen benötigen Sie möglicherweise keine Funktion wie makeWhatever, um mehrere akkumulierte Werte zurückzugeben, und können sie nur einmal aufrufen, um einen einzelnen Wert zu erhalten. In anderen Fällen müssen Sie das nicht einmal explizit kennen Rückgabewert.

Der Kern davonOb Sie nun eine Funktion wie diese function foo(){} oder var foo = function(){} definieren, müssen Sie beim Aufrufen ein Paar hinzufügen von Klammern, wie foo().

//向下面这样定义的函数可以通过在函数名后加一对括号进行调用,像这样`foo()`,
//因为foo相对于函数表达式`function(){/* code */}`只是一个引用变量

var foo = function(){/* code */}

//那这可以说明函数表达式可以通过在其后加上一对括号自己调用自己吗?

function(){ /* code */}(); //SyntaxError: Unexpected token (

Wie Sie sehen, ist hier ein Fehler aufgetreten. Wenn hinter einer Funktion zum Aufrufen einer Funktion Klammern stehen, wird diese standardmäßig als Funktionsdeklaration und nicht als Funktionsausdruck behandelt, unabhängig davon, ob sie in der globalen oder lokalen Umgebung auf ein solches Funktionsschlüsselwort trifft. Wenn Sie den Klammern nicht explizit mitteilen, dass es sich um einen Ausdruck handelt, wird es als Funktionsdeklaration ohne Namen behandelt und einen Fehler ausgegeben, da Funktionsdeklarationen einen Namen erfordern.

Frage 1: Können wir hier über eine Frage nachdenken, können wir die Funktion auch direkt so aufrufen var foo = function(){console.log(1)}(), die Antwort ist ja.
Frage 2: Ebenso können wir über eine Frage nachdenken: Was passiert, wenn eine solche Funktionsdeklaration direkt mit Klammern am Ende aufgerufen wird? Bitte beachten Sie die Antwort unten.

Funktion, Klammern, FehlerInteressanterweise wird derselbe Fehler ausgegeben, wenn Sie einer Funktion einen Namen geben und ein Paar Klammern dahinter setzen, aber dieses Mal war es für einen anderen Grund. Wenn Klammern nach einem Funktionsausdruck gesetzt werden, bedeutet dies, dass es sich um eine aufgerufene Funktion handelt, und wenn Klammern nach einer Deklaration platziert werden, bedeutet dies, dass sie vollständig von der vorherigen Funktionsdeklaration getrennt ist. Zu diesem Zeitpunkt sind die Klammern nur eine einfache Darstellung. Eine Klammer (Klammern zur Steuerung der Priorität von Operationen).

//然而函数声明语法上是无效的,它仍然是一个声明,紧跟着的圆括号是无效的,因为圆括号里需要包含表达式

function foo(){ /* code */ }();//SyntaxError: Unexpected token

//现在,你把一个表达式放在圆括号里,没有抛出错误...,但是函数也并没有执行,因为:

function foo(){/* code */}(1)

//它等同于如下,一个函数声明跟着一个完全没有关系的表达式:

function foo(){/* code */}
(1);

Sofort ausgeführter Funktionsausdruck (IIFE) Glücklicherweise ist das Beheben von Syntaxfehlern einfach. Die beliebteste und akzeptierte Methode besteht darin, eine Funktionsdeklaration in Klammern zu setzen, um den Parser anzuweisen, einen Funktionsausdruck auszudrücken, da Klammern in JavaScript keine Deklarationen enthalten können. Aus diesem Grund weiß es, wenn Klammern eine Funktion einschließen und auf das Schlüsselwort function stoßen, es als Funktionsausdruck und nicht als Funktionsdeklaration zu analysieren. Beachten Sie, dass sich die Klammern hier anders verhalten als die Klammern oben, wenn sie auf Funktionen treffen.

Wenn am Ende einer anonymen Funktion Klammern erscheinen und Sie eine Funktion aufrufen möchten, wird die Funktion standardmäßig als Funktionsdeklaration verwendet.
Wenn eine Funktion in Klammern eingeschlossen wird, wird die Funktion standardmäßig als Ausdruck und nicht als Funktionsdeklaration geparst.

//这两种模式都可以被用来立即调用一个函数表达式,利用函数的执行来创造私有变量

(function(){/* code */}());//Crockford recommends this one,括号内的表达式代表函数立即调用表达式
(function(){/* code */})();//But this one works just as well,括号内的表达式代表函数表达式

// Because the point of the parens or coercing operators is to disambiguate
// between function expressions and function declarations, they can be
// omitted when the parser already expects an expression (but please see the
// "important note" below).

var i = function(){return 10;}();
true && function(){/*code*/}();
0,function(){}();

//如果你并不关心返回值,或者让你的代码尽可能的易读,你可以通过在你的函数前面带上一个一元操作符来存储字节

!function(){/* code */}();
~function(){/* code */}();
-function(){/* code */}();
+function(){/* code */}();

// Here's another variation, from @kuvos - I'm not sure of the performance
// implications, if any, of using the `new` keyword, but it works.
// http://twitter.com/kuvos/status/18209252090847232

new function(){ /* code */ }
new function(){ /* code */ }() // Only need parens if passing arguments

Wichtige Hinweise zu KlammernIn manchen Fällen sind zusätzliche mehrdeutige Klammern um einen Funktionsausdruck nicht notwendig (da die Klammern ihn bereits als Ausdruck getrennt haben), aber es ist trotzdem gut Idee, wenn Klammern zum Aufrufen von Funktionsausdrücken verwendet werden.

Solche Klammern zeigen an, dass der Funktionsausdruck sofort aufgerufen wird und die Variable das Ergebnis der Funktion speichert, nicht die Funktion selbst. Wenn es sich um einen sehr langen Funktionsausdruck handelt, kann dies einer Person, die Ihren Code liest, Zeit ersparen, zum Ende der Seite scrollen zu müssen, um zu sehen, ob die Funktion aufgerufen wird.

Wenn Sie klaren und prägnanten Code schreiben, ist es in der Regel notwendig, zu verhindern, dass JavaScript Fehler auslöst. Es ist auch notwendig, zu verhindern, dass andere Entwickler Fehler auf Sie werfen WTFError!

Beibehalten des Zustands eines Abschlusses So wie Argumente übergeben werden, wenn eine Funktion über ihren Namen aufgerufen wird, werden Argumente auch übergeben, wenn ein Funktionsausdruck sofort aufgerufen wird. Ein sofort aufgerufener Funktionsausdruck kann verwendet werden, um den Wert zu sperren und den aktuellen Status effektiv zu speichern, da jede innerhalb einer Funktion definierte Funktion die von der äußeren Funktion übergebenen Parameter und Variablen verwenden kann (diese Beziehung wird als Abschluss bezeichnet).

// 它的运行原理可能并不像你想的那样,因为`i`的值从来没有被锁定。
// 相反的,每个链接,当被点击时(循环已经被很好的执行完毕),因此会弹出所有元素的总数,
// 因为这是 `i` 此时的真实值。

var elems = document.getElementsByTagName('a');
for(var i = 0;i < elems.length; i++ ) {
  elems[i].addEventListener(&#39;click&#39;,function(e){
    e.preventDefault();
    alert(&#39;I am link #&#39; + i)
    },false);
}

// 而像下面这样改写,便可以了,因为在IIFE里,`i`值被锁定在了`lockedInIndex`里。
// 在循环结束执行时,尽管`i`值的数值是所有元素的总和,但每一次函数表达式被调用时,
// IIFE 里的 `lockedInIndex` 值都是`i`传给它的值,所以当链接被点击时,正确的值被弹出。

var elems = document.getElementsByTagName(&#39;a&#39;);
for(var i = 0;i < elems.length;i++) {
  (function(lockedInIndex){
    elems[i].addEventListener(&#39;click&#39;,function(e){
      e.preventDefault();
      alert(&#39;I am link #&#39; + lockedInIndex);
      },false)
  })(i);
}

//你同样可以像下面这样使用IIFE,仅仅只用括号包括点击处理函数,并不包含整个`addEventListener`。
//无论用哪种方式,这两个例子都可以用IIFE将值锁定,不过我发现前面一个例子更可读

var elems = document.getElementsByTagName( &#39;a&#39; );

for ( var i = 0; i < elems.length; i++ ) {
  elems[ i ].addEventListener( &#39;click&#39;, (function( lockedInIndex ){
    return function(e){
      e.preventDefault();
      alert( &#39;I am link #&#39; + lockedInIndex );
    };
    })( i ),false);
  }

Denken Sie daran, dass lockInIndex in diesen letzten beiden Beispielen problemlos auf i zugreifen kann, aber die Verwendung eines anderen benannten Bezeichners als Funktionsparameter kann die Erklärung des Konzepts erleichtern.

Einer der bedeutendsten Vorteile der sofortigen Ausführung einer Funktion besteht darin, dass ein Funktionsausdruck, selbst wenn er unbenannt oder anonym ist, sofort ohne Bezeichner aufgerufen werden kann und ein Abschluss sofort ohne aktuelle Variable aufgerufen werden kann. Verunreinigungen verwendet werden.

Was ist falsch an einer selbstausführenden anonymen Funktion („Selbstausführende anonyme Funktion“)?

你看到它已经被提到好几次了,但是它仍然不是那么清楚的被解释,我提议将术语改成"Immediately-Invoked Function Expression",或者,IIFE,如果你喜欢缩写的话。

什么是Immediately-Invoked Function Expression呢?它使一个被立即调用的函数表达式。就像引导你去调用的函数表达式。

我想Javascript社区的成员应该可以在他们的文章里或者陈述里接受术语,Immediately-Invoked Function Expression和 IIFE,因为我感觉这样更容易让这个概念被理解,并且术语"self-executing anonymous function"真的也不够精确。

//下面是个自执行函数,递归的调用自己本身

function foo(){foo();};

//这是一个自执行匿名函数。因为它没有标识符,它必须是使用`arguments.callee`属性来调用它自己

var foo = function(){arguments.callee();};

//这也许算是一个自执行匿名函数,但是仅仅当`foo`标识符作为它的引用时,如果你将它换成用`foo`来调用同样可行

var foo = function(){foo();};

//有些人像这样叫&#39;self-executing anonymous function&#39;下面的函数,即使它不是自执行的,因为它并没有调用它自己。然后,它只是被立即调用了而已。

(function(){ /*code*/ }());

//为函数表达式增加标识符(也就是说创造一个命名函数)对我们的调试会有很大帮助。一旦命名,函数将不再匿名。

(function foo(){/* code */}());

//IIFEs同样也可以自执行,尽管,也许他不是最有用的模式

(function(){arguments.callee();}())
(function foo(){foo();}())

// One last thing to note: this will cause an error in BlackBerry 5, because
// inside a named function expression, that name is undefined. Awesome, huh?

(function foo(){ foo(); }());

希望上面的例子可以让你更加清楚的知道术语'self-executing'是有一些误导的,因为他并不是执行自己的函数,尽管函数已经被执行。同样的,匿名函数也没用必要特别指出,因为,Immediately Invoked Function Expression,既可以是命名函数也可以匿名函数。

最后:模块模式当我调用函数表达式时,如果我不至少一次的提醒我自己关于模块模式,我便很可能会忽略它。如果你并不属性 JavaScript 里的模块模式,它和我下面的例子很像,但是返回值用对象代替了函数。

var counter = (function(){
  var i = 0;
  return {
    get: function(){
      return i;
    },
    set: function(val){
      i = val;
    },
    increment: function(){
      return ++i;
    }
  }
  }());
  counter.get();//0
  counter.set(3);
  counter.increment();//4
  counter.increment();//5

  conuter.i;//undefined (`i` is not a property of the returned object)
  i;//ReferenceError: i is not defined (it only exists inside the closure)

模块模式方法不仅相当的厉害而且简单。非常少的代码,你可以有效的利用与方法和属性相关的命名,在一个对象里,组织全部的模块代码即最小化了全局变量的污染也创造了使用变量。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

JavaScript中各数制转换全面总结(图文教程)

原生JavaScript来实现对dom元素class的操作方法(图文教程)

JavaScript中的字符串连接问题(图文教程)

Das obige ist der detaillierte Inhalt vonDetaillierte Antwort auf die Funktion zur sofortigen Ausführung in JavaScript. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn