Heim  >  Artikel  >  Web-Frontend  >  Detaillierte Erläuterung der JavaScript-Bereiche und -Abschlüsse

Detaillierte Erläuterung der JavaScript-Bereiche und -Abschlüsse

小云云
小云云Original
2018-02-09 13:33:271273Durchsuche

Umfang und Abschluss sind in JavaScript sehr wichtig. Aber als ich JavaScript zum ersten Mal lernte, war es schwer zu verstehen. Beginnen wir mit dem Umfang. Dieser Artikel stellt Ihnen hauptsächlich den JavaScript-Bereich und -Abschluss vor und hofft, Ihnen dabei zu helfen, den JavaScript-Umfang und -Abschluss besser zu verstehen.

Bereich

Der Bereich in JavaScript begrenzt, auf welche Variablen Sie zugreifen können. Es gibt zwei Arten von Bereichen: den globalen Bereich und den lokalen Bereich.

Globaler Geltungsbereich

Variablen, die außerhalb aller Funktionsdeklarationen oder geschweiften Klammern definiert sind, liegen im globalen Geltungsbereich.

Diese Regel gilt jedoch nur für JavaScript, das im Browser ausgeführt wird. Wenn Sie sich in Node.js befinden, unterscheiden sich die Variablen im globalen Bereich, in diesem Artikel wird Node.js jedoch nicht behandelt.

`const globalVariable = 'some value'`

Sobald Sie eine globale Variable deklariert haben, können Sie sie überall verwenden, auch innerhalb von Funktionen.

const hello = 'Hello CSS-Tricks Reader!'

function sayHello () {
 console.log(hello)
}

console.log(hello) // 'Hello CSS-Tricks Reader!'
sayHello() // 'Hello CSS-Tricks Reader!'

Obwohl Sie Variablen im globalen Bereich definieren können, empfehlen wir dies nicht. Da Namenskonflikte auftreten können, verwenden zwei oder mehr Variablen denselben Variablennamen. Wenn Sie beim Definieren einer Variablen const oder let verwenden, erhalten Sie bei einem Namenskonflikt eine Fehlermeldung. Dies ist nicht ratsam.

// Don't do this!
let thing = 'something'
let thing = 'something else' // Error, thing has already been declared

Wenn Sie beim Definieren einer Variablen var verwenden, überschreibt die zweite Definition die erste Definition. Dies erschwert auch das Debuggen des Codes und ist unerwünscht.

// Don't do this!
var thing = 'something'
var thing = 'something else' // perhaps somewhere totally different in your code
console.log(thing) // 'something else'

Sie sollten also versuchen, lokale Variablen anstelle von globalen Variablen zu verwenden.

Lokaler Bereich

Variablen, die innerhalb eines bestimmten Bereichs Ihres Codes verwendet werden, können verwendet werden. Definiert in lokalen Geltungsbereich. Dies ist eine lokale Variable.

Es gibt zwei Arten von lokalen Bereichen in JavaScript: Funktionsbereich und Bereich auf Blockebene.

Wir beginnen mit dem Funktionsumfang.

Funktionsumfang

Wenn Sie eine Variable in einer Funktion definieren, kann sie an einer beliebigen Stelle innerhalb der Funktion verwendet werden. Außerhalb der Funktion können Sie nicht darauf zugreifen.

Zum Beispiel im folgenden Beispiel die Variable hello in der Funktion sayHello:

function sayHello () {
 const hello = 'Hello CSS-Tricks Reader!'
 console.log(hello)
}

sayHello() // 'Hello CSS-Tricks Reader!'
console.log(hello) // Error, hello is not defined

Geltungsbereich auf Blockebene

Wenn Sie geschweifte Klammern verwenden, deklarieren Sie a Wenn Sie eine const- oder let-Variable verwenden, können Sie diese Variable nur in geschweiften Klammern verwenden.

Im folgenden Beispiel kann „Hallo“ nur in geschweiften Klammern verwendet werden.

{
 const hello = 'Hello CSS-Tricks Reader!'
 console.log(hello) // 'Hello CSS-Tricks Reader!'
}

console.log(hello) // Error, hello is not defined

Der Bereich auf Blockebene ist eine Teilmenge des Funktionsbereichs, da Funktionen mit geschweiften Klammern definiert werden müssen (es sei denn, Sie verwenden explizit Rückgabeanweisungen und Pfeilfunktionen).

