Learning to Code

プログラミング勉強記録

【JavaScript】 Array(配列)のメソッドまとめ

今まで学習した範囲でまとめ。

let fruits = ["Banana", "Orange", "Apple", "Mango"];

fruits.toString(); 
// 配列の要素を全て表示
// Banana,Orange,Apple,Mango
// toString()とわざわざメソッドをつけなくても同じ結果が返ってくる

Array.isArray(fruits); 
// 変数が配列であればtrueを返す
// true

fruits.join(" * "); 
// toStringと同じく配列の要素を表示するが区切り文字を指定できる
// Banana * Orange * Apple * Mango

fruits.pop(); 
// 配列の最後の要素を削除する(削除された要素を表示する)
// Mango
// fruits = Banana,Orange,Apple

fruits.push("Grape"); 
// 新たな要素を配列の最後に追加
// fruits[3] = "Grape"でも同じ結果が得られる

fruits; 
// Banana,Orange,Apple,Grape

fruits.shift(); 
// 配列の最初の要素を削除(削除された要素を表示)
// Banana

fruits; 
// Orange,Apple,Grape

fruits.unshift("Peach"); 
// 配列の最初に要素を追加する
// fruits = Peach,Orange,Apple,Grape

fruits[fruits.length] = "Kiwi";
// 配列の最後に要素を追加する
// fruits = Peach,Orange,Apple,Grape,Kiwi

fruits.splice(2, 0, "Lemon", "Strawberry"); 
// 最初のパラメータ(2)で追加する位置を、2番目のパラメータ(0)で削除する要素の数を、
// 3番目以降のパラメータで追加する要素を指定する。
// fruits = Peach,Orange,Lemon,Strawberry,Apple,Grape,Kiwi

fruits.splice(3);
// fruits = Peach,Orange,Lemon
// 配列の中から指定した数の要素のみ残す

fruits.splice(1, 2);
// fruits = Peach,Strawberry,Apple,Grape,Kiwi
// [1]~[2]の要素(この例ではOrangeとLemon)を消す

fruits.splice(1, 2, "Blueberry");
// fruits = Peach,Blueberry,Strawberry,Apple,Grape,Kiwi
// [1]~[2]の要素(この例ではOrangeとLemon)を消し、同じ位置に新要素を追加

let friends = ["Ros", "Chandler", "Joey"];

fruits.concat(friends);
// concat()で指定した変数と配列を連結できる。配列+配列はもちろん、配列+文字列も可能
// Peach,Orange,Lemon,Strawberry,Apple,Grape,Kiwi,Ros,Chandler,Joey;
// concat()は既存の配列を書き換えるのではなく新しい配列を返すので、
// fruitsの中身は変わらない
// fruits = Peach,Orange,Lemon,Strawberry,Apple,Grape,Kiwi

fruits.slice(3);
// slice()は指定したインデックスの位置以前の要素を配列から削除する
// Strawberry,Apple,Grape,Kiwi;
// slice()も既存の配列を書き換えるのではなく新しい配列を返す
// fruits = Peach,Orange,Lemon,Strawberry,Apple,Grape,Kiwi

fruits.slice(1, 4);
// slice(開始位置, 終了位置)で2つ要素を指定できる。この場合は4番目のAppleは
// 含まない。Orange, Lemon, Strawberry

【JavaScript】変数の宣言と上書きについて

・参考にした教材

今回はこちらのサイトの関数について解説されている項を参考にしてます。
JavaScriptについて網羅的に解説されている良サイト。

javascript.info

このページ⇓
Functions

・ローカル変数とグローバル変数

ざっくり言うと関数の外で宣言した変数は「グローバル変数」で、
どこでも参照可能。
関数のカッコ{}の中で宣言した変数は「ローカル変数」で、
関数の中からしか参照できないという理解。

ローカル変数は外から参照できないという例:

function showHello () {
  let hello = "Hello, I'm JavaScript!"; // これがローカル変数
  alert( hello );
}

showHello(); // Hello, I'm JavaScript!

alert( hello ); // 参照できないのでエラー

関数内からグローバル変数の参照は可能:

