1

私が想定しているのは非常に基本的な質問ですが、JavaScript関数をGoogleで大雑把に検索すると、「これ」と、物事をグローバルに宣言しない理由、およびオブジェクトの作成に関するあらゆる種類の情報が返されます。

を使用してインタラクティブな地理チャートを作成しようとしています。ここに作業バージョンがあります(一種):

<!--
You are free to copy and use this sample in accordance with the terms of the
Apache license (http://www.apache.org/licenses/LICENSE-2.0.html)
-->

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
  <title>Google Visualization API Sample</title>
  <script type="text/javascript" src="http://www.google.com/jsapi"></script>
  <script type="text/javascript">
    google.load('visualization', '1', {packages: ['geochart']});

    var width, height, selectedRegion, resolution;

    window.onload = function(){
      width = 556;
      height = 400;
      selectedRegion = 'world';
      resolution = 'subcontinents';
    };

    function drawVisualization() {
      var data = new google.visualization.DataTable();
      data.addColumn('string', 'Region');
      data.addColumn('number', 'Value');
      data.addRows([
        [{v:"005", f:"South America"}, 978.7],
        [{v:"011", f:"Western Africa"}, 46],
        [{v:"013", f:"Central America"}, 299],
        [{v:"014", f:"Eastern Africa"}, 63.9],
        [{v:"015", f:"Northern Africa"}, 255.7],
        [{v:"017", f:"Middle Africa"}, 21.4],
        [{v:"018", f:"Southern Africa"}, 244.5],
        [{v:"029", f:"Caribbean"}, 76.5],
        [{v:"030", f:"Eastern Asia"}, 5712.9],
        [{v:"034", f:"Southern Asia"}, 1275.1],
        [{v:"035", f:"South-Eastern Asia"}, 639.2],
        [{v:"039", f:"Southern Europe"}, 777.8],
        [{v:"053", f:"Australia and New Zealand"}, 272],
        [{v:"054", f:"Melanesia"}, 6.3],
        [{v:"057", f:"Micronesia"}, 1.8],
        [{v:"061", f:"Polynesia"}, 1],
        [{v:"143", f:"Central Asia"}, 170.3],
        [{v:"145", f:"Western Asia"}, 834.1],
        [{v:"151", f:"Eastern Europe"}, 1587.6],
        [{v:"154", f:"Northern Europe"}, 801.5],
        [{v:"155", f:"Western Europe"}, 1456.2],
        [{v:"021", f:"Northern America"}, 4704.1]
      ]);

      var options = {
        displayMode: 'regions',
        enableRegionInteractivity: 'true',
        resolution: resolution,
        region: selectedRegion,
        height: height,
        width: width
      };

      var geochart = new google.visualization.GeoChart(
          document.getElementById('visualization'));

      google.visualization.events.addListener(geochart, 'select', function() {
        var selection = geochart.getSelection();

        if (selection.length == 1) {
          var selectedRow = selection[0].row;
          selectedRegion = data.getValue(selectedRow, 0);
          resolution = "countries";
          options.region = selectedRegion;
          options.resolution = resolution;
          //alert(resolution);
          geochart.draw(data, options);
          }
      });

      geochart.draw(data, options);
    }

    google.setOnLoadCallback(drawVisualization);
  </script>
</head>
<body style="font-family: Arial;border: 0 none;">
<div id="visualization"></div>
</body>
</html>

コードが適切に機能すること (そして、より大きなプロジェクトの一部として改善したいこと) は、マップ上の地域をクリックすると、マップのオプションが変更されて再描画され、その地域をさらにズームインすることです。

これは素晴らしいことですが、上記は 1 つの巨大な関数であり、関数内にハンドラー関数があります。これは非常に扱いにくくなります。なぜなら、ズームアウトしたり、マップをリセットして全世界を表示したり、選択した地域に応じてはるかに大きなデータ セットを調整したりする必要があるからです (上記の例では、現在データは表示されていません)。

そのため、コードをより管理しやすいチャンク、個別にデバッグできるチャンクに分割し、どこで何が問題になっているのかをよりよく理解できるようにし、一般的に、私は専門のプログラマーとはかけ離れているため、プロジェクト全体をより管理しやすくしたいと考えています。 (正直に言うと、おそらく初心者のプログラマーとはかけ離れています)。

分割したいチャンクは次のとおりです。

  1. データを定義する (オプションが変更されるたびに)
  2. オプションを定義する (オプションが変更されるたびに)
  3. マップの描画 (機能 5 ~ 7 が実行されるたびに)
  4. リスナーを追加(1回)
  5. 地図上で拡大する機能(クリック時)
  6. 地図上でズームアウトする機能(クリック時)
  7. マップをリセットする機能 (クリック時)
  8. データを操作する関数 (関数 5 ~ 7 が実行されるたびに)

私が問題に遭遇するのは、非常に基本的なことです。すべての変数をグローバルに (プレフィックスを付けずにvar) 宣言することはできますが、これは一般的に推奨されておらず、おそらく長期的には悪影響を与えると思います (特に、10,000 要素で可変的に宣言された巨大なデータ テーブルがある場合)。これが間違っている場合は、修正してください - 私の限られた理解からグローバル変数を使用することは悪いことですが、JavaScript は特別なのでしょうか?

これらの関数の 1 つに注目してみましょう。その 1 つの関数がどのように機能し、相互作用するかを理解できれば、おそらく他の関数も理解できるでしょう。

グラフを描くには、次の 2 つの情報が必要です。

  1. どのデータを使用するか
  2. 使用するオプション

ここで、データとオプションの両方をグローバル変数として宣言すると、他の関数から喜んで操作できます (どうもありがとうございました)。ただし、それらはグローバルです。ものを関数に渡し、必要に応じて調整されたデータを返す方法がわかりません。

たとえば、次のように作業マップを簡単に作成できます。

function drawVisualization() {
  var rawData = new google.visualization.DataTable();
  rawData.addColumn('string','Continent');
  rawData.addColumn('string','Subontinent');
  rawData.addColumn('string','Country');
  rawData.addColumn('number','Data');
  rawData.addRows([
    [{v:"142",f:"Asia"},{v:"145",f:"Western Asia"},{v:"AE",f:"United Arab Emirates"},91.9],
    // more data in between
    [{v:"002",f:"Africa"},{v:"014",f:"Eastern Africa"},{v:"ZW",f:"Zimbabwe"},7.8],
  ]);

  resetMap();

  var data = new google.visualization.DataView(rawData);
  data.setColumns([resolutionIndex, 3]);

  var options = {
    displayMode: displayMode,
    enableRegionInteractivity: 'true',
    resolution: resolution,
    region: region,
    height: height,
    width: width
  };

  drawMap(data, options);

}

function drawMap(data, options) {
  var geochart = new google.visualization.GeoChart(document.getElementById('visualization'));
  geochart.draw(data, options);
}

function resetMap() {
  resolutionArray = ['continents', 'subcontinents', 'countries'];
  resolutionIndex = 0;
  previousIndex = 0;
  previousRegion = 'world';
  displayMode = 'regions';
  resolution = resolutionArray[resolutionIndex];
  region = 'world';
  height = '600';
  width = '800';
}

このコードの問題は、「オプション」変数内のこれらすべての変数をグローバルとして設定する必要があることです。関数resolution内のように変数を更新すると、resetMap()オプション内の値が実際に影響を受けるかどうかはわかりません(必要ですか?options後で変数を更新する別の関数を作成しますか?)。また、すべてがグローバルであるように見えますが、変数をやり取りして、それらがすべて連携して作業を完了できるようにする方法がわかりません。

これは非常に長い投稿であり、おそらく非常に単純な概念で解決できることはわかっていますが、頭を包むことはできません. 誰かが一般的なポインタ、または真の初心者向けに書かれた JavaScript で関数がどのように機能するか (関数がどのように機能するか、それらがどのように定義されているか、それらから値を返す方法など) の説明を持っている場合、私は非常に感謝しています。

4

2 に答える 2

2

正確な理由を知らずに (それは悪いことです!) グローバル変数を持つことを心配しています (それは良いことです!)。それらの主な問題は、今日では Web ページでさまざまなソースからのスクリプトを組み合わせることが非常に一般的であることです。それらのすべてがグローバル変数を使用している場合、名前の衝突が原因で別の変数に干渉する (そして壊れる) 可能性が高くなります。そのため、ベスト プラクティスはグローバルを避けることです。

そのためには、まずJavaScript でスコープがどのように機能するかを理解する必要があります。すべての関数は新しいスコープを作成するため、var関数内で宣言された a はそこでのみ表示されます。ネストされた関数内でも表示されます (クロージャー経由)。グローバル変数を回避したい場合は、これら 2 つの概念を理解することが不可欠です。

また、簡単な言語機能も役立ちます。「即時に呼び出される関数式」(IIFE) を使用して、コードのブロックを独自のスコープにラップできます。グローバル スコープの代わりにそのスコープを使用して、変数を内部関数と共有し、クロージャーを介して変数にアクセスできます。

(function(){
    // declare common variables here
    var a = 1, b = 2, c = 3;

    // any function declare here can access a, b, c
    function foo() {
        console.log(a);
    }

    // works with anynymous function expressions too
    document.addEventListener('click', function(e) {
        alert(b);
    });
}());

これにより、既存のものと非常によく似たコードを作成できますが、グローバルをリークすることはありません。

オブジェクト指向の jsを使用すると、コードを構造化するのにも役立ちますが、これは幅広いトピックであり、具体的な問題について質問しない限り、ここで詳細を説明することはできません。

于 2013-02-19T14:43:45.030 に答える
-1

jQuery Learning のCode Organizationページが興味深いかもしれません。jQuery を使用していない場合でも、ほとんどの概念は適用されます。

于 2013-02-19T05:38:24.720 に答える