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

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

ただいまの
回答率

87.90%

Node.jsでのグローバル変数について

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 10K+

score 29

オライリー本のオブジェクト指向JavaScriptの原則にてグローバル変数の解説で以下のようなコードがありました。

function say() {
    console.log(this.name);
}

var person1 = {
    name: "Nico",
    say: say
};

var person2 = {
    name: "Greg",
    say: say
};

var name = "Michael";

person1.say();
// => "Nico"

person2.say();
// => "Greg"

say();
// => "Michael" 

//実際はMichaelではなくundefinedが表示される

//var name = "Michael"
//ではなく
//name = "Michael"
//とすると
//Michaelが表示されることが確認できた。

person1とperson2のsay()については、thisがそれぞれpersonのオブジェクトに割り当てられるためNicoとGregが出力されるのは分かるのですが

var nameでグローバル変数のnameに"Michael"が代入されているはずなのにsayを実行するとundefinedになってしまっています。

書籍内でもMichaelが期待される出力なのですが、これは何故なのでしょうか?

グローバル変数として定義 = グローバルオブジェクトにnameプロパティを追加している、という意味ではないのでしょうか?

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

+5

自分も知らなかったので調べてみました。

https://nodejs.org/docs/latest-v9.x/api/globals.html#globals_global

をみますと、

In browsers, the top-level scope is the global scope. This means that within the browser var something will define a new global variable. In Node.js this is different. The top-level scope is not the global scope; var something inside a Node.js module will be local to that module.

(太字は回答者)

とあります。nodeではvar xxxと記述するとそれはモジュールのローカル変数とみなされるとのことです。おそらくオライリー本がフォーカスしているのはブラウザー上で動作するいわゆるJavaScriptでありNode.jsでは仕様が異なる点があると思うので注意したほうがよいと思います。

じゃぁどう書けばいいのかなと思って「nodejs global」で検索してみるとnodeでは
global.variable_name = value
と書くらしいです。

なおNodeJSでもvariable_name = valueと書けばglobal変数の宣言ができるようですが、strictモードではエラーとなる(global変数として扱われず、宣言ずみの変数と扱われ未定義といわれる)ためこの書き方はどちらかといえば非推奨なのかも知れません。

NodeJS/JavaScriptにあまり明るくないので間違いなどあったらご容赦ください。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/10/01 12:15

    通常のJavaScriptとnode.jsの挙動が違うのですね。

    ブラウザ上で同じコードを動かして確認させていただきたいと思います!



    docsまで貼っていただきありがとうございました!

    キャンセル

+3

KSwordOfHasteさんが答えきってるので、ちょっとした雑学でもぶら下げます。

そもそもグローバル変数を作る用途って、
大抵がこの2種類なので別の方法でもし代用出来れば使う必要はありません。

  • クラスや関数を共有
  • 値をシングルトンとして複数箇所で閲覧

Node.jsはCommomJS由来のrequireあたりの作りがよく出来てて、
requireで実行された外部のjsファイルの挙動はこんな感じになります。

  • require先のコードを読み込む
  • ファイル用のスコープを生成
  • 一通りコードを実行しきる
  • (コード内で)module.exports = valueとして代入する(最も推奨されるのがこれ)
  • module.exportsをrequireの実行結果として持ち帰る
  • 実行したmodule.exportsの中身はrequire関数のプロパティにキャッシュとして保存され、2度目以降は代入済みの値を即返す

この上手い感じの実装により、グローバル変数を利用すること無く、
関数はもちろん、シングルトンも実現できるのです。

$ ls
index.js
singleton.js
show.js

各ファイルの実装はこんな感じ

// index.js
var user = require('./singleton.js');
user.name = 'jiro';
user.age = 17;
console.log(user);
require('./show.js');

// singleton.js
module.exports = {
  name: 'taro',
  age: 18
}

// show.js
var user = require('./singleton.js');
console.log(user);
$ index.js
{ name: 'jiro', age: 17 }
{ name: 'jiro', age: 17 }

index.js側のconsole.logの実行結果は{ name: 'jiro', age: 17 }になるのは一目で分かりますが、
その後に実行されたshow.jsも{ name: 'taro', age: 18 }ではなく、jiroのデータになっています。
実行結果のキャッシュというルールによりindex.jsが行った修正内容が残っていることが分かります。

※まぁDI覚えればこんな使い方のシングルトンも不要なんで、完全に余談ですけどね。


ブラウザに搭載されているJavaScriptはrequireはないので、
考えなしに使いまくるとグローバル変数がすぐに衝突します。

そのため、ベストプラクティスとしてグローバル変数汚染を必要最小限で抑えるためのテクニックが色々と存在します。
クロージャーなんかもそれですが、元になっている変数スコープの知識というのは覚えておいた方が何かと便利ですね。
という訳で、書籍ではわりと早い段階で変数スコープ周りの解説が載ってるんじゃないかなと思います。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

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

関連した質問

同じタグがついた質問を見る