ホームページ > ウェブフロントエンド > jsチュートリアル > JavaScript の変数、スコープ、ホイスティングについての深い理解

JavaScript の変数、スコープ、ホイスティングについての深い理解

青灯夜游
リリース: 2019-11-25 14:39:39
転載
2651 人が閲覧しました

変数は多くのプログラミング言語の基本的な部分であり、初心者が最初に学ぶ必要がある最も重要な概念です。 JavaScript にはさまざまな変数プロパティが多数あり、変数に名前を付けるときに従わなければならないルールもいくつかあります。 JavaScript では、変数の宣言に var、let、const という 3 つのキーワードが使用されます。これらのキーワードはそれぞれ、コードによる変数の解釈方法に影響します。

JavaScript の変数、スコープ、ホイスティングについての深い理解

このチュートリアルでは、変数とは何か、変数の宣言と名前の付け方を紹介し、var、let、const の違いについてさらに詳しく説明します。また、巻き上げの影響と、変数の動作に対するグローバル スコープとローカル スコープの重要性についても確認します。 [関連コースの推奨事項: JavaScript ビデオ チュートリアル ]

変数について理解する

変数は、値を格納するために使用される名前付きコンテナです。複数回参照する可能性のある情報は、後で使用したり変更したりできるように変数に保存できます。 JavaScript では、変数に含まれる値は、数値、文字列、オブジェクトなど、任意の JavaScript データ型にすることができます。

現在の JavaScript のベースとなっている ECMAScript 2015 (ES6) 言語仕様が登場する前は、変数を宣言する方法は var キーワードを使用する 1 つだけでした。したがって、古いコードと学習リソースのほとんどは、変数に var を使用するだけです。 var、let、const キーワードの違いについては、以下の別のセクションで説明します。

var を使用して、変数自体の概念を示すことができます。次の例では、変数を宣言し、それに値を割り当てます。

// Assign the string value Sammy to the username identifier
var username = "sammy_shark";
ログイン後にコピー

このステートメントは次の部分で構成されています。

  • var キーワードを使用して変数を宣言します

  • 変数名 (または識別記号)、ユーザー名

  • = 構文で表される代入操作

  • 代入された値「sammy_shark」

これで、コード内でユーザー名を使用できるようになりました。 JavaScript は、ユーザー名が文字列値 sammy_shark を表すことを記憶します。

// Check if variable is equal to value
if (username === "sammy_shark") {
  console.log(true);
  }
ログイン後にコピー

出力:

true
ログイン後にコピー
ログイン後にコピー

前述したように、変数を使用して任意の JavaScript データ型を表すことができます。この例では、文字列、数値、オブジェクト、ブール値、および null 値を使用して変数を宣言します。

// Assignment of various variables
var name = "Sammy";
var spartans = 300;
var kingdoms = [ "mammals", "birds", "fish" ];
var poem = { roses: "red", violets: "blue" }; 
var success = true;
var nothing = null;
ログイン後にコピー

console.log を使用すると、特定の変数に含まれる値を確認できます。

// Send spartans variable to the console
console.log(spartans);
ログイン後にコピー

出力: 300

変数は、後でアクセスして変更できるデータをメモリに保存します。変数を再割り当てして新しい値を与えることもできます。以下の簡略化された例は、パスワードを変数に保存して更新する方法を示しています。

//为password变量赋值
var password = "hunter2";
//用一个新值重新分配变量值
password = "hunter3";
console.log(password);
ログイン後にコピー

出力:

'hunter3'
ログイン後にコピー

実際のプログラムでは、パスワードはデータベースに安全に保存される可能性があります。ただし、この例は、変数の値を更新する必要がある状況を示しています。パスワードの値はhunter2でしたが、それをhunter3に再割り当てしました。これは、その時点からJavaScriptが認識する値になります。

名前付き変数

変数名は、JavaScript では識別子と呼ばれます。 JavaScript の構文とコード構造を理解する際に、識別子の命名に関するいくつかのルールについて説明しました。概要を以下に示します。

  • 変数名は、文字 (a ~ z)、数字 (0 ~ 9)、ドルのみで構成できます。記号 ($) とアンダースコア (_) の形式

  • 変数名には空白文字 (タブまたはスペース) を含めることはできません

  • 数字は使用できません

  • #で始まる変数の名前は変数の名前として使用できません

  • #変数名は大文字と小文字が区別されます
  • JavaScript には、var または let で宣言された関数や変数の名前にキャメルケース (キャメルケースとしてスタイルされることもあります) を使用する習慣もあります。これは、最初の単語を小文字にし、その後の各単語の最初の文字を大文字にし、間にスペースを入れない方法です。一部の例外を除いて、ほとんどの非 const 変数はこの規則に従います。 const キーワードを使用して宣言された定数変数の名前は、通常は大文字です。

これは学ぶべきルールがたくさんあるように思えるかもしれませんが、有効で正規の変数名を書くことはすぐに習慣になるでしょう。

var、let、const の違い

JavaScript には変数を宣言するための 3 つの異なるキーワードがあり、言語がさらに複雑になります。 3 つの違いは、範囲、昇格、および再割り当てに基づいています。

letブロックスコープNoYesNoconstブロック範囲NoNoNo

您可能想知道应该在自己的程序中使用这三种方法中的哪一种。一个普遍接受的做法是尽可能多地使用const,并在循环和重新分配的情况下使用let。通常,在处理遗留代码之外可以避免var。

变量作用域

JavaScript中的作用域是指代码的当前上下文,它决定了变量对JavaScript的可访问性。范围的两种类型是局部的和全局的:

  • 全局变量是在块之外声明的变量

  • 局部变量是在块内声明的变量

在下面的示例中,我们将创建一个全局变量。

//初始化一个全局变量
var creature = "wolf";
ログイン後にコピー

我们知道变量可以重新分配。使用局部作用域,我们实际上可以创建与外部作用域中的变量同名的新变量,而无需更改或重新分配原始值。

在下面的示例中,我们将创建一个全局species变量。函数内部是一个具有相同名称的局部变量。通过将它们发送到控制台,我们可以看到变量的值如何根据范围而不同,并且原始值不会更改。

//初始化一个全局变量
var species = "human";
function transform() {
//初始化一个局部的、函数作用域的变量
  var species = "werewolf";
  console.log(species);
}
//记录全局和局部变量
console.log(species);
transform();
console.log(species);
ログイン後にコピー

输出:

human
werewolf
human
ログイン後にコピー

在本例中,局部变量是函数作用域的。使用var关键字声明的变量总是函数作用域,这意味着它们将函数识别为具有独立作用域。因此,这个局部作用域的变量不能从全局作用域访问。

然而,新的关键字let和const是块范围的。这意味着从任何类型的块(包括函数块、if语句、for和while循环)创建一个新的本地范围。

为了说明函数作用域变量和块作用域变量之间的区别,我们将使用let在if块中分配一个新变量。

var fullMoon = true;
//初始化一个全局变量
let species = "human";
if (fullMoon) { 
//初始化一个块范围的变量
  let species = "werewolf";
  console.log(`It is a full moon. Lupin is currently a ${species}.`);
}
console.log(`It is not a full moon. Lupin is currently a ${species}.`);
ログイン後にコピー

输出:

It is a full moon. Lupin is currently a werewolf.
It is not a full moon. Lupin is currently a human.
ログイン後にコピー

在此示例中,species变量具有一个值global(human),另一个值local(werewolf)。var但是,如果我们使用,则会有不同的结果。

//使用var初始化一个变量
var species = "human";
if (fullMoon) {  
//尝试在一个块中创建一个新变量
  var species = "werewolf";
  console.log(`It is a full moon. Lupin is currently a ${species}.`);
}

console.log(`It is not a full moon. Lupin is currently a ${species}.`);
ログイン後にコピー

输出:

It is a full moon. Lupin is currently a werewolf.
It is not a full moon. Lupin is currently a werewolf.
ログイン後にコピー

在这个例子的结果中,全局变量和块范围的变量都以相同的值结束。这是因为您不是使用var创建一个新的本地变量,而是在相同的范围内重新分配相同的变量。var不能识别是否属于不同的新范围。通常建议声明块范围的变量,因为它们生成的代码不太可能无意中覆盖变量值。

变量提升

到目前为止,在大多数示例中,我们已经使用var声明了一个变量,并使用一个值初始化了它。在声明和初始化之后,我们可以访问或重新分配变量。

如果我们试图在变量被声明和初始化之前使用它,它将返回undefined。

//在声明变量之前尝试使用它
console.log(x);
/ /变量赋值
var x = 100;
ログイン後にコピー

输出:

undefined
ログイン後にコピー
ログイン後にコピー

但是,如果省略var关键字,就不再声明变量,而是初始化它。它将返回一个ReferenceError并停止脚本的执行。

//在声明变量之前尝试使用它
console.log(x);
//没有var的变量赋值
x = 100;
ログイン後にコピー

输出:

ReferenceError: x is not defined
ログイン後にコピー

原因在于提升,这是JavaScript的一种行为,其中变量和函数声明被移到它们作用域的顶部。由于只挂起实际声明,而没有初始化,因此第一个示例中的值返回未定义的值。

为了更清楚地演示这个概念,下面是我们编写的代码以及JavaScript如何解释它。

// The code we wrote
console.log(x);
var x = 100;
// How JavaScript interpreted it
var x;
console.log(x);
x = 100;
ログイン後にコピー

JavaScript在执行脚本之前将x保存为内存作为变量。 由于它在定义之前仍然被调用,因此结果是未定义的而不是100.但是,它不会导致ReferenceError并停止脚本。

尽管var关键字实际上并未更改var的位置,但这有助于表示提升的工作原理。 但是,这种行为可能会导致问题,因为编写此代码的程序员可能希望x的输出为true,而不是undefined。

在下一个例子中,我们还可以看到提升是如何导致不可预测的结果的:

//在全局范围内初始化x
var x = 100;
function hoist() {
//不应影响编码结果的条件
  if (false) {
      var x = 200;
  }
  console.log(x);
}

hoist();
ログイン後にコピー

输出:

undefined
ログイン後にコピー
ログイン後にコピー

在本例中,我们声明x全局为100。根据if语句,x可以更改为200,但是由于条件为false,所以它不应该影响x的值。

这种不可预测的行为可能会在程序中引起bug。由于let和const是块范围的,所以它们不会以这种方式提升,如下所示。

//在全局范围内初始化x
let x = true;function hoist() {
//在函数作用域中初始化x
 if (3 === 4) {
      let x = false;
  }
  console.log(x);
}

hoist();
ログイン後にコピー

输出:

true
ログイン後にコピー
ログイン後にコピー

变量的重复声明(这在var中是可能的)将在let和const中抛出一个错误。

//试图覆盖用var声明的变量
var x = 1;
var x = 2;

console.log(x);
ログイン後にコピー

输出:2

//试图覆盖用let声明的变量
let y = 1;
let y = 2;

console.log(y);
ログイン後にコピー

输出:

Uncaught SyntaxError: Identifier 'y' has already been declared
ログイン後にコピー

总之,使用var引入的变量有可能受到提升的影响,提升是JavaScript中的一种机制,其中变量声明被保存到内存中。这可能导致代码中出现未定义的变量。let和const的引入解决了这个问题,它在试图在声明变量之前使用该变量或多次声明该变量时抛出一个错误。

常量

许多编程语言都有常量,这些常量是不能修改或更改的值。在JavaScript中,const标识符是根据常量建模的,不能重新分配分配给const的值。

将所有const标识符都写成大写是常见的约定。这将它们与其他变量值区分开来。

在下面的示例中,我们使用const关键字将变量SPECIES初始化为常量。试图重新分配变量将导致错误。

//给const赋值
const SPECIES = "human"; 

//尝试重新分配值
SPECIES = "werewolf";

console.log(SPECIES);
ログイン後にコピー

输出:

Uncaught TypeError: Assignment to constant variable.
ログイン後にコピー

因为不能重新分配const值,所以需要同时声明和初始化它们,否则也会抛出错误。

//声明,但不初始化const
const TODO;

console.log(TODO);
ログイン後にコピー

输出:

Uncaught SyntaxError: Missing initializer in const declaration
ログイン後にコピー

不能在编程中更改的值称为不可变值,而可以更改的值是可变的。虽然const值不能重新分配,但是它们是可变的,因为可以修改用const声明的对象的属性。

//创建一个具有两个属性的CAR对象
const CAR = {
    color: "blue",
    price: 15000}
//修改CAR的属性
CAR.price = 20000;

console.log(CAR);
ログイン後にコピー

输出:

{ color: 'blue', price: 20000 }
ログイン後にコピー

常量非常有用,可以让将来的自己和其他程序员清楚地认识到,不应该重新分配预期的变量。如果您希望将来修改某个变量,那么您可能希望使用let来声明该变量。

本文来自 js教程 栏目,欢迎学习!

以上がJavaScript の変数、スコープ、ホイスティングについての深い理解の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:digitalocean.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
キーワード
スコープ変数プロモーション再割り当て可能再定義可能
var関数スコープYesYesYes