ホームページ ウェブフロントエンド jsチュートリアル JavaScript アドバンスト シリーズ - スコープと名前空間

JavaScript アドバンスト シリーズ - スコープと名前空間

Feb 08, 2017 am 09:35 AM

  • 暗黙的なグローバル変数

  • ローカル変数

  • 変数宣言のホイスティング(ホイスティング)

  • 名前解決の順序

  • 名前空間

  • 結論

JavaScript は For コード セグメントをサポートしていますが、中括弧で作成される場合、ブロックレベルのスコープはサポートされません。関数スコープのみがサポートされます。

function test() { // 一个作用域
    for(var i = 0; i < 10; i++) { // 不是一个作用域
        // count
    }
    console.log(i); // 10
}
ログイン後にコピー

翻訳者注: return オブジェクトの左括弧と return が同じ行にない場合、エラーが発生します。

(注: 代入ステートメント内ではなく、戻り式または関数パラメーター内にある場合、{...} はオブジェクトのリテラル構文としてではなく、コード セグメントとして解析されます。自動解析が有効な場合、 No. の挿入を考慮すると、これによりいくつかの微妙なエラーが発生する可能性があります)

// 译者注:下面输出 undefined
function add(a, b) {
    return 
        a + b;
}
console.log(add(1, 2));
ログイン後にコピー

JavaScript には明示的な名前空間定義がありません。これは、すべてのオブジェクトがグローバルに共有される名前空間の下で定義されることを意味します。

変数が参照されるたびに、JavaScript は変数が見つかるまでスコープ全体を上方向に走査します。 グローバル スコープに到達しても変数が見つからない場合は、ReferenceError 例外がスローされます。

暗黙的なグローバル変数

// 脚本 A
foo = &#39;42&#39;;

// 脚本 B
var foo = &#39;42&#39;
ログイン後にコピー

上記の 2 つのスクリプトには異なる効果があります。スクリプト A はグローバル スコープで変数 foo を定義し、スクリプト B は現在のスコープで変数 foo を定義します。

もう一度言いますが、変数の宣言に var を使用しない場合は、暗黙的なグローバル変数が生成されます。

// 全局作用域
var foo = 42;
function test() {
    // 局部作用域
    foo = 21;
}
test();
foo; // 21
ログイン後にコピー

関数テスト内で var キーワードを使用せずに foo 変数を宣言すると、同じ名前の外部変数が上書きされます。 最初はこれは大きな問題に思えないかもしれませんが、コードが数千行ある場合、var を使用せずに変数を宣言すると、追跡が難しいバグが発生する可能性があります。

// 全局作用域
var items = [/* 数组 */];
for(var i = 0; i < 10; i++) {
    subLoop();
}

function subLoop() {
    // subLoop 函数作用域
    for(i = 0; i < 10; i++) { // 没有使用 var 声明变量
        // 干活
    }
}
ログイン後にコピー

subLoop はグローバル変数 i を上書きするため、外側のループは subLoop への最初の呼び出し後に終了します。 このエラーは、2 番目の for ループで var を使用して変数を宣言することで回避できます。 外部スコープに影響を与える望ましい動作でない限り、変数を宣言するときに var キーワードを省略しないでください。

ローカル変数

JavaScript のローカル変数は 2 つの方法でのみ宣言できます。1 つは関数パラメーターとして宣言され、もう 1 つは var キーワードを通じて宣言されます。

// 全局变量
var foo = 1;
var bar = 2;
var i = 2;

function test(i) {
    // 函数 test 内的局部作用域
    i = 5;

    var foo = 3;
    bar = 4;
}
test(10);
ログイン後にコピー

foo と i は関数 test 内のローカル変数であり、bar への代入により、グローバル スコープ内の同じ名前の変数が上書きされます。

変数宣言のホイスト(Hoisting)

JavaScriptは変数宣言をホイスティングします。これは、var 式と関数宣言の両方が現在のスコープの先頭に巻き上げられることを意味します。

bar();
var bar = function() {};
var someValue = 42;

test();
function test(data) {
    if (false) {
        goo = 1;

    } else {
        var goo = 2;
    }
    for(var i = 0; i < 100; i++) {
        var e = data[i];
    }
}
ログイン後にコピー

上記のコードは実行前に変換されます。 JavaScript は、var 式と関数宣言を現在のスコープの先頭に巻き上げます。

// var 表达式被移动到这里
var bar, someValue; // 缺省值是 &#39;undefined&#39;

// 函数声明也会提升
function test(data) {
    var goo, i, e; // 没有块级作用域,这些变量被移动到函数顶部
    if (false) {
        goo = 1;

    } else {
        goo = 2;
    }
    for(i = 0; i < 100; i++) {
        e = data[i];
    }
}

bar(); // 出错:TypeError,因为 bar 依然是 &#39;undefined&#39;
someValue = 42; // 赋值语句不会被提升规则(hoisting)影响
bar = function() {};

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

ブロック スコープがないことにより、var 式がループの内側から外側に移動されるだけでなく、一部の if 式が読みにくくなります。

元のコードでは、if 式はグローバル変数 goo を変更しているように見えますが、実際にはプロモーション ルールが適用された後にローカル変数を変更します。

ホイスティングの知識がないと、次のコードは ReferenceError 例外をスローするように見えます。

// 检查 SomeImportantThing 是否已经被初始化
if (!SomeImportantThing) {
    var SomeImportantThing = {};
}
ログイン後にコピー

実際、var 式がグローバル スコープの最上位にホイストされているため、上記のコードは正常に動作します。

var SomeImportantThing;

// 其它一些代码,可能会初始化 SomeImportantThing,也可能不会

// 检查是否已经被初始化
if (!SomeImportantThing) {
    SomeImportantThing = {};
}
ログイン後にコピー

翻訳者注: Nettuts+ Web サイトにホイスティングを紹介する記事があり、そのコードは非常に啓発的です。

// 译者注:来自 Nettuts+ 的一段代码,生动的阐述了 JavaScript 中变量声明提升规则
var myvar = &#39;my value&#39;;  

(function() {  
    alert(myvar); // undefined  
    var myvar = &#39;local value&#39;;  
})();
ログイン後にコピー

名前解決の順序


グローバル スコープを含む JavaScript のすべてのスコープには、現在のオブジェクトを指す特別な名前があります。関数スコープにはデフォルトの変数引数もあり、これには関数に渡されるパラメータが含まれます。たとえば、関数内の foo 変数にアクセスすると、JavaScript は次の順序で検索します:

  1. 現在のスコープに var foo の定義があるかどうか。

  2. 関数の仮パラメータが foo 名を使用するかどうか。

  3. 関数自体が foo と呼ばれるかどうか。

  4. 前のスコープに戻り、#1 からやり直します。

名前空間

グローバル スコープが 1 つしかないことによって引き起こされるよくある間違いは、名前の競合です。 JavaScript では、これは匿名ラッパーを使用して簡単に解決できます。

(注: カスタム引数パラメーターはネイティブ引数オブジェクトの作成を防ぎます。)

(function() {
    // 函数创建一个命名空间

    window.foo = function() {
        // 对外公开的函数,创建了闭包
    };

})(); // 立即执行此匿名函数
ログイン後にコピー

匿名関数は式とみなされ、呼び出し可能性を考慮して最初に実行されます。

( // 小括号内的函数首先被执行
function() {}
) // 并且返回函数对象
() // 调用上面的执行结果,也就是函数对象
ログイン後にコピー

関数式を呼び出す方法は他にもいくつかあります。たとえば、次の 2 つのメソッドは構文が異なりますが、結果はまったく同じです。

// 另外两种方式
+function(){}();
(function(){}());
ログイン後にコピー

結論


名前空間を作成するには、匿名ラッパー (翻訳者注: 自己実行匿名関数) を使用することをお勧めします。これにより、名前の競合が防止されるだけでなく、プログラムのモジュール化も容易になります。

また、グローバル変数の使用は悪い習慣とみなされます。このようなコードはエラーが発生しやすく、保守にコストがかかります。