let userName = 'Taro';

function showMessage() {
  let message = 'Hello, ' + userName;
  alert(message);
}

showMessage(); // Hello, Taroとなる。グローバル変数を参照できている

関数内でグローバル変数と同じ名前の変数を使うと、値の上書きも出来てしまう:

let userName = 'Taro';

function showMessage() {
  userName = 'Kenta';
  let message = 'Hello, ' + userName;
  alert(message);
}

alert(userName); // 関数が使われる前まではTaro

showMessage(); // Hello, Kenta

alert(userName); // 関数によってuserNameが上書きされたため、Kentaになる

ややこしいのが、この時に関数内でletを使っているとグローバル変数の値は上書きされない点。
ローカル変数として宣言した場合、例え同名でも別個の変数として扱われるため、
それが優先して使われる。グローバル変数には何も影響を与えない。 宣言なしで使用すると上記の例のように上書きされてしまう。
そもそも同じ名前の変数を複数宣言するということ自体があまり良くないのだとは思うが・・・

・ローカル変数によるグローバル変数の参照

また、ローカル変数の値に同名のグローバル変数を参照することは出来る。 1つ前の例のように、値も上書きされる。

let userName = 'Taro';

function showMessage() {
  userName = 'Kenta, ' + userName; // Kenta, Taroになる
  let message = 'Hello, ' + userName;// Hello, Kenta, Taro 
  alert(message);
}

alert(userName); // 関数が使われる前まではTaro

showMessage(); // Hello, Kenta, Taro

alert(userName); // 関数によってuserNameが上書きされたため、Kenta, Taroになる

ただし、グローバル変数を参照して関数内でローカル変数を宣言しようとするとエラーになる。

let userName = 'Taro';

function showMessage() {
  let userName = 'Kenta, ' + userName; // Kenta, Taroになる
  let message = 'Hello, ' + userName;// Hello, Kenta, Taro 
  alert(message);
}

alert(userName); // 関数が使われる前まではTaro

showMessage(); // エラー発生 

VM172:2 Uncaught ReferenceError: userName is not defined
    at showMessage (<anonymous>:2:30)
    at <anonymous>:1:1
・関数の引数はグローバル変数を上書きしない

どういうことかと言いますと、

function showMessage(userName, text) {
  userName = '*' + userName + '*';
  alert( userName + ': ' + text );
}

let userName = "Taro";

showMessage(userName, "Hello"); // *Taro*: Hello

alert( userName ); // Taroのまま。*Taro*に上書きはされない。

なぜこういう動きになるか、いまいち納得のいく解説は見つけられなかったが、
今回の場合はグローバル変数と同名なのが引数だからだと考えている。
userName = '*' + userName + '*';の行では、 1つ目のuserNameはあくまで引数で、そこに2つ目のuserName(グローバル変数)をあてはめている。 関数を呼び出した時だけ作られる引数だから、グローバル変数には影響を与えないのではないかと思う。

・教訓

・変数名は慎重に、わかりやすくつける(重複は避ける)
・変数はわざとでない限りは宣言して使う(そのほうが予期せぬエラーが少なくなる)
・引数は宣言しなくてよい

ということになるかと思う。

【JavaScript】 計算と変数の宣言について 基本のルールまとめ

忘れそう&引っかかりそうなことをメモしていく。

演算子の使い方 文字列と文字列、文字列と数字を扱う場合

数字同士は単純に足し算をするが、
文字列同士に+を使うと文字列を連結することができる。

let sample = "my" + "name";
alert(sample); // ⇐myname

仮に文字列と数を+でつないだ場合は、どちらも文字列の扱いをされる。
下の例だと'1'が文字列で2は数値だが、結果は'12'(文字列)として出力される。

alert( '1' + 2 ); // ⇐"12"
alert( 2 + '1' ); // ⇐"21"

しかも!この文字列連結ルールは+にしか通用しない。
ー(マイナス)を使えば文字列を削除してくれるのかというとそうではなくて、
+以外を使うと値(operand、または被演算子というらしいですが)は強制的に数字にされる。
+の時とは逆の動きになるということ。
値が文字列と数値でー(マイナス)した場合、
NaN(Not a Number)という結果が返ってくる。

let foo = "20"
let bar = 40
bar - foo
20 // ⇐fooの値は文字の20だったのに数値の20が結果として返ってきている
foo + bar
"2040" // ⇐+を使った場合は文字列の「2040」
another = "lorem"
"lorem"
foo + another
"20lorem"
foo - another
NaN
・ "=="と"==="の違い

==は値だけを比較する。
===は値と変数の型(数か文字列か、オブジェクトかなど)も含めて比較する。

let strings = "100"
let numbers = 100

strings == numbers
true
strings === numbers
false

typeof strings
"string"
typeof numbers
"number"
・1行1動作 コードはシンプルに保つこと

あと大事な原則として、

1行1動作

というのがある。1行に色々な指示を詰め込むことも出来るが、
後で読み返すのが大変だから、簡単に縦読みできるように1行をシンプルすること。

変数も同じ変数名を何度も再利用するのではなくて、
必要なら新しい変数を宣言したほうがずっといい。
同じ名前を使いまわしていると値が何かわからなくなるので。

・変数の宣言 基本的にはletを使う

変数の宣言にはletを使う。定数はconstで宣言。
varも使えるが、古い文法とのこと。微妙に動作も違うらしい。

・定数の宣言 名前の付け方

定数は初めから決まっており絶対に変化しないものについては変数名を全て大文字で書く。
例えば誕生日とか、地名とかも多分そう?

対して、何らかの処理が終わってから分かるもの(例えば誕生日をもとに計算したユーザーの年齢とか)、
これについては通常通り、camelCaseで書く。

つまり、currentUserBirthdayのように、最初の1語を小文字で書いて、
後の語は最初の1文字を大文字にする。
attackFromMarsとか、theLordOfTheRingsとか、そういう感じ。

HTMLとCSSで隠し要素を作る

ブログを書くと思ったより時間がかかって大変だけど、忘れないようにメモ。

・HTML要素をCSSで出したり隠したりするには

まず参考にしたのはこちらの記事。ツイッター等を見るとグラフィック作品等も発表されているようなので、 デザイナーの方なのでしょうかね。色々洗練されててひれ伏したいくらい良く出来ています。 内容も充実。大変勉強になります(速攻ブックマーク)!

saruwakakun.com

長いけどコードがあったほうが分かりやすいと思うので載せておく。 このアンドロイドのお腹のあたりにカーソルを載せるとボタンが出るようにしてある。 その部分の実装は以下の通り。

<div class="secret">
        <input type="checkbox">
        <div class="message">Don't push the button!</div>
    </div>
.secret {
    top: 120px;
    left: 100px;
    width: 20px;
    height: 20px;
    background: yellow;
    border-radius: 25px;
    position: absolute;
    opacity: 0;
    box-shadow: 2px 2px 2px grey;
}

.secret:hover {
    opacity: 1;
}

.secret input {
    opacity: 0;
}

.message {
    opacity: 0;
    border-radius: 20px;
    background: lightgray;
    padding: 5px 0 0 35px;
    width: 200px;
    height: 80px;
    top: -200px;
    left: 200px;
    position: absolute;   
    font-family: Arial;
    font-weight: bold;
    font-size: 30px;
}

.secret input:checked ~ .message {
    opacity: 1;
}

どうやって非表示→表示を切り替えるのか?手順は2つだけ。

1. 隠したい要素を非表示にする

まずは<div class="secret"><div class="message">の両方を opacity: 0;にして非表示にする。 (opacityは透明度を変えるプロパティ)

2. カーソルを合わせると表示されるようにする

.secret:hoverに対してopacityを1にしておけば、カーソルが乗っている時は表示されるようになる。

これだけで非表示→表示の切り替えは出来たことになる。

・隠し要素をクリックして表示を変化させるには

隠し要素の「表示」だけでなく、それをさらにクリックすると何かが起こるように設定する。

今回のアンドロイドでいうと、黄色いボタン(隠し要素)をクリックするとテキストが表示されるようになっている。

さっきのopacityの設定に加えて、以下を追加する。

1. <input type="checkbox">

隠し要素にチェックボックスを仕込んでおく。 ただしこれは見えてしまうとダサいので、opacityをゼロにして非表示にする。 もちろん、カーソルを合わせても表示されないようにしておく。 見えてもいいデザインの場合はそのままでOK。

2. .secret input:checked ~ .message

ここが今回のキモになるテクニック! CSS~セレクタを使うと、~以後の要素に対してCSSを指定できる。

ただし、有効なのは~の前にある要素と同じ階層の要素のみ。

今回の場合でいうと、.secretinputがチェックされた場合、 .messageが表示されるように設定してある。

input.messageは同じdivにネストしている同階層の要素なので問題なし。

特に意味のない実装だけど、ちょっとした工夫が出来たので良しとする。

HTMLとCSSだけでアンドロイドのロゴを描く

・HTMLとCSSで絵を描く

イラレとかを使うとすぐ出来るというツッコミは置いておいて、HTMLとCSSのいい練習になるので、 描いてみた。 参考にしたのはこちらの動画。実際の製作者が入力した通りにコードが表示されるので、 打ち間違いとか入力の順番も含めて見られる。HTMLを全部書いてからCSSというふうに分かれてなくて、 ちょっとHTMLを書いたらCSSをつけて、またHTMLを足して、というふうに行ったり来たりして作るものなんですね。 人によるんだとは思うが。

CSS3 Android Logo

・気になったテクニック1 margin: 0 auto;

CSSでこう指定すると要素がセンタライズされるのだが、このautoって何か分からなくないですか? 上下のマージンが0で、左右がautoということなんだろうけど・・・ 試しにマージン0でやるとブラウザの一番左上に寄せて表示される。まあこれは分かる。 でもなぜautoをつけただけで中央に寄るのか?

そこで調べたところ、どうやらautoを指定すると自動でマージンを調節してくれるようです。 ただし、marginとautoを使って中央寄せにするにはwidthがないといけない。 margin: 0 auto;を設定した場合、左右両方に均等にmarginが割り振られる。 margin-leftを設定すると右寄せ(左側にマージン)になり、margin-rightを設定すると左寄せ(右側にマージン)となる。 なので、widthが500pxで、ブラウザ幅が1,000pxだった場合、margin-left: auto;と設定すると、 左側に500pxのマージンが入るということ。

じゃあheightを設定してmargin-topを設定したら同じように動くのかな?と思ったらそれは動かない。 margin-topにautoじゃなくて数値を指定するとしっかり上側にマージンが入るのだが・・・ 上下と左右でautoの仕様が違うのかもしれない。

参考にさせて頂いたのはこの記事。ちょっと古いようですが、marginの部分の話は今も一緒かと思います。

kojika17.com

・気になったテクニック2 div div

下のように全てのdivに対してCSSを指定するのは分かるが、div divと二重になっている例に遭遇した。

div {
  background: black;
}

何で2回書く?と思ったが、divにネストしているdivのみに適用させるためのようだ。 なので、例えばこう書くと全てのpタグにboldが適用されるが、

p {
  font-weight: bold;
}

こう書けばdivにネストしているpタグにだけプロパティを適用できる。

div p {
  font-weight: bold;
}
・気になったテクニック3 transform

選択した要素を動かすことができるプロパティ。 今回は:hoverと組み合わせて、カーソルを持っていくと動くという形にした。 rotateは回転の動きを加える。カッコ内の数値で角度を指定する。プラスの数字の場合は時計回り、 マイナスの場合は半時計回りで動く。

translateは上下左右に移動させることが出来る。カッコ内の数値は基本的に1つあるいは2つ指定できる。 (3Dに動かすことも出来るらしいが今回は見ていない) 最初の数値で左右の動き、2つ目の数値で上下の動きを加える。 下のコード(transform: rotate(7deg) translate(5px, -15px);)では右に5px、上に15px動かしている。

scaleは要素の大きさを変える。カッコ内の数値で倍率を指定。translateと同じく、 最初の数値で左右のサイズ、2つ目の数値で上下のサイズを指定する。下のコードでは縦横の比を保ったまま 1.5倍にしている。

