K2さんの雑記
2018-05-02(Wed) [長年日記]■ 日本一マクドナルドから遠い場所の記事が面白そうだったので、やってみたGoogle Mapに、自分の好きなマーキングができそうな記事を、はてなブックマーク経由で見つけていて、面白そうだったのでやってみた。 シナリオは、マクドナルドのページから、店舗情報を取得してローカルに保存、Google Map上に表示するものを作成するというもの。タイトルのページでは、日本で一番マクドナルドから遠い場所はどこかを調べたり非常におもしろい考察をしているので、見てください。私は、とりあえず表示するところまでがんばってやってみようと思った。 まずマクドナルドから店舗情報をjson形式のファイルでローカルにダウンロードする方法を探す。詳細はタイトルページには載っていないので、自分でChromeのデベロッパーツールで調べた。今回デベロッパーツールもはじめて本格的に見たので、店舗情報を探し出すまではかなり手間取った。 Networkのタブで表示されるオブジェクトを一つ一つ見ていくと、地図の表示領域の範囲にある店舗情報が入っているオブジェクトを見つけた。全2887店舗分は入っていない。タイトルページでは、全店舗のjsonがデベロッパーツールで見れるとあったが、結局それは探し出せず。で、表示領域の範囲の店舗情報は、マクドナルドのホストにクエリを出せばもらえているので、ノーオプションで試して見ると、無事全店舗情報が取得できた。 さて、次はFusionTableが紹介されているので、使ってみた。Googleドライブで、まずFusionTableサービスを追加して、新規作成、ファイルをインポートするのだが、ここではcsvファイルを要求される。上記のjsonファイルをK2Editorに読み込んで、キーマクロでcsvファイルに変更。2900店舗分ほどのファイルで、変更に30分くらいかかった。本当はスクリプト言語で変換すれば簡単だと思うのだが、直感的なキーマクロでやってしまった。 で、Fusion Tableにインポートすると、元のファイルに含まれている緯度と経度は自動的に緯度と経度として認識されていて、そのままMap表示をすると全店舗が表示された。 ここでタイトルページは、方針変更、Google Maps JavaScript APIを使用するシナリオに進むので、私もそちらへ。Google APIを使用するのも始めてだったので、全部一から調べたが、Google Developers Consoleに行き、そのまま新規プロジェクトを作成、Google Maps Javascript APIを有効化して、APIキーを取得できた。 で、タイトルページに掲載されているhtmlファイルとjsファイルを使用して、ローカルのChromeで全マクドナルド店舗を地図上に表示することに成功した。下記の図は、1kmの円で描画したマクドナルド店舗マップ。 結構簡単にGoogle Mapが使えることがわかったので、これは仕事で使えそう。個人情報保護の観点であまり公開できるものにはならないが、身内で使うツールとかが作れそうなので、GW明けからがんばってみたい。 2018-05-03(Thu) [長年日記]■ そういうわけで、JavaScript昨日の、Google Maps JavaScript API使用を業務で使おうと思うのだが、今まで全くJavaScriptにさわったことがなかったので、このGWを利用してJavaScriptを勉強してやろうと思った。 テキストは、改訂新版JAVASCRIPT本格入門。Kindle版を購入。 電子書籍を読みながらコーディングするのは、ディスプレイが2枚あると簡単なんだが、ノートPCのみの場合は、iPad miniの出番。iPad miniで書籍を読んで、ノートPCでコーディングする。 本日の勉強部屋はスタバ。 letとvarの違いES2015から追加された変数宣言のためのletは、varと以下の点で違う。
すぐ忘れてしまうので、メモ。 JavaScriptでは、連想配列と「オブジェクト」が同じ?「オブジェクト」は多くの言語では、最も基本になるクラスに与えられる名称であることが多いが、JavaScriptの場合は、連想配列を「オブジェクト」と呼ぶようだ。 教科書にはNoteとして同じであることが示されているが、理由までは書いてない。うまく「オブジェクト」と連想配列という言葉がつながらない。違和感しかない。 おまけに!、連想配列の個々のデータは、「プロパティ」、このプロパティが関数の場合(関数も格納することができる)、特別に「メソッド」と呼ぶらしい! ということは、連想配列が「クラス」に近い言葉として定義されていると言うことなのだろうか。 もうちょっと学ぶと合点がいくかもしれないので、このまま進めます。 追記アクセス方法で、通常 obj['x'] としてアクセスするのは自然だが、JavaScriptの場合は、同様に、 obj.x でアクセスできるらしい。 ああ、これはオブジェクトだな。ちょっと合点した。 追記2読み進めると、 var today = new Date(); のコードで、todayがオブジェクトである意味の記述が教科書本文に出てきた。 ここでまた混乱。 このコードは、他の言語ではクラス生成してインスタンスをtodayに入力するものだが、JavaScriptの場合は、オブジェクトは連想配列だと習った。とすると、new Date()という記述は、連想配列を作成するという意味なのだろうか…… 読み進めよう。 インクリメント・デクリメント演算子はあり前置演算と後置演算の区別もあり。最近の言語では珍しい?(そもそも最近の言語ではないのか……) 等価判定は===イコールを3つ重ねる演算子は始めて見た。 追記==も等価演算子。しかしながら、両辺のデータ型が違う場合は、数値(文字列や論理型)や基本型(オブジェクトの場合)に変換して比較する。両辺とも参照型の場合は、参照先が等しいかどうかを判定する。 ===は、データ型も同じ場合にtrueになるより厳密な等価演算子。 ==は、無理矢理型変換をして比較をするので、バグを生みやすい。 教科書ではできるだけ===を使うように記述されている。 数値やundefinedなどの論理値0やNaN、""、null、undefinedはfalse、それ以外はtrueと見なされる。最近の言語ではちょっと違和感がある実装? and、orの際の短絡演算false && Aや、true || Aの場合、Aを実行する前に結果が確定しているから、Aは実行されない。C言語等ではおなじみ。 時代背景からか、C言語に近い実装が多いね。 使用例として、 var msg = ''; msg = msg || 'Default String.'; という例が紹介されている。msgが空文字の時に、"Default String."を代入するというものだが、これはあまり感心できないな。テクニックとしてはわかるけど、もう少しわかりやすく書くべき。 switch文はC言語仕様とほぼ同じ今や他の言語では見ることがなくなったbreak文が必要なcase句。使い方によっては便利だが、わかりにくくなるデメリットの方が大きいので、現在ではこのような仕様を持つsiwtch-case文は他の言語には見られない。 配列要素をfor文で列挙する場合for ... inは、連想配列の場合だけに使う。配列では副作用があるので、推奨されていない。 また、通常のfor文で列挙する場合も、毎回配列のlengthプロパティ(メソッド?)にアクセスするとレガシーブラウザの場合は性能が劣化するため、以下のように初期化ブロックで変数に取り出しておくのが推奨されている。 var data = ['apple', 'orange', 'banana']; for (var i = 0, len = data.length; i < len; i++) { console.log(data[i]; } または、for ... of文で、値を列挙する。(ただしES2015以降) for(var value of data) { console.log(value); } ラベル構文必要悪なラベルジャンプ的なものもある。ただしgotoよりもさらにややこしい。 kuku: for(var i = 1; i < 10; i++) { for (var j = 1; j < 10; j++) { var k = i * j; if (k > 30) break kuku; document.write(k + ' '); } document.write('<br />'); } break文で、2重forループの外に脱出する例だが、ラベルは先頭にあり、このラベルは外側のforループを装飾しているという解釈となる。 これはややこしく美しくない言語仕様だと感じる。使うことはほとんどないだろう。 ■ html記述で間違えた場合、ブラウザはエラーを返してくれないの?例をこなしていくときに、JavaScriptが動かない場合はあった。特にブラウザはエラーも吐かないし、よくわからなくて、htmlをよく見ると、 <script type="text/jacascript" src="scripts/foo.js"></script> ^^^ とミスタイプしていた。 Chromeのデベロッパーツールでもエラーは吐いてくれないし、気づくのに時間がかかってしまった。エラーを吐いてもらう方法を見つけられていないだけなのかな? ■ Visual Studio Codeの上書きモードJavaScriptのコーディングには、Visual Studio Codeを使用している。コードの自動補完などの機能が多彩。 コードを入力していて、繰り返しで文字を変更したいシチュエーションに出くわした。 console.log(x0); console.log(x1); console.log(x2); console.log(x3); console.log(x4); console.log(x5); console.log(x6); console.log(x7); これを入力する場合、最初の行を入力、コピーペーストで8行作って、上から0を1,2,3,4……と変換していくということをよくしますよね。その際には、上書きモードを使って上書きしていく方が、入力が早くできます。 で、Insertキーを押してみたが、上書きモードに切り替わらない。 え、上書きモードがないの?と、仕方がないのでBSを押しながら全部書き換えた。 ふと、キーバインドされてないだけであるのでは?とぐぐってみると、拡張機能で上書きモードがインストールできるようだ(拡張機能:overtype)。不用意に押してしまう人がいるので、デフォルトではインストールされていないらしい。 無事、上書きモードが使えるようになりました。 ■ 疲れたので本日は終わり改訂新版JAVASCRIPT本格入門という本ですが、非常に丁寧に説明されていて、不明な箇所がほとんど無く、よい本です。私にとっては全く難しくはなかったのですが、プログラミング言語初挑戦の人には難しいかもしれません(といってもK&Rが最初の本という人も多かったと思うので、それに比べれば1/10くらいとっつきやすいと思います)。 コードを打ち込みながら、約30%進みました。 Kindle版もレイアウトがよいので、非常に読みやすいです。 2018-05-04(Fri) [長年日記]■ 引き続きJavaScript二日目。atスターバックス。 Array.map「配列の内容を順に加工」なので、破壊的メソッドかと思ったら、そうではないようだ。 配列を本当に加工するには、 var ary = [1, 2, 3, 4]; ary = ary.map(function(value, index, array) { return value * value; }); としてやればよいみたい。 コールバック関数の第三引数は使えるんだろうか。 var ary = [1, 2, 3, 4]; ary.map(function(value, index, array) { return array[index] = value * value; }); でもOKのようだ。ということはforEachを使っても同じかな。 var ary = [1, 2, 3, 4]; ary.forEach(function(value, index, array) { array[index] = value * value; }); これもOK。 でもなんかスマートじゃないな…… 破壊的な同様のメソッドはないのだろうか。 Array.sortこれは破壊的メソッド。 Array.sort(function(a, b){ return a > b; }); コールバック関数がtrueを返すなら、aが後ろに配置される。 普通そうだっけ? 逆のイメージ(aが前に配置される)が感覚としてあるが、たぶん私の気のせいだろう。 MapES2015からMapオブジェクトが追加された。 ここを参照すると、
やはり、歴史的背景から、オブジェクト、連想配列あたりはややこしいことになっているらしい。 なぜ、ここを疑問に思ったかというと、Mapのサンプルコードを書いているときに、 for-inが動作しない現象につきあたったから。 // mapオブジェクトに値を追加 let m = new Map(); m.set('dog', 'ワンワン'); m.set('cat', 'ニャー'); m.set('mouse', 'チュー'); //キーを順に取得 for (var key in m){ console.log(key + '=' + m[key]); } for-ofなら動作する。またObjectの連想配列なら動作するのだが、上記コードでは、for内部を一度も通らないようだ。これはなぜだろう。 for-inはいろいろ難しいことがありそうなので、まだ近寄るには早すぎると言うことなのだろうか。多くのスクリプト言語では、よく使うのはfor-inなんだけどなぁ。 追記for-ofは、ES2015から使用可能。ということは昔から使えたのはfor-in。ということはfor-inを使うべきなのか。なんかこの辺(連想配列、forによる列挙)は癖が強そうだ。 追記2for-ofは、Objectの連想配列には使えないようだ。is not iterableのエラーが出る。 この辺は非常にややこしそうだ。
とすれば、とりあえずはしのげるか。 追記3教科書でも、オブジェクトリテラル(Objectを使った連想配列をこう呼んでいるようだ)とMapの違いについて言及があるが、ここを読み解くにはプログラム言語初心者にはかなり難しいと思われる。 基本的に、参照型(orポインタ)を理解していないと、この手の理屈の裏面は理解できないということなんだけど、最近の言語を知っているだけでは、ポインタや参照型の本当の理解にはなかなか到達しないと思われるので。コンピュータを本当の意味で勉強するには、今でもC言語の理解(特にポインタ)が必須なのかもしれない。 追記4オブジェクトの連想配列でも、for-ofが使えた。以下のObjectの静的メソッドを使う。 var data = {dog: 'ワンワン', cat: 'ニャー', mouse: 'チュー'}; for (var key of Object.keys(data)){ console.log(key + '=' + data[key]); } data.keys()としてもうまくいかない。 Dateオブジェクト特に難しいところは一つを除いては特になさそう。 その一つとは、Monthを単独で扱う場合は、1差し引いた値で扱わないとならないところ! getMonth()メソッドで得られたNumberは、12月なら11。setMonth(7)なら、8月がセットされる。これは間違いやすそうだ。Date(日)はそんなことはなく、単にNuberと日は同じ値になる。なぜ?としか言えない。 なお、setDate()では、負の値や0もセットできる。ちなみに0をセットすると、前月の最終日を指定することになるようだ。 RegExpオブジェクト言語仕様として正規表現が組み込まれているのはうれしい。 正規表現を知っている人は問題ないが、この本で始めて触れる人は、この本では正規表現には入門できないと思われる(ほとんど解説がないに等しいので)。参照本として傷害されているのは、オライリーの詳説 正規表現 第3版ということで、これまたスパルタンな仕様ですね(笑)。 正規表現のサブマッチ文字列正規表現の中で、()でグルーピングされた部分にマッチした文字列を取得するのは、検索結果として返された配列のインデックス1以上の要素を使う。ただし、String.match()を使う場合でglobalオプション(g)が付いた場合には、結果の配列には、すべてのマッチした文字列が複数入っているため、サブマッチ文字列は取得できなくなる。 RegExp.exec()メソッドの場合は、グローバルオプションが付いていても、一回の検索では一つだけマッチし、サブマッチ文字列にもアクセスできる。複数回の検索結果を参照するには、結果がnullになるまでexec()メソッドを繰り返す。 rubyなどでは、サブマッチ文字列に$1などの表現でアクセスできるのだが、JavaScriptでは、そこまで言語仕様に密に組み込まれたものではない。正規表現ライブラリを使用する感覚ですね。 ただし、正規表現リテラルは存在するので、正規表現の記述は、//で囲むだけでよい。 追記String.replace()メソッドでは、置き換える文字列表現の中で、$1等のサブマッチ文字列表現が使用できる。 ただし、$0(マッチ文字列全体)の表現は使えないので、マッチ文字列全体が必要な場合は、検索正規表現全体を()でグルーピングして、$1をマッチ文字列全体のサブマッチ文字列にしてやる工夫が必要。 これはあまり美しくないなぁ。 なお、String.replace()やspilit()メソッドでは、検索文字列の表現には通常文字列と正規表現とどちらでも使える。これはよい仕様。これはString.match()等でも同様のようだ。 ■ やっと関数教科書38%。1日目の進捗から考えるとGW中に全部読めるかと予想していたのだが、ちょっと無理そう。後半に行くほど難易度も上がっていくだろうし。 なかなか面白いのでこのまま続けられるとよいな。 関数定義function hoge([引数リスト]) { ... } と書く。functionという命令が必要なのは、C言語とは違う。 swiftはfuncを使う。rubyやpythonはdef、pascalはfunction/procedure。 型宣言は必要なし。返り値があるかないかは、本体にreturnがあればあり、なければ返り値はundefinedとなる。 関数リテラルこんな関数宣言もある。 var getTriangle = function(base, height) { return base * height / 2; }; function(...){...}で名前のない関数を定義し、変数getTriangleに代入する。これを匿名関数、無名関数と呼ぶ。 Array.sort()等で使ったコールバック関数も、サンプルはこの形で書いた。もっともこの場合は、定義部分のみで、変数代入はしていないが。 Array.sort(function(a, b){ return a > b; }); アロー関数ネットでJavaScriptのコードを見ていて意味不明な=>を見たことがあったが、これか! 関数定義を以下のようにできる。 //アロー関数による関数定義 let getTriangle4 = (base, height) => { return base * height / 2; } console.log('三角形の面積:' + getTriangle4(5, 2)); //アロー関数で、関数定義が1行の場合は、中括弧を省略できる。 //中括弧省略の場合は、文の返り値がそのまま関数返り値になる。 let getTriangle5 = (base, height) => base * height / 2; console.log('三角形の面積:' + getTriangle5(5, 2)); //アロー関数で、関数の引数が1個の場合は、括弧を省略できる。 let getCircle = radius => Math.PI * radius * radius; console.log('円の面積:' + getCircle(2)); //関数の引数がない場合は、括弧を省略できない。 let show = () => console.log('Hello, world!'); show(); これらは、初見でぱっと見ても何してるか全くわからないだろうな。 こう書く便利さは、まだよくわからない。 関数定義でreturnの直後の改行はNGreturn base * height / 2; と書くと、関数の返値はundefinedとなってしまう。returnの後ろに;が自動的に補われるかららしい。 return base * height / 2; などのように、returnの直後で無ければ改行はOKのようだ。(Chromeで確認)。 function命令を使った関数宣言は、ユニットのどこに置いてもよい通常言語の関数宣言と同様、function命令を使った関数宣言は、実際に関数が使われる後に置かれていても実行できる。 関数リテラルを変数に代入する方法では、使う前に変数宣言ができていないとエラーになる。 ■ 本日も終わり本全体の半分くらいまで終了。 JavaScriptの基本的なところはだいたいわかったが、まだクラス宣言とかは見ていない。 複数ユニットでなる大規模プログラムはどう書くのかとかもよくわからない。これはhtmlファイルでのscriptタグとの複合技になるのかな。 1965|09|
|
//
自己紹介
自己紹介
広告
計るだけダイエット
つっこみリスト
TrackBacks
日記仲間
な/
す/
ひ/
最近の日記
|
◆ j_catfish [いいですね。やってみようと思って頂けて手順までなぞってもらえて、あの記事を書いた甲斐がありました。 自分でも出来そ..]
◆ K2 [記事作者様からコメントをいただけて恐縮です。以前から地図を使っていろいろやりたいと思っていたのですが、忙しさにかまけ..]