上記は JavaScript 上級シリーズ - スコープと名前空間の内容です。さらに関連する内容については、PHP 中国語 Web サイト (www.php.cn) に注目してください。


このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

C言語でのtypedef構造体の使い方 C言語でのtypedef構造体の使い方 May 09, 2024 am 10:15 AM

typedef struct は、構造体の使用を簡素化するために構造体型のエイリアスを作成するために C 言語で使用されます。構造体の別名を指定することで、新しいデータ型を既存の構造体に別名付けします。利点としては、可読性の向上、コードの再利用、型チェックなどが挙げられます。注: エイリアスを使用する前に構造体を定義する必要があります。エイリアスはプログラム内で一意であり、宣言されているスコープ内でのみ有効である必要があります。

Javaで期待される変数を解決する方法 Javaで期待される変数を解決する方法 May 07, 2024 am 02:48 AM

Java における変数の期待値の例外は、変数の初期化、null 値の使用、およびローカル変数のスコープの認識によって解決できます。

JSのクロージャーの長所と短所 JSのクロージャーの長所と短所 May 10, 2024 am 04:39 AM

JavaScript クロージャーの利点には、変数スコープの維持、モジュール化コードの有効化、遅延実行、およびイベント処理が含まれますが、欠点としては、メモリ リーク、複雑さの増加、パフォーマンスのオーバーヘッド、およびスコープ チェーンの影響が挙げられます。

C++ で include は何を意味しますか C++ で include は何を意味しますか May 09, 2024 am 01:45 AM

C++ の #include プリプロセッサ ディレクティブは、外部ソース ファイルの内容を現在のソース ファイルに挿入し、その内容を現在のソース ファイル内の対応する場所にコピーします。主に、コード内で必要な宣言を含むヘッダー ファイルをインクルードするために使用されます。たとえば、標準入出力関数を組み込むための #include <iostream> などです。

C++ スマート ポインター: ライフサイクルの包括的な分析 C++ スマート ポインター: ライフサイクルの包括的な分析 May 09, 2024 am 11:06 AM

C++ スマート ポインターのライフ サイクル: 作成: スマート ポインターは、メモリが割り当てられるときに作成されます。所有権の譲渡: 移動操作を通じて所有権を譲渡します。リリース: スマート ポインターがスコープ外に出るか、明示的に解放されると、メモリが解放されます。オブジェクトの破壊: ポイントされたオブジェクトが破壊されると、スマート ポインターは無効なポインターになります。

C++ での関数の定義と呼び出しはネストできますか? C++ での関数の定義と呼び出しはネストできますか? May 06, 2024 pm 06:36 PM

できる。 C++ では、ネストされた関数の定義と呼び出しが可能です。外部関数は組み込み関数を定義でき、内部関数はスコープ内で直接呼び出すことができます。ネストされた関数により、カプセル化、再利用性、スコープ制御が強化されます。ただし、内部関数は外部関数のローカル変数に直接アクセスすることはできず、戻り値の型は外部関数の宣言と一致している必要があります。内部関数は自己再帰的ではありません。

js の this が指す状況がいくつかあります。 js の this が指す状況がいくつかあります。 May 06, 2024 pm 02:03 PM

JavaScript では、this のポインティング タイプには、1. グローバル オブジェクト、2. 関数呼び出し、4. イベント ハンドラー、5. アロー関数 (this の外側の継承) が含まれます。さらに、bind()、call()、および apply() メソッドを使用して、これが何を指すかを明示的に設定できます。

Vueのletとvarの違い Vueのletとvarの違い May 08, 2024 pm 04:21 PM

Vue では、let と var の間で変数を宣言するときのスコープに違いがあります。 スコープ: var にはグローバル スコープがあり、let にはブロック レベルのスコープがあります。ブロックレベルのスコープ: var はブロックレベルのスコープを作成しません。let はブロックレベルのスコープを作成します。再宣言: var は同じスコープ内の変数の再宣言を許可しますが、let は許可しません。

See all articles