.head:hover {
    transform: rotate(7deg) translate(5px, -15px);
}

.l_eye:hover, .r_eye:hover {
    transform: scale(1.5, 1.5)
}

.l_arm:hover {
    transform: rotate(30deg) translate(-35px, 0px);
}

あと最後にもう1テクニックあるのだが、それは長くなるので次の記事にする。 完成したアンドロイドくんはSinatraに組み込んでherokuにデプロイしたので、 よかったら触ってみてください。

Android logo

※一応スマホでも動くようにしてますが、なんかカクカクしてる・・・

f:id:yzume:20180118195227j:plain

基本のGitコマンド

・Gitとは

Gitはバージョン管理システムVCS)の一種。

管理対象にしたファイルについては、元ファイルからの変更点をGitが全て記録し、バージョンごとに保存しておいてくれる。

こう言うとなんだかイメージがわかないが、要はゲームのセーブポイントみたいなもの。 例えばレベル1でセーブして、レベル20まであげて再度セーブする場合、 Gitはレベル1のデータも、レベル20時点でのデータも両方とっておいてくれる。

しかも、他のプレイヤーのセーブデータと合体させて1つのデータを作ることが出来る。 攻略が早くなるし、苦手なダンジョンを他の人にクリアしてもらえるというような利点もある。 ※これらの機能はこの本記事では扱わない。

・Gitの仕組み

仕組みが少しややこしい。Gitには次の3つの階層がある。

①作業ディレクトリ/ ファイルの編集をする

②ステージングエリア/ コミットの前段階

③レポジトリ/ コミットされた変更済みのファイルが保存される

セーブデータを作ることを、「コミット」という。 Gitがインストールされており登録を済ませていれば、ターミナル上でコマンドを入力してコミットができる。 ただし、ディレクトリごとにレポジトリが作られていないといけないし、 保存したいファイルがステージングエリアに追加されていなければいけない。

・Gitのコマンド 基礎編
  • git init

Gitのレポジトリを新しく作る

  • git status 

作業ディレクトリとステージングエリアの状態を確認する (ステージングエリアに追加されていないファイルがあればここで表示される)

  • git add(ファイル名)

作業ディレクトリからステージングエリアにファイルを追加する

  • git diff 

作業ディレクトリとステージングエリアの違いを確認する(どんな変更がされたか)

  • git commit 

ファイルの変更をステージングエリアからレポジトリに保存する(この状態で初めてセーブされる)

実際にコミットする際は-mをつけてコミットメッセージをつける。

git commit -m "Add foo to bar"という感じ。他にもオプション多数

  • git log

過去のコミットのログを見る

・Gitのコマンド リセット編
  • git checkout HEAD (ファイル名)

ファイルが"names.txt"だったら"git checkout HEAD names.txt"とコマンドを入力する。 作業ディレクトリでファイルを編集中に、まだ変更がステージングエリアに追加されていなければ、 このコマンドで前回のコミット時点のファイルに戻すことが出来る。

  • git reset HEAD (ファイル名)

git add済でファイルがステージングエリアに追加されていても、このコマンドで 取り消しできる。変更点は元には戻らないが、とりあえずステージングエリアから外してしまえば間違ってコミットしてしまうことはない。

  • git reset commit (コミット識別番号の最初の7文字)

コミットをするとこんなメッセージが出る。

commit d640dc3b22b3ee1d0a6e87477a35fd5e75c0712e

Author: learningtocode

Date: Thu Nov 7 16:19:17 2017 -0500

Add foo to bar.rb

1行目の番号がコミット識別番号。最初の7桁はこの場合だと「d640dc3」。 例えば5回コミットをしていて、2回目のコミット時点まで戻りたいとなった場合、 2回目のコミット識別番号を使ってこのコマンドを入力すれば戻れる。 その場合、3・4・5回目のコミットは削除されるので注意。

以下のサイトも分かりやすく大変勉強になる。というか圧倒的にきちんと解説されています。

backlog.com

Sinatraで数字当てゲームを作った

Railsチュートリアルを終えて