Funktionsheraufstufung und -umfang

Bei Definition mit einer Funktion wird die Funktion an die Spitze des aktuellen Geltungsbereichs heraufgestuft. Daher ist der folgende Code äquivalent:

// This is the same as the one below
sayHello()
function sayHello () {
 console.log('Hello CSS-Tricks Reader!')
}

// This is the same as the code above
function sayHello () {
 console.log('Hello CSS-Tricks Reader!')
}
sayHello()

Bei der Definition mithilfe eines Funktionsausdrucks wird die Funktion nicht an die Spitze des Variablenbereichs gehoben.

sayHello() // Error, sayHello is not defined
const sayHello = function () {
 console.log(aFunction)
}

Da es hier zwei Variablen gibt, kann das Hochziehen von Funktionen zu Verwirrung führen und wird daher nicht wirksam. Stellen Sie daher sicher, dass Sie die Funktion definieren, bevor Sie sie verwenden.

Funktion kann nicht auf den Umfang anderer Funktionen zugreifen

Wenn verschiedene Funktionen separat definiert werden, kann zwar eine Funktion in einer Funktion aufgerufen werden, eine Funktion kann jedoch immer noch nicht intern auf den Umfang anderer Funktionen zugreifen.

Im folgenden Beispiel kann „second“ nicht auf die Variable „firstFunctionVariable“ zugreifen.

function first () {
 const firstFunctionVariable = `I'm part of first`
}

function second () {
 first()
 console.log(firstFunctionVariable) // Error, firstFunctionVariable is not defined
}

Verschachtelter Bereich

Wenn eine Funktion innerhalb einer Funktion definiert ist, kann die innere Funktion auf die Variablen der äußeren Funktion zugreifen, aber nicht umgekehrt. Der Effekt ist lexikalisches Scoping.

Die äußere Funktion kann nicht auf die Variablen der inneren Funktion zugreifen.

function outerFunction () {
 const outer = `I'm the outer function!`

 function innerFunction() {
  const inner = `I'm the inner function!`
  console.log(outer) // I'm the outer function!
 }

 console.log(inner) // Error, inner is not defined
}

Wenn Sie sich den Mechanismus des Zielfernrohrs vorstellen, können Sie sich einen Zwei-Wege-Spiegel (einseitig durchsichtiges Glas) vorstellen. Du kannst von innen nach draußen sehen, aber die Leute von draußen können dich nicht sehen.

Funktionsumfang ist wie ein Zwei-Wege-Spiegel. Von innen kann man nach draußen schauen, von außen ist man aber nicht zu sehen.

Verschachtelte Zielfernrohre haben einen ähnlichen Mechanismus, sie entsprechen jedoch mehr Zwei-Wege-Spiegeln.

Mehrere Funktionsebenen bedeuten mehrere Zwei-Wege-Spiegel.

Wenn Sie den vorherigen Teil über den Umfang verstehen, werden Sie verstehen, was ein Abschluss ist.

Abschluss

Wenn Sie eine weitere Funktion innerhalb einer Funktion erstellen, entspricht dies dem Erstellen eines Abschlusses. Innere Funktionen sind Abschlüsse. Um die internen Variablen der externen Funktion zugänglich zu machen, wird normalerweise dieser Abschluss zurückgegeben.

function outerFunction () {
 const outer = `I see the outer variable!`

 function innerFunction() {
  console.log(outer)
 }

 return innerFunction
}

outerFunction()() // I see the outer variable!

Da die innere Funktion einen Wert zurückgibt, können Sie den Funktionsdeklarationsteil vereinfachen:

function outerFunction () {
 const outer = `I see the outer variable!`

 return function innerFunction() {
  console.log(outer)
 }
}

outerFunction()() // I see the outer variable!

Da Abschlüsse auf die Variablen der äußeren Funktion zugreifen können, haben sie normalerweise zwei Verwendungszwecke :

  1. Nebenwirkungen reduzieren

  2. Private Variablen erstellen

Verschlüsse verwenden, um Nebenwirkungen zu kontrollieren

Wenn Sie etwas tun, während eine Funktion einen Wert zurückgibt, treten normalerweise einige Nebenwirkungen auf. Nebenwirkungen treten in vielen Situationen auf, z. B. bei Ajax-Aufrufen, Zeitüberschreitungen oder sogar Ausgabeanweisungen von console.log:

function (x) {
 console.log('A console.log is a side effect!')
}

Wenn Sie Abschlüsse verwenden, um Nebenwirkungen zu kontrollieren, müssen Sie tatsächlich überlegen, welche Teile das verwirren könnten Workflow Ihres Codes, wie Ajax oder Timeouts.

Zur Verdeutlichung ist es bequemer, sich Beispiele anzusehen:

比如说你要给为你朋友庆生,做一个蛋糕。做这个蛋糕可能花1秒钟的时间,所以你写了一个函数记录在一秒钟以后,记录做完蛋糕这件事。

为了让代码简短易读,我使用了ES6的箭头函数:

function makeCake() {
 setTimeout(_ => console.log(`Made a cake`, 1000)
 )
}

如你所见,做蛋糕带来了一个副作用:一次延时。

更进一步,比如说你想让你的朋友能选择蛋糕的口味。那么你就给做蛋糕makeCake这个函数加了一个参数。

function makeCake(flavor) {
 setTimeout(_ => console.log(`Made a ${flavor} cake!`, 1000))
}

因此当你调用这个函数时,一秒后这个新口味的蛋糕就做好了。

makeCake('banana')
// Made a banana cake!

但这里的问题是,你并不想立刻知道蛋糕的味道。你只需要知道时间到了,蛋糕做好了就行。

要解决这个问题,你可以写一个prepareCake的功能,保存蛋糕的口味。然后,在返回在内部调用prepareCake的闭包makeCake。

从这里开始,你就可以在你需要的时调用,蛋糕也会在一秒后立刻做好。

function prepareCake (flavor) {
 return function () {
  setTimeout(_ => console.log(`Made a ${flavor} cake!`, 1000))
 }
}

const makeCakeLater = prepareCake('banana')

// And later in your code...
makeCakeLater()
// Made a banana cake!

这就是使用闭包减少副作用:你可以创建一个任你驱使的内层闭包。

私有变量和闭包

前面已经说过,函数内的变量,在函数外部是不能访问的既然不能访问,那么它们就可以称作私有变量。

然而,有时候你确实是需要访问私有变量的。这时候就需要闭包的帮助了。

function secret (secretCode) {
 return {
  saySecretCode () {
   console.log(secretCode)
  }
 }
}

const theSecret = secret('CSS Tricks is amazing')
theSecret.saySecretCode()
// 'CSS Tricks is amazing'

这个例子里的saySecretCode函数,就在原函数外暴露了secretCode这一变量。因此,它也被成为特权函数。

使用DevTools调试

Chrome和Firefox的开发者工具都使我们能很方便的调试在当前作用域内可以访问的各种变量一般有两种方法。

第一种方法是在代码里使用debugger关键词。这能让浏览器里运行的JavaScript的暂停,以便调试。

下面是prepareCake的例子:

function prepareCake (flavor) {
 // Adding debugger
 debugger
 return function () {
  setTimeout(_ => console.log(`Made a ${flavor} cake!`, 1000))
 }
}

const makeCakeLater = prepareCake('banana')

打开Chrome的开发者工具,定位到Source页下(或者是Firefox的Debugger页),你就能看到可以访问的变量了。

使用debugger调试prepareCake的作用域。

你也可以把debugger关键词放在闭包内部。注意对比变量的作用域:

function prepareCake (flavor) {
 return function () {
  // Adding debugger
  debugger
  setTimeout(_ => console.log(`Made a ${flavor} cake!`, 1000))
 }
}

const makeCakeLater = prepareCake('banana')

调试闭包内部作用域

第二种方式是直接在代码相应位置加断点,点击对应的行数就可以了。

通过断点调试作用域

总结一下

闭包和作用域并不是那么难懂。一旦你使用双向镜的思维去理解,它们就非常简单了。

当你在函数里声明一个变量时,你只能在函数内访问。这些变量的作用域就被限制在函数里了。

如果你在一个函数内又定义了内部函数,那么这个内部函数就被称作闭包。它仍可以访问外部函数的作用域。

相关推荐:

详解JavaScript作用域和闭包

javascript 词法作用域和闭包分析说明_javascript技巧

深入理解javascript作用域和闭包_基础知识

Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung der JavaScript-Bereiche und -Abschlüsse. 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