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

Eine ausführliche Erläuterung der JavaScript-Bereiche und -Abschlüsse

小云云
小云云Original
2017-12-05 10:40:311868Durchsuche

Als Programmierer sind Umfang und Abschluss in JavaScript sehr wichtig. Vielleicht war es für uns am Anfang schwierig zu verstehen, was Umfang und Abschluss sind und wie man sie in JavaScript verwendet? In diesem Artikel stellen wir JavaScript-Bereiche und -Abschlüsse im Detail vor.

Bereich

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

Globaler Gültigkeitsbereich

Variablen, die außerhalb aller Funktionsdeklarationen oder geschweiften Klammern definiert sind, befinden sich im Globalen Gültigkeitsbereich.

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

In einem bestimmten Bereich Ihrer Codevariablen Die Verwendung innerhalb kann im lokalen Bereich definiert werden. Dies ist 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

Bereich auf Blockebene

Bei Verwendung geschweifte Klammern: Wenn Sie eine const- oder let-Variable deklarieren, 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 die Funktionsförderung 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, umgekehrt jedoch nicht. 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.

Eine ausführliche Erläuterung der JavaScript-Bereiche und -Abschlüsse

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.

Eine ausführliche Erläuterung der JavaScript-Bereiche und -Abschlüsse

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 innere Funktionen Werte zurückgeben, 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 Variablen von zugreifen können äußere Funktionen, daher haben sie normalerweise zwei Verwendungszwecke:

  1. Nebenwirkungen reduzieren

  2. Private Variablen erstellen

Verwenden Sie Abschlüsse, 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 bei Ausgabeanweisungen von console.log:

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

当你使用闭包来控制副作用时,你实际上是需要考虑哪些可能会混淆代码工作流程的部分,比如Ajax或者超时。

要把事情说清楚,还是看例子比较方便:

比如说你要给为你朋友庆生,做一个蛋糕。做这个蛋糕可能花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页),你就能看到可以访问的变量了。

Eine ausführliche Erläuterung der JavaScript-Bereiche und -Abschlüsse

使用debugger调试 prepareCake 的作用域。

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

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

const makeCakeLater = prepareCake('banana')

 

Eine ausführliche Erläuterung der JavaScript-Bereiche und -Abschlüsse

调试闭包内部作用域

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

Eine ausführliche Erläuterung der JavaScript-Bereiche und -Abschlüsse

通过断点调试作用域

闭包和作用域并不是那么难懂。一旦你使用双向镜的思维去理解,它们就非常简单了。当你在函数里声明一个变量时,你只能在函数内访问。这些变量的作用域就被限制在函数里了。如果你在一个函数内又定义了内部函数,那么这个内部函数就被称作闭包。它仍可以访问外部函数的作用域。希望本文能帮助到大家。

相关推荐:

JS的解析顺序和作用域以及严格模式的简单介绍

javascript中关于作用于作用域链的详解

JavaScript作用域与闭包的分析讲解

Das obige ist der detaillierte Inhalt vonEine ausführliche 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