前のブログに書いたかもしれないが、ついこの間まではRuby on Railsチュートリアルをやっていた。

先日最後まで終えることができ、ツイッターのクローンサイトも一応完成はした。

一応・・・というのは、結局自分で考えて作ったものとは言えないから。 最後の章あたりはレベルが高すぎて正直何を言っているのか、 なんとなくでしか分からなかった。

機能拡張もしたかったが、明らかにレベルに合っていないので、一旦これで終了。 (この教材で学んだこと、疑問点などはそのうち別記事にしたい)

とはいえサーバーサイドの言語はRuby中心に勉強していこうとは思っているし、 何らかのアプリを作るならフレームワーク自体は使っていきたい。 当然Railsでもいいわけだが、ネットで検索していると 「初心者にはおすすめしない」という記事もある。

blog.sumyapp.com

記事そのものもコメント欄での応酬も読ませて頂いた。

ガチ初心者としては、 「で結局どうしたら?」という感じではあるが、一通りRailsの機能を見た感じ、 やはり高機能すぎるというのは言えていると思う。 そのせいでめちゃくちゃ覚えることが多い。

もう少し、自分の把握できる範囲で使えるほうがレベルアップはしやすいのではないか。 例えるなら、今のRailsは攻撃力がめっちゃ高いが重量が重すぎて装備できないバトルアックスのようなもの。

それを無理やり使うよりは、攻撃力は劣るものの、 自分の力で振り回せる短剣を使ったほうが戦える。

というわけで、やや軽量級のSinatraを使ってみることにした。

Sinatraを使ってみる

参考にした教材はこちら。 Webguesserというゲームを作る課題です。

tutorials.jumpstartlab.com

必要なファイル等々を作ってから本編へ。

①1〜100までの間でランダムに数を生成

②ブラウザのフォームからユーザーが数字を入力

③ランダム生成の数とユーザーの入れた数字を比較し、メッセージを表示

大筋はこういうゲーム(最後の拡張はまだやってない)。

恥ずかしい話、これだけでも相当苦戦した・・・

・ルーティングハンドラが読めなかった

おなじみのHello Worldをブラウザに表示させるブロック。

まずこれの意味すら分からなかった(Railsにはget '/'なんてなかった!)。

require 'sinatra'
get '/' do
  'Hello world!'
end

getの部分がHTTPリクエストになっていて、例えばpostにも出来る。

'/'の部分はURLになっていて、この場合はルートURL。 「GETリクエストでルートURLにアクセスした時」という意味。

・変数のスコープが分からなかった

これはそもそもRubyの基礎がおろそかなのでは?という話だが、変数を定義してエラーが連発した。

get '/' do
  guess = params['guess'].to_i
  message = check_guess(guess)
  erb :index, :locals => { :random_number => rand_number,
                                :message => message }
end

rand_number = rand(101)

def check_guess(guess)
  if guess > rand_number
    "foobar"
  else "error"
  end
end

これでif guess > rand_numberがエラーになるとか。ローカル変数だからアクセスできないのか? と思って全部ルーティングのブロックに入れてもnilでエラー。

ネットで検索して何となく@をつけてインスタンス変数にしてみたりもしたが、変わらず。 何で使えないんだと思ったらこの記事にたどり着いた。

qiita.com

インスタンス変数は初期化しないといけないし、インスタンスメソッドでしかアクセスできない。 だから単純に@をつけただけではnilになってエラーになる。

何となくの知識しかなかったために、@をつければどこからでも使える変数になるのかと思っていた。 結局、この場は$rand_numberという形でグローバル変数を使うことで解決した。

初歩知識の一つだと思うが、全然知らなかった。基礎のなさを痛感。 他にも、paramsの取得方法や利用方法もまだまだわかっていない。

ブラウザにGETでアクセスしてページを表示するなら、 ブラウザ「から」情報を送信するにはPOSTを使うのかな? と思った。実際そういうふうにも出来るようだが、 今回はpostを使わずに済んでいる。

例えばデータベースに入力された情報を保存するとか、 その情報を他のページに表示させるとかいう場合は postなのだろうか。これは頭にとめておいて、今後はっきりさせていく。