スコープ内のすべての変数を取得する


194

現在JavaScriptのスコープ内にあるすべての変数を取得する方法はありますか?


Camsoftへのあなたの答えについて:それは全く違う質問です。対処するために回答を更新しました。
TJクラウダー2010年

3
これは一般的な質問に過ぎず、ドキュメントが不十分なあいまいなAPIを使用しているため、より具体的にしてもあまり役に立ちません。
Ian

あなたはグローバル変数を意味します!を使用して、列挙可能なグローバル変数を表示できますfor (v in this) alert(v);。ただし、すべてのグローバルが列挙可能であるとは限りません。列挙できないもののリストを取得する標準的な方法は知りません。
Jason Orendorff、2010年

2
@ジェイソン-いいえ、質問は明確です。関数内のスコープ内の変数はグローバル変数が含まれますthisargumentsパラメータおよびスコープを囲んで定義されているすべての変数を。
Tim Down

2
これが、Perlのシンボルテーブルが見つからない理由です。これをJavascriptの将来のリリースに追加する予定はありますか?
Dexygen、2015

回答:


84

いいえ。「スコープ内」変数は「スコープチェーン」によって決定され、プログラムからはアクセスできません。

詳細(かなりの量)については、ECMAScript(JavaScript)仕様を確認してください。ここでは、リンクだあなたは標準的な仕様(PDF)をダウンロードすることができ、公式ページには、とここで一つだ公式、リンク可能なHTMLバージョンに。

Camsoftへのコメントに基づいて更新

イベント関数のスコープ内の変数、イベント関数の呼び出し方法ではなく、イベント関数を定義する場所によって決まります。しかしthisKennyTMが指摘したこと(for (var propName in ____))に沿って何かを行うことで、関数や引数を介して利用できるものに関する有用な情報を見つけることができます()は、提供されているさまざまなオブジェクトで利用できるもの(thisおよび引数、それらがあなたに与える引数がわからない場合はarguments、すべての関数に対して暗黙的に定義されている変数を介して調べることができます)。

したがって、関数を定義する場所が原因で範囲内にあるものに加えて、他の方法で他に何が利用できるかを調べるには、次のようにします。

var n, arg, name;
alert("typeof this = " + typeof this);
for (name in this) {
    alert("this[" + name + "]=" + this[name]);
}
for (n = 0; n < arguments.length; ++n) {
    arg = arguments[n];
    alert("typeof arguments[" + n + "] = " + typeof arg);
    for (name in arg) {
        alert("arguments[" + n + "][" + name + "]=" + arg[name]);
    }
}

(これを拡張すると、さらに役立つ情報を取得できます。)

その代わりに、おそらく、Chromeの開発ツール(通常、開発にChromeを使用しない場合でも)またはFirebug(通常、Firefoxを開発に使用しない場合でも)のようなデバッガー、またはOpera上のDragonflyを使用します、またはIEの「F12 Developer Tools」。そして、それらが提供するJavaScriptファイルを読み通してください。そして、適切なドキュメントを取得するために頭を打ってください。:-)


ちなみに、Google ChromeにはFirebugに匹敵する優れたデバッガーがあります(上にもう少しアイシングがあります)。
2014年

4
@Swivelgames:ああ、私はFirefox + FirebugよりもChromeの開発ツールを好みます。彼らは2010年にはそれほど多くのことをしていませんでした。:-)
TJ Crowder '19

1
@tjcrowder確かに!私は回答のタイムスタンプが少し前であることに気づきました:)
Swivel

98

誰もが「いいえ」と答え、私は「いいえ」が正しい答えであることを知っていますが、本当に関数のローカル変数を取得する必要がある場合、制限された方法があります。

この関数を考えてみましょう:

var f = function() {
    var x = 0;
    console.log(x);
};

関数を文字列に変換できます:

var s = f + '';

関数のソースを文字列として取得します

'function () {\nvar x = 0;\nconsole.log(x);\n}'

今、あなたは次のようにパーサーを使用することができますesprima機能コードを解析し、ローカル変数の宣言を見つけること。

var s = 'function () {\nvar x = 0;\nconsole.log(x);\n}';
s = s.slice(12); // to remove "function () "
var esprima = require('esprima');
var result = esprima.parse(s);

とオブジェクトを見つける:

obj.type == "VariableDeclaration"

結果(私はconsole.log(x)以下を削除しました):

{
    "type": "Program",
    "body": [
        {
            "type": "VariableDeclaration",
            "declarations": [
                {
                    "type": "VariableDeclarator",
                    "id": {
                        "type": "Identifier",
                        "name": "x"
                    },
                    "init": {
                        "type": "Literal",
                        "value": 0,
                        "raw": "0"
                    }
                }
            ],
            "kind": "var"
        }
    ]
}

私はこれをChrome、Firefox、Nodeでテストしました。

しかし、この方法の問題は、関数自体に変数が定義されていることです。たとえば、この場合:

var g = function() {
    var y = 0;
    var f = function() {
        var x = 0;
        console.log(x);
    };
}

yではなく、xにアクセスできます。ただし、ループ内で呼び出し元のチェーン(arguments.callee.caller.caller.caller)を使用して、呼び出し元関数のローカル変数を見つけることができます。すべてのローカル変数名があり、スコープ変数がある場合。変数名を使用すると、単純なevalで値にアクセスできます。


7
元の問題に取り組む際の優れたテクニック。賛成票に値する。
deepelement 2014

4
呼び出し元の変数は必ずしもスコープ変数ではありません。また、スコープ変数は必ずしも呼び出しチェーンにある必要はありません。閉じられた変数は、定義/クロージャスコープの外にある呼び出し元から呼び出されたときに、クロージャ関数によって参照される可能性があります(その変数は、クロージャの本体からアクセスできません)。
DDS

「簡単な評価」をわかりやすく説明していただけませんか?以下のコードを試してみましたが、スコープにトラップされた変数を取得できませんでした。function getCounter(start){ return function(){ start ++; return start; } } var counter = getCounter(1); var startInClosure = eval.call(counter, 'this.start;'); console.log(startInClosure);それは印刷しundefined、私はそれが2でなければなりません期待しながら
Pylipala

@Pylipalaここでの質問は、スコープ内の変数がスコープ外からローカル変数の値を取得しないことです。これは、外部からアクセスできないようにする必要があるローカル変数の定義であるため、不可能です。コードに関しては、スコープではなくコンテキストを意味しますが、コンテキスト(this)でstartを指定しなかったため、this.startで読み取ることはできません。ここを参照してください:paste.ubuntu.com/11560449
イマン

@imanご回答ありがとうございます。また、JavaScript側では不可能だと思いますので、v8側では可能かと思います。私の問題を正確に説明している質問リンクの下に私は見つかりました。その中でラッセ・ライヒシュタインはノーと言うが、マコタコはイエスと言う。リンクとしていくつかのC ++コードを試しましたが、それを書く方法がわかりません。
Pylipala

32

はいといいえ。ほとんどすべての状況で「いいえ」。「はい」。ただし、グローバルスコープを確認する場合に限られます。次の例を見てください。

var a = 1, b = 2, c = 3;

for ( var i in window ) {
    console.log(i, typeof window[i], window[i]);
}

150以上の中で、以下を出力します。

getInterface function getInterface()
i string i // <- there it is!
c number 3
b number 2
a number 1 // <- and another
_firebug object Object firebug=1.4.5 element=div#_firebugConsole
"Firebug command line does not support '$0'"
"Firebug command line does not support '$1'"
_FirebugCommandLine object Object
hasDuplicate boolean false

したがって、現在のスコープ内のいくつかの変数をリストすることは可能ですが、信頼性が高く、簡潔で、効率的で、簡単にアクセスできるわけではありません。

より良い質問は、なぜスコープ内にある変数を知りたいのですか?


2
質問はより一般的で、WebブラウザーのコンテキストでのJavaScriptに限定されていなかったと思います。
Radu Simionescu 2012年

ノードを使用している場合は、「ウィンドウ」という単語を「グローバル」に変更するだけです。または、「this」という単語を使用できますが、「use strict」では禁止されています
Ivan Castellanos

hasOwnPropertyの行チェックを追加しました。次に例を示しますfor ( var i in window ) { if (window.hasOwnProperty(i)) { console.log(i, window[i]); }}。これにより、少なくとも継承されたプロパティが削減され、変数は他の約50のプロパティに含まれるようになります。
timctran 2015年

8
デバッグや開発の目的で、スコープ内の変数を少なくとも誰かが確認したくないのはなぜですか。
Dexygen、2015

ローカルスコープにどの変数があるかを知りたいもう1つの理由は、クロージャーをシリアル化することです。
マイケル

29

ECMAScript 6では、withステートメント内のコードをプロキシオブジェクトでラップすることで、多かれ少なかれ可能です。非厳密モードが必要であり、これは悪い習慣であることに注意してください。

function storeVars(target) {
  return new Proxy(target, {
    has(target, prop) { return true; },
    get(target, prop) { return (prop in target ? target : window)[prop]; }
  });
}
var vars = {}; // Outer variable, not stored.
with(storeVars(vars)) {
  var a = 1;   // Stored in vars
  var b = 2;   // Stored in vars
  (function() {
    var c = 3; // Inner variable, not stored.
  })();
}
console.log(vars);

プロキシは、内部withで参照されるすべての識別子を所有していると主張しているため、変数の割り当てはターゲットに保存されます。ルックアップの場合、プロキシはプロキシターゲットまたはグローバルオブジェクト(親スコープではない)から値を取得します。letそしてconst変数が含まれていません。

触発され、この答えによってBergi


1
これは、そのような単純な手法では驚くほど成功しています。
ジョナサンユーニス

WOWスーパーパワー
ペリーミモン

16

できません。

変数、関数宣言の識別子、関数コードの引数は、アクセスできない変数オブジェクトのプロパティとしてバインドされます。

以下も参照してください。


1
真ですが、スコープ内の変数は現在の変数オブジェクトだけにとどまりません。スコープ内変数は、スコープチェーンによって決定されます。スコープチェーンは、一連の変数オブジェクトで構成され(通常の場合)、グローバルオブジェクトで終了します(withステートメントを使用してチェーンに他のオブジェクトを挿入できます)。
TJクラウダー2010年

+1(bclary.comへのリンク)。最新の仕様のHTMLバージョンがECMAのWebサイトに今後2か月以内に表示されると思います。
TJクラウダー2010年

3
ただ注意してください、両方のリンクが壊れています。
0xc0de


8

特定のスコープでVarにアクセスする最も簡単な方法

  1. デベロッパーツールを開く>リソース(Chrome内)
  2. そのスコープにアクセスできる関数でファイルを開きます(ファイルを見つけるためにcmd / ctrl + pをヒントします)
  3. その関数内にブレークポイントを設定し、コードを実行します
  4. ブレークポイントで停止すると、コンソール(またはスコープ変数ウィンドウ)からスコープ変数にアクセスできます

注:縮小化されていないjsに対してこれを行う必要があります。

非プライベート変数をすべて表示する最も簡単な方法

  1. コンソールを開く(Chrome内)
  2. タイプ:this.window
  3. Enterキーを押す

これで、宣言されたすべてのオブジェクトで展開できるオブジェクトツリーが表示されます。


7

誰もが気づいたように、できません。しかし、objを作成し、宣言したすべてのvarをそのobjに割り当てることができます。そうすれば、変数を簡単にチェックアウトできます。

var v = {}; //put everything here

var f = function(a, b){//do something
}; v.f = f; //make's easy to debug
var a = [1,2,3];
v.a = a;
var x = 'x';
v.x = x;  //so on...

console.log(v); //it's all there

1
クール例えば+1のおかげで、唯一の完了のために同じことを介しても見ることができるconsole.log(window); jsfiddle.net/4x3Tx
Stano

5

私が作っフィドル(基本的に)イマンによって概説アイデアの上に実装します。これは、2番目のipsumにマウスを置いたときの様子です。return ipsum*ipsum - ...

ここに画像の説明を入力してください

スコープ内の変数は、宣言された場所で強調表示されます(スコープごとに異なる色で)。lorem赤い境界とする影可変である(スコープではないが、さらに木ダウン他のLoremのが存在しない場合範囲にあります。)

私はesprimaライブラリーを使用してJavaScriptを解析し、estraverse、escodegen、escope(esprimaの上にあるユーティリティー・ライブラリー)を使用しています。「重いリフティング」はすべてこれらのライブラリーによって行われます(もちろん、esprima自体が最も複雑です)。

使い方

ast = esprima.parse(sourceString, {range: true, sourceType: 'script'});

抽象構文木を作成します。そして、

analysis = escope.analyze(ast);

プログラム内のすべてのスコープに関する情報をカプセル化する複雑なデータ構造を生成します。残りは、その分析オブジェクト(および抽象構文ツリー自体)にエンコードされた情報を収集し、それからインタラクティブなカラーリングスキームを作成します。

したがって、正解は実際には「いいえ」ではなく「はい」です。「しかし」は大きな問題です。基本的に、JavaScriptでChromeブラウザー(およびそれは開発ツール)の重要な部分を書き直す必要があります。JavaScriptはチューリング完全言語ですので、もちろんそれは原則的に可能です。ソースコード全体を(文字列として)使用せずにすべてを実行し、それを使用して非常に複雑な処理を実行するのは不可能です。


3

デバッグに役立つように変数を手動で検査したい場合は、デバッガーを起動します。

debugger;

ブラウザコンソールに直接アクセスします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.