質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.54%

クロージャーを利用した関数スコープ内の現在の変数名と値を取得することはできますか?

解決済

回答 7

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 1,373

domidomi

score 29

function fn(n) {
    var cnt = n;
    return function() {
        return ++cnt;   
    }
}
var f = fn(0);
f() // 1


このようにクロージャーを使った変数の保持をしている場合、
fの現在のcntという変数名と値を取得することはできますか?

(chromeのdevtoolを用いれば見れることは知っています。)

追記

chromeを使った場合なのですが
・関数定義&1回使用
イメージ説明
・windowオブジェクトみる
イメージ説明
・さっき作った関数を確認
イメージ説明

こんな感じでその関数に付随するスコープが確認でき、さらにその中身の値まで知ることが出来ます。
どこかに保持されているのならjavascriptを用いて(例えば実際は無いですがfunc.scopesでスコープオブジェクトが出てきたりとかで)確認する方法がないかなーと思った次第です。

好奇心からの質問であり、特に用途は考えていないのでまったくもって意味のない事の可能性もあります、すみません・・・

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • macaron_xxx

    2019/06/20 15:56

    何をもって”取得”といっているのですか?

    キャンセル

  • domidomi

    2019/06/20 16:23

    fという関数があると分かっている状態で
    fの中で宣言されている変数名(今回は"cnt")とその現在の値(今回は1度使われているので1)を
    知ることが出来るのか?です。

    Object.keys(obj)を用いてオブジェクトのプロパティを得る事ができるように
    関数オブジェクトに紐づいているクロージャースコープの変数の値をとる手法ってないのかな?
    と思った次第です。

    キャンセル

回答 7

checkベストアンサー

+3

Object.keys(obj)を用いてオブジェクトのプロパティを得る事ができるように
関数オブジェクトに紐づいているクロージャースコープの変数の値をとる手法ってないのかな?

標準的なJavaScriptには用意されていません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/06/20 16:28

    それを逆用して、Chromeでは「スコープ内にあるけどクロージャから参照されていない変数」を最適化で除去してしまいます。プログラムから取得する方法があるのであれば、このような最適化をすることは許されないはずです。

    キャンセル

  • 2019/06/20 21:44

    いつもありがとうございます。
    付加情報も非常に納得いたしました。

    キャンセル

+2

スコープ外の変数を取得することは出来ません
(取得する裏技があったら、スコープの意味がありません)

function fn(n) {
    var cnt = n;
    return function() {
        return ++cnt;   
    }
}

変数 cnt は「関数 fn 内」及び「関数 fn の内部関数」のみにスコープがあります。

Re: domidomi さん

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

クラス化する、インスタンス化する等はあります。

ただ、どうしてもクロージャで行いたいという要望の場合、隠ぺいが目的かと思いますので、取得とカウントする処理の関数各々かえせばいいんじゃないでしょうか。

function fn(n) {
    var cnt = n;
    return {
      up:function(){return ++cnt;},
      state:function(){ return cnt;}
    }
}
var f = fn(0);
f.up() // 1
f.state() // 1

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/06/20 16:09

    変数名を取得したいと言っているのでそれは違うような気がします

    キャンセル

  • 2019/06/20 16:17

    hentaimanさん
    確かに質問文を読み落としておりました。わざわざ変数名を取得したいという事であれば、上記は不可能ですね。
    どうしても行居た場合は、オブジェクト定義してKEY取るかの実装になるかと思います。

    また、差し出がましくはありますが、hentaimanさんの回答につきましても私見をコメントさせて頂きました。

    キャンセル

0

なんか不毛なことをやっているような気がします

const fn=(...n)=>()=>++n[0];   
const f=fn(0);
console.log(f()) // 1


みたいな話ですよね?
nが"n"であることは調べられないし、そもそもアクセスもできないのでは?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

変化球っぽいですがオブジェクトとして返してあげれば良いのでは?

function fn(n) {
    var cnt = n;
  return function () {
    ++cnt;
    return {cnt}    
    }
}
var f = fn(0);
console.log(f()); // { cnt: 1 }
console.log(f()); //{ cnt: 2 }
console.log(Object.keys(f())); //[ 'cnt' ]

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

-3

varで定義したものを取得する方法は知らないけど、thisならfnオブジェクトに属するものって事で取れます。

  1 function fn(n) {
  2     var cnt = n;
  3     this.cnt2= n;
  4     return function() {
  5         //return ++cnt;
  6         return this;
  7     }
  8 }
  9 var f = fn(0);
 10 f() // 1
 11 console.log(f());

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/06/21 16:07 編集

    質問者ってのはコメントした人(AzumaOさん)のことですか?それとも回答者(hentaiman)の事ですか?
    AzumaOさんが指摘してくれと言ってるかどうかは知りませんが、AzumaOさんに関しての事ならすいませんが回答とかほとんど読んでません。サッと見た感じ変な言葉ばっかりで読みにくかったので。
    hentaimanの事なら、少なくとも回答から逸れた話題にならない限りはとりあえず普通の対応か多少hentaiな対応するぐらいです。

    キャンセル

  • 2019/06/21 16:11

    間違えました。質問者ではありませんでした。コメントした人(AzumaO)のことです。

    キャンセル

  • 2019/06/21 16:11

    質問者さん、hentaiman さんすみません。

    キャンセル

-10

クロージャの仕組みは、レキシカル環境(lexical environment)が関わってきます。

そして、レキシカル環境というのは、JavaScriptエンジンの内部処理を規定するための概念・用語であり、実際のコード(JavaScript)でアクセスする事は出来ません。

レキシカル環境は、....の定義に使用される仕様用のタイプです。

A Lexical Environment is a specification type used to define ...

...
レキシカル環境と環境記録の値は、純粋に仕様の仕組みであり、ECMAScript実装の特定の現実物に対応する必要はありません。 ECMAScriptプログラムがそのような値(レキシカル環境・環境記録)に直接アクセスしたり操作したりすることは不可能です。
...

...
Lexical Environments and Environment Record values are purely specification mechanisms and need not correspond to any specific artefact of an ECMAScript implementation. It is impossible for an ECMAScript program to directly access or manipulate such values.
...

クロージャとレキシカル環境の関係

レキシカル環境(lexical environment)

レキシカル環境とは、大まかにいうと、コード実行処理時に形成される領域と、それに伴う変数の記録簿の事です。また、両方を指す場合にも使われます。

コードが処理され始め、グローバルが処理されている時関数が呼び出された際に、レキシカル環境は生成されます。今JSエンジンが処理している部分を含む"領域"をレキシカル環境といい、その外側を外側レキシカル環境といいます。

例えば、以下のコードを見て下さい。

// グローバル

←(JSエンジン処理点)

var goku = "Son Goku";

レキシカル環境: グローバル  
外側レキシカル環境: null

です。

レキシカル環境にはgokuという識別子が記録されており、値"Son Goku"が対になって保存されています。
グローバルの外側はないので、その様な場合、外側レキシカル環境はnullになります。

また、先程述べたように、関数が呼び出された際にも、レキシカル環境は生成されます。

// グローバル


var goku = "Son Goku";

function greeting(){
   // ローカル(ローカル)
      ←(処理点)

   console.log( "hi" )
}


greeting(); ←(処理点: 定義内処理中)

レキシカル環境: greeting関数内  
外側レキシカル環境: グローバル

処理がグローバル → 関数 へ移ると、関数内の新たなレキシカル環境が生成され、グローバルを処理していた時に作成されたレキシカル環境は消滅します。

クロージャ(closure: 閉包)

クロージャとは、関数が入れ子状で定義されており、且つ、コード実行時に内側の関数が返却された場合、その返却された関数の外側レキシカル環境が維持される、というメカニズムです。

抽象的すぎて分かりにくいので、実際にコードを元に見ていきましょう。

function outer() {
    // `inner`の外側 レキシカル環境

    var cnt = 0;
    function inner() {
        // `inner`のレキシカル環境

        return ++cnt;
    }
  return inner;
}

関数innerのレキシカル環境には、変数は宣言されていません。関数innerの外側レキシカル環境には、変数cntが宣言されています。

先程も言いましたが、関数が実行される際にこのレキシカル環境は生成され、変数もそこに保存されます。そして、関数の処理が終われば、この両方のレキシカル環境も消去されてしまいます。

ところがです。関数を返却する関数の場合は(関数outer)、その返却された関数(関数inner)の外側レキシカル環境は維持されたまま、関数にくっ付いた状態で返却されるのです。

ですので、返却される予定の関数inner内で、その外側レキシカル環境の変数ctnにアクセスするような処理を書いておくことにより、返却後、inner関数を実行することによって、維持された状態の外側レキシカル環境(変数)にアクセスする事ができるのです。

もちろん、変数ctnは関数内で定義されているので、その外側からはアクセスできません。

function outer() {
   var cnt = 1;

   function inner() {
      return ++cnt;
   }
   return inner;
}

これがクロージャの仕組みです。

メソッドによるクロージャ

今後、余裕があれば追記致します(。•ㅅ•。)

追記

高評価を頂けた方・冷静に適切なコメントを頂けた方、ありがとうございます。一部の荒らし者がコメントに混入してきた為、追記は削除しました(。•ㅅ•。)🌟 通知でご迷惑をお掛けしていたら、すみません(。•ㅅ•。)🌟

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/06/22 02:55

    > raccyさん
    丁寧に解説頂きありがとうございました。僕の回答語彙を「レキシカル」に直しておきました。
    raccyさんの解説により、僕が大きく間違っていた点がはっきり致しました。

    解説コメントを読み、もう一度lexical, lexiconの辞書の定義を注意深く読むと、「文字一つ一つを表す」という意味では全くなく、「字母」でもなんでもありませんでした…💦💦

    lexicon -Collins Dictionary-
    > 2. the special vocabulary of a particular author, field of study, etc.
    > 3. the vocabulary of a language or of an individual

    lexicon -Online Etimology Dictionary-(https://www.etymonline.com/word/lexicon)
    > c. 1600, "a dictionary, a word-book," from Middle French lexicon or directly from Modern Latin lexicon, from Greek lexikon (biblion) "word (book)," from neuter of lexikos "pertaining to words," from lexis "a word, a phrase; reason; way of speech, diction, style," from legein "to say," from PIE root *leg- (1) "to collect, gather," with derivatives meaning "to speak (to 'pick out words')."

    今回僕がこのような状況を招いたのは、raccyさんが仰るように
    > あまりにも他の言語を知らなさすぎ

    であるという点も大きいと再認識致しました。それに加え、辞書的意味ですら誤読しておりましたし…💦💦

    今後、当分回答は控えます。様々な言語や概念に親しみ、もっと理解と知識と実力を身に付けようと思ます。



    回答者(小生)が間違っている点を、多量の知識と経験と技術をもって、しかし1ミリも偉そうにせず、明確に論理的に指摘してくださるraccyさんのような方がおられて大変感謝であります。本当にありがとうございました(•ᵕᴗᵕ•)⁾⁾🌟

    キャンセル

  • 2019/06/22 06:16

    raccy さん hayataka2049 さん
    ありがとうございます。なかなかぴったり重なる言葉がないために適当な訳語が定着していないのでしょうね。
    字母は論外ですが、字句でも語彙でも辞書でも権威ある組織が使用して定着するならば私は少々のズレには目をつぶって使用できますし、実際そのような訳語も他にいくつかあります。それは翻訳につきものの悩みでしょう。
    が、まだ全然通じない言葉、いやまだどころか変な笑いの出るような珍妙な独自言語をどや顔で大量に押しつけ、それが認められなければ迷惑行為を働くようなのはどうかと思うので、なんという名前か忘れましたが、彼が少しでも反省の色を見せたのは良かったと思っています。

    キャンセル

  • この投稿は削除されました

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.54%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる