Quantcast
Channel: 初心者タグが付けられた新着記事 - Qiita
Viewing all 21239 articles
Browse latest View live

2019年新卒から2020年新卒へ、IT企業の新人研修でこれが重要!

$
0
0

次の新卒のより良いスタートダッシュの為に

さて、この記事は2020年の新卒の方に向けて、2019年新卒の失敗や経験の一例を知ってもらって、
より良いスタートダッシュを4月にきってもらえると嬉しいな、という気持ちで書きました。
私が入社した会社は社員100人弱のベンチャーですので、同じくITベンチャーに務めることが決まっている方ですと、よりお役に立てると思います。

私は2019年の新卒です

まず、少し自己紹介させて下さい。
私は2019年の4月に新卒としてITベンチャーに入社して、
現在その会社で主にスマホアプリのフロント開発に従事しております。
他にも大学が電子工学科だったことも手伝って、Raspberry Piを使ったIoTっぽいことも会社でしてます。
会社での使用言語は主に、Swift、Kotlin、Java、Javascript、GAS、Pythonです。

一番最初のチャンス?新人研修は終わってからが大事!

さて、入社したみなさんを必ず待ち受けている最初の関門は研修だと思います。
新人研修の内容はもちろん会社によって様々だと思いますが、私の会社では外部研修でした。
新宿にある某有名ITスクールに通ってバックエンド、フロントエンド、ディレクション、ビジネスマナーまで、広く浅く学ぶものでした。
正直言ってどこの会社でもこれの内容はそんなに変わらないと思います。

ある程度プログラムをやったことがある人なら「参考書買って、実際チュートリアル作った方がまし」って思う人もいると思います。僕の同期も受講中にはこの意見がとても多かったです。
ですが、研修は終わってからが重要なのです!

会社は必ず研修が新卒にとって有益なものだったのか意見を聞いて、その意見を参考に次年度の研修内容を練り直します。
研修が終わった後、先輩社員の方に「研修の内容はどうだった?どこが良かった&悪かった?何か付け足して貰いたものは?」など参考意見を求められます。
ここで、「研修は授業みたいでした、大体ネットで調べたら書いてありました。」とか新卒が言ったらどうでしょう。
先輩はこう思います。「え?いつでも質問できる環境があったのに、基礎が出来た上で応用に挑戦しなかったのか、この子は自発的に動くタイプじゃないのかな」と…。
これが結構マイナスイメージなのはITベンチャーに就職しようと思った方なら分かってもらえると思います。
ITベンチャーの就職面接でお馴染みの「自発的&能動的な行動」にマイナス点を付けられてしまうのです。
こうならない為に!
新鮮な実体験を持った私が新人研修を1年目のスムーズな業務に繋げる重要な点を3つ上げます!

1.研修の悪い点をメモっておく

もちろん受講の良くないところを無理やり良かったと言う必要はありません。
悪いものは悪いと言いましょう!
ですが、どこが良くなかったのか、出来ればどうすれば良くなるかまでを研修終わりに言えるようになっておきましょう。

2.研修で興味を持った分野で+α

大手の会社さんなどは別ですがITベンチャーでは、みなさんがどの役職につくかは結構印象勝負なところがあります。
先輩社員に「この新卒にはこの分野の仕事に振ろう」と思ってもらえるように興味をもった分野をしっかりアピールしましょう!
例で言うと、研修でRubyを習って、興味が湧いたので、HerokuにWebアプリをデプロイしてみました。
などを先輩に伝えるなどです。

3.同期と仲良く!

これもかなり重要です!
一緒に研修を受ける会社の同期と仲良くしておきましょう。
会社に入ると、学生の時は必要なかった業務以外の仕事があります。
税金の申請、勤怠、社内の健康診断などの書類提出、物品購入の申請…
他にも上げ出したらきりがありません。
これらを全部間違いなく最初からこなすのは、はっきり言って無理です。
失敗して当然、先輩に教えてもらって当然です。
ですが、新卒に何度も同じ質問をされると先輩はどう思うでしょう…。
そのうち、「新卒の〜君に共有したから彼から聞いて」というように同期間の情報共有を求められます。
この時です!
同期に話せる相手がいなかったらどうなってしまうでしょう…。
考えただけでも恐ろしいですね。
出来るだけ研修中に同期たちと仲良くなって気軽に質問や情報共有ができる関係になっておきましょう。

終わりに

新卒の皆様、就職おめでとうございます!
新卒って期待と不安とでいっぱいですよね。
皆さんも面接などで言われたことかもしれませんが、就職が決まってから入社するまでの時間は思いっきり遊んでやりたいことやって下さい!
この時期にこんな記事を読んでるあなたはもしかしたら肩に力が入り過ぎかもしれませんね笑
一意見でしかないので気休めですが、私は今の会社に入って実は学生の時よりのびのび生活してる実感があります。
もちろん時間の制約は増えましたし、考えることも増えました。
ですが、より多くの学んでいる実感、役に立つプログラムを書いている実感があります。
2020年の新卒でIT企業に就職した方が一人でも多く、より良い1年目を過ごせることを切に願っております。


たのしい1次元セル・オートマトンの世界

$
0
0

はじめに

Happy hacking!
初投稿記事です。

突然ですが、こんな図形を描画するプログラム、カワイイと思いませんか?

rule90.gif

カワイイですよね、ありがとうございます。
今回は皆様に摩訶不思議なセル・オートマトンの世界をご紹介したいと思います。

それでは、いってみましょ~!🐕

セル・オートマトンとは

セル・オートマトン(英: cellular automaton、略称:CA)とは、格子状のセルと単純な規則による、離散的計算モデルである。

Wikipediaより引用

なるほど、わからん

まず、無限に広がる方眼紙を想定します。Excelでもいいです。無限……?
その方眼紙におけるマス目がセルにあたります。
各セルは2つの状態(0, 1)のうちいずれかに決定されます。
各セルは単純なルールに従って、離散的な――つまり分断された非連続的な時間経過とともに変化していきます。
その変化の様を観察していくと、冒頭のような幾何学模様を描き出す 単純なルールが存在することに気が付きます。
気が付いたんです、昔のすごいヒトが。
すごいですよね。

今回は 1次元のセル・オートマトンにフォーカスしていきます。
高次のセル・オートマトンについてはまたの機会に!

1次元セル・オートマトンにおけるルール

さて、先程から話しているこの魔法のような単純なルールって一体何なんでしょうね。
まず、用語として 近傍 (neighbourhood, neighborhood)という言葉が出てきます。
ここでは、隣接するセル群のことだと理解してください。

1次元というくらいですから、セルは線状に並んでいます。こんな感じに。

(0)10101(0)

🐕 < 有限の計算をする際、両端には常に0の状態を持つセルを想定するワン🐾

両端の亜空間を除いた5マスの方眼紙に、0の状態を持つセルが2つと、1の状態を持つセルが3つ並んでいます。
例えば、真ん中の1の状態を持つセルを中心に考えると、近傍は両隣の0の状態を持つセルです。
全てのセルについてそれぞれの近傍を見ていくと、次のようになります。

(0)10
101
010
101
01(0)

5マスの方眼紙なので、中心とその近傍のグループは当然5つ存在します。
このグループの状態をもとに、次の世代におけるセルの状態を決定していきます。
具体的なルールを例に、その状態変化の過程を見てみましょう。

ルール90

フラクタル図形のひとつであるシェルピンスキーのギャスケットと呼ばれる図形を生成する、ルール90を例にして1次元セル・オートマトンにおけるルールを理解してみます。

現在の状態次世代における中央セルの状態
0 | 0 | 0| 0 |
0 | 0 | 1| 1 |
0 | 1 | 0| 0 |
0 | 1 | 1| 1 |
1 | 0 | 0| 1 |
1 | 0 | 1| 0 |
1 | 1 | 0| 1 |
1 | 1 | 1| 0 |

これは、中心とその近傍の状態をもとに、その中心セルが次世代においてどのような状態に決定されるかを表したものです。

次のようなセルの初期状態を想定します。
(記載していませんが、両端は0です。)

000010000

先程の状態遷移表に従って次世代のセルの状態を表してみると、こんな感じになります。

000101000

さらに次の世代を見てみましょう。

001000100

このような変化を無限に繰り返すわけです。
この変化を下方向に積み上げるかたちで描画すると、こんな興味深い図形が生成されるんですね~!

rule90.gif

はい、記事冒頭の図形はルール90によって生成されたものでした。

ルールの命名

ところで、ルール90における 90って何なんでしょう。
先程の、ルール90についての状態遷移表における 次世代における中央セルの状態を下から順に並べてみます。

01011010

これを2進数として捉え、10進数に変換したものをルールの名称として使っているのです!

01011010(2) = 90(10)

つまり、逆算するとルールの番号から状態遷移表が導き出せます。
ルール30の状態遷移表をつくってみましょう。

30(10) = 00011110(2)

現在の状態次世代における中央セルの状態
0 | 0 | 0| 0 |
0 | 0 | 1| 1 |
0 | 1 | 0| 1 |
0 | 1 | 1| 1 |
1 | 0 | 0| 1 |
1 | 0 | 1| 0 |
1 | 1 | 0| 0 |
1 | 1 | 1| 0 |

次のような初期状態を与えて、3世代分の変化を見てみます。

000010000
000111000
001100100

ルール30は次のような図形を生成します。
これまたカワイイ……。

rule30.gif

ルールの種類

前述したように、各セルは2つの状態(0, 1)のうちいずれかに決定されます。
先程の状態遷移表を見ても分かるように、1次元セル・オートマトンにおける中心と近傍は3つのセルによって構成されるので、8つのパターン(23 = 8)をとります。
中心と近傍によって決定される 次世代における中央セルの状態もまた2つの状態をとるので、ルールは全部で 256種類 (28 = 256)存在することが分かります。

ルールに与えられた0から255までの番号を ウルフラム・コードと呼びます。
これは、イギリスの理論物理学者スティーブン・ウルフラムが考案したことに由来します。

C#で実装してみる

すきな言語でつくってみよう!

🐕 < イヌはC#がすき!

以下は抜粋したソースです。
ソースのフルバージョンはイヌの GitHubにありますので、是非遊んでみてください!

入力したウルフラム・コードからルールを生成する

/// <summary>/// ルールを取得する/// </summary>/// <param name="ruleDec">ウルフラム・コード</param>/// <returns>ルール</returns>privatestaticstring[,]GetRule(intruleDec){// ウルフラム・コードを2進数に変換し8桁0埋めvarruleBinArray=int.Parse(Convert.ToString(ruleDec,2)).ToString("D8").ToCharArray();// 近傍の状態を表す10進数varn=7;varrule=newstring[8,2];varcount=0;// ルールを生成foreach(varbininruleBinArray){rule[count,0]=int.Parse(Convert.ToString(n,2)).ToString("D3");rule[count,1]=bin.ToString();count++;n--;}returnrule;}

第1世代のセル・オートマトンを生成し初期状態を与える

// 第1世代のセル・オートマトンを生成し初期状態を与えるvarfirstGene="0".PadLeft(automatonSize+2,'0').ToCharArray();firstGene[firstGene.Count()/2]='1';

セルの状態に応じて描画する

for(vart=0;t<stepCount;t++){foreach(varcellincurrentGene.ToCharArray()){// セルの状態に応じて描画varview=cell=='0'?" ":"*";Console.Write(view);}Console.Write("\r\n");

ルールに従って次世代のセル・オートマトンを生成する

/// <summary>/// 次世代のセル・オートマトンを取得する/// </summary>/// <param name="rule">ルール</param>/// <param name="currentGene">現世代のセル・オートマトン</param>/// <returns>次世代のセル・オートマトン</returns>privatestaticstringGetNextGene(string[,]rule,stringcurrentGene){// 左端は常に0varnextGene="0";// ルールに従って次世代のセル・オートマトンを生成for(vari=1;i<automatonSize+1;i++){for(varj=0;j<rule.GetLength(0);j++){if(rule[j,0]==currentGene.Substring(i-1,1)+currentGene.Substring(i,1)+currentGene.Substring(i+1,1)){nextGene+=rule[j,1];break;}}}// 右端は常に0returnnextGene+"0";}

カワイイけど、これって何に使うの?

セル・オートマトンは様々な研究に用いられています。
今回のテーマである1次元セル・オートマトンにおける最も有名であろう利用方法として、一車線の高速道路における交通流シミュレーションが挙げられます。
ルール184がこのシミュレーションをするためのモデルとして利用できます。

実際に適当な初期状態を与えてルール184を動かしてみると、交通渋滞の様子を再現できます。
この素晴らしいインターネッツで検索してみるとたくさんの論文を読むことができるので、興味のある方は是非!

自然界におけるセル・オートマトン

イモガイの一種であるタガヤサンミナシという貝は、ルール30が生成する模様によく似た貝殻を持つことで知られています。

何故キミはその模様を選んだのだ……?
何に対して都合が良かったのだ……?

おわりに

生命という現象の謎を解き明かすために考案され、発展してきたセル・オートマトン。
この深淵の先に見えるものとは?
たとえそれが、呪いだったとしても……。

C++の自作クラスを持つvectorがresizeできない時は

$
0
0

はじめに

C++を書いていてふとしたミスで悩んでしまったので、原因と解決策を記します。

状況

自作クラスdim_3を持つvector<dim_3>resize()しようとするが、コンパイルエラーが起こる。ソースコードは以下。

main.cpp
#include <iostream>
#include <vector>
usingnamespacestd;classdim_3{private:intx_;inty_;intz_;public:dim_3(intx,inty,intz):x_{x},y_{y},z_{z}{}inlinevoidsetX(intin){x_=in;}inlinevoidsetY(intin){y_=in;}inlinevoidsetZ(intin){z_=in;}inlineintgetX()const{returnx_;}inlineintgetY()const{returny_;}inlineintgetZ()const{returnz_;}};intmain(){vector<dim_3>vc;vc.resize(10);cout<<vc[4].getX()<<" "<<vc[4].getY()<<" "<<vc[4].getZ()<<endl;return0;}
error
error: no matching constructor for initialization of 'dim_3'

dim_3を初期化するコンストラクタがないらしい。

cplusplusの該当ページには、

val
Object whose content is copied to the added elements in case that n is greater than the current container size.
If not specified, the default constructor is used instead.
Member type value_type is the type of the elements in the container, defined in vector as an alias of the first template parameter (T).

と記述されており、std::vector::resizeでは値の指定がない時はデフォルトコンストラクターを用いるとのこと。

原因

デフォルトコンストラクターを忘れていた。

解決方法1

デフォルトコンストラクターを作る。
冗長になるが、書き直したソースコードが以下。

main.cpp
#include <iostream>
#include <vector>
usingnamespacestd;classdim_3{private:intx_;inty_;intz_;public:dim_3():x_{0},y_{0},z_{0}{}dim_3(intx,inty,intz):x_{x},y_{y},z_{z}{}inlinevoidsetX(intin){x_=in;}inlinevoidsetY(intin){y_=in;}inlinevoidsetZ(intin){z_=in;}inlineintgetX()const{returnx_;}inlineintgetY()const{returny_;}inlineintgetZ()const{returnz_;}};intmain(){vector<dim_3>vc;vc.resize(10);cout<<vc[4].getX()<<" "<<vc[4].getY()<<" "<<vc[4].getZ()<<endl;return0;}

実行結果が以下。

output
0 0 0

解決方法2

初期化方法を指定する。
これは使いやすくないが、試したら動いたので一応記す。これを用いるとしてもデフォルトコンストラクターは作るべきである。ソースコードは以下。

main.cpp
#include <iostream>
#include <vector>
usingnamespacestd;classdim_3{private:intx_;inty_;intz_;public:dim_3(intx,inty,intz):x_{x},y_{y},z_{z}{}inlinevoidsetX(intin){x_=in;}inlinevoidsetY(intin){y_=in;}inlinevoidsetZ(intin){z_=in;}inlineintgetX()const{returnx_;}inlineintgetY()const{returny_;}inlineintgetZ()const{returnz_;}};intmain(){vector<dim_3>vc;vc.resize(10,dim_3(8,9,0));cout<<vc[4].getX()<<" "<<vc[4].getY()<<" "<<vc[4].getZ()<<endl;return0;}

実行結果が以下。

output
8 9 0

おわりに

今後は、デフォルトコンストラクターを忘れないよう注意します。

例題から理解するベイズ統計

$
0
0

趣旨

ベイズ統計学にちょっと興味の湧いた僕氏、なかなか理解できず半年ほど放置。

春休みに入って少し勉強したので、アウトプットがてら書いてみたところ、僕的に一番しっくり来る例を思いついたのでメモ書き程度に書いておきます。

n番煎じ

あ、死ぬほど基礎的な内容です。
高度な内容を期待して開いた方、ごめんなさい。

問題

2つのサイコロを用意した。
サイコロはA、Bのいずれかであるが、A、Bは外観や重量では区別できない。

ただし、A、Bのいずれも出目の偏りがある。
それぞれのサイコロの各目が出る確率は以下の通りであることが分かっている。

出目AB
10.30.1
20.250.1
30.20.1
40.150.2
50.050.25
60.050.25

今、2つのサイコロから1つを手に取った。
このサイコロがAなのかBなのか知りたい。

問0

手に取ったサイコロがAである確率を求めよ。

問1

今、手に取ったサイコロを1回振ったとき、その出目が1であった。
この時、手に取ったサイコロがAである確率を求めよ。

問2

「問0の確率」と「問1の確率」を比較して、手に取ったサイコロがAである確率は、サイコロを振ることにより何倍になったか計算せよ。

問3

問1からさらにもう一度振ると、その出目が3であった。
この時、手に取ったサイコロがAである確率を求めよ。

解説

我流・ベイズ統計 超絶概論

極端な言い方ですが、ベイズ統計のやろうとしていることは、条件付確率を逆にする試みといえます。この記事ではベイズの公式を深掘りすることはあえてしないですが、「一瞬だけ」ベイズの定理を見ると分かりやすいと思います。

P(A|B) = \frac{P(B|A) \times P(A)}{P(B)}

さて、本説例では、サイコロが所与であるときの各目が出る確率を前提として示して、その上でサイコロの出目からサイコロの種類を推論しようとしています。これを事象X、事象Yを定義してもう少し数学的に書き換えてみましょう。

事象X: 選択したサイコロがAである確率
事象Y: サイコロを振ると1の目が出る確率

ここで、最初の表でいう「Aのサイコロを1回振って1が出る確率」は、$P(Y|X)$と書けます。この条件付確率は、「Aのサイコロを選んだから、1の目は0.3で出る」という因果関係に基づいたものといえます。このようなP(結果|原因)の形をした条件付確率は、サイコロが何らかの形でA, Bを区別できる場合は有効でしょう。ここではP(結果|原因)型と名付けます。ベイズ統計学上の、いわゆる尤度でもあります。

一方、問題で求めようとしている確率は、「ある出目のときに、それがAである確率」であり、$P(X|Y)$と書くことができます。この条件付確率は、出目からサイコロを推論する、つまり結果から原因を探るものなので、P(原因|結果)型と名付けましょう。ベイズ統計学のちゃんとした用語で、事後確率ともいいます。

$P(Y|X)$ から $P(X|Y)$ を推論する

ところで、サイコロを区別できないとすれば、このP(結果|原因)型の条件付確率の価値は低まってしまいます。説例(表)でいう条件付確率は、「サイコロは分かっている。その上で出目の確率はこうだ」ということを暗に前提としています。つまり、条件付確率というのは、ある条件が所与ということが前提ですから、その前提が崩れている今、条件付確率を適切に適用できない可能性が高いです。
今回はサイコロが2つだけなので$\frac{1}{2}$で当てはまるでしょうが、サイコロを10個に増やしたとすると、サイコロを区別できていないときに、この条件付確率をそのままの形で積極的に利用することは難しいでしょう。「ベイズ統計学の考え方を使わないうちは」、せめて、全体の出目の確率の期待値を計算することぐらいしかできません。

このようなことが起きるのは、「サイコロを区別できないから」です。「その原因を直接観察することが不可能だから」と言い換えることもできるでしょう。
ベイズ統計では「検査で陽性(結果)の人が実際に陽性だった(原因)確率」「URLの記載のあるメール(結果)が迷惑メールである(原因)確率」などが例として挙げられることが多いですが、もし「その人が実際に陽性である」ということが分かるのであれば検査など不要だし、もし「そのメールが迷惑メールである」というのが第三者(メールサービスの運営者)が間違いなく判断できるのであれば、時々重要なメールが迷惑メールに分類される事象が起きるはずがありません。私たちが「神の眼」を持っているのであれば、病院の検査などもはや不要のはずです。

さて、原因は直接観察不能ですが、代わりに入手できるのは、サイコロを振って分かる経験的な出目の偏りに関する情報です。究極的には、無限回の試行を繰り返せば、最終的には表に示した確率のどちらかに収束するわけですから、それで判断することもできるでしょう。
いずれにしても、とりあえず分からないからまずサイコロを振って、そのサイコロがAなのかBなのかを推論してみよう、ということですね。これが「P(原因|結果)型」、つまりベイズ統計のやろうとしていることです。

原因がブラックボックスであれ、結果(出目、検査結果、迷惑メールの文面)は一般的には観察可能です。そして観察から得られた結果を、P(原因|結果)の条件付確率の前提として利用し、(乱暴な言い方をすれば)母集団を徐々に狭めていくことで原因を推論していく作業が、ベイズのやろうとしていることでしょう。

ここで、原因が分からないと利用しづらいと先に書いたP(結果|原因)型の条件付確率を、ベイズ統計学では、今度はこれを推論過程のモデル(仮定)として使うことになるわけです。原因⇒結果という一方通行の因果関係というよりは、どちらかといえば原因⇔結果という対応関係に紐解いていくわけですね。
設例の問題でも、原因(サイコロAか否か)を調べるために、「原因⇒結果の関係(サイコロの種類と出目の関係表)」を上手く変形させてから、観察結果(出目が1である)を当てはめていくわけです。

「P(結果|原因) 型」が神の眼の条件付確率だとすれば、 観察可能な事象から原因を推論する「P(原因|結果) 型」の条件付確率は、とても人間的な条件付確率だと思いませんか。

つまづいていたところと説例の工夫

ここは余談なので、流してもらっていいです。


ずーーーっと理解できなかったのが、この事後確率P(原因|結果)が分かったところで何が分かるのかということでした。つまり、自分の中で、「原因は直接観察可能」「原因は既知」という神の眼を暗に仮定してしまったためにベイズ統計の必要性が理解できず、半年間ベイズから離れてしまったわけです。

そこで、説例では「サイコロを外観等では区別できない」とあえて明記することで、原因(サイコロがAかBか)を推論する必要性を強調しました。

解答

問0

サイコロを投げる前の期待を計算する問題です。
このような、情報獲得前の確率を「事前確率」といいます。
計算自体は、ただただ中学生レベルの確率の問題です。

適当に選んだらAである確率
⇨ 2つの中から一方を無作為に選ぶ確率
⇨ $0.5$

問1

いわゆる「事後確率」を求める問題です。
公式を使えば一瞬ですが、直感的に分かり易いようにするために、あえてベイズの定理を避けて、弁図的な解き方で書きます。

「いずれかのサイコロを振って1が出る確率の期待値」
⇨ A, Bのいずれかのサイコロを選ぶ確率はそれぞれ0.5
⇨ $0.5 \times 0.3 + 0.5 \times 0.1 = 0.2$

「Aを選び、かつ、出目が1である確率」
⇨ 「Aを降ったときに、1が出る確率」に「サイコロからAを選ぶ確率」を掛ければよい
⇨ $0.3 \times 0.5 = 0.15$

「出目が1であるとき、Aである確率」
⇨ 「Aを選び、かつ、出目が1である確率」を「いずれかのサイコロを振って1が出る確率の期待値」で除すればよい
⇨ $0.15 \div 0.2 = 0.75 $

問2

事前確率と事後確率の比較問題です。
「振ったら1が出た」という情報から、予想確率がどの程度変化したかを評価します。

事前確率
⇨「サイコロを振る前の、サイコロを適当に1つ選んだときAである確率」
⇨ $0.5$

事後確率
⇨「サイコロを振って1が出た後の、サイコロを適当に1つ選んだときAである確率」
⇨ $0.75$

よって、$0.75 \div 0.5 = 1.25倍$ になった(25%改善した)。

問3

さらに情報が加わったときにどのように変化するかを見てみる問題です。
問1の計算結果から「逐次合理性」を利用したスマートな解法もありますが、ここも泥臭く弁図っぽく解いてみます。計算の流れは問1と全く同じです。

そのサイコロがAである時、「1回目が1」かつ「2回目が3」である確率
⇨ $0.3 \times 0.2 = 0.06$

そのサイコロがBである時、「1回目が1」かつ「2回目が3」である確率
⇨ $0.1 \times 0.1 = 0.01$

出目が「1回目が1」かつ「2回目が3」であるとき、そのサイコロがAである確率(事後確率)
⇨ $\begin{align} \frac{0.06}{(0.06 + 0.01)} &= \frac{6}{7}\\ &≒ 0.857 \end{align}$

おわりに

ということで、ざっくりとしたポイントは、「ベイズ統計の考え方を用いると、結果から原因を推論するという帰納的なアプローチが可能になる」ということです。
そのうえで、何かをベイズ推定に当てはめるとき、以下のことを気にかけると分かりやすくなると思いました。

  • どちらが原因でどちらが結果か、ハッキリさせておく(因果関係は、モデル設定 [設例でいう確率表] で暗に仮定している。)
  • 観察された結果の原因は「わからない」と仮定しておく(それをベイズを使って推論するわけだから。)



おしまい。

参考書籍

これまでの学びを振り返り、より良いインプット・アウトプットを考察してみた

$
0
0

はじめに

Qiita初投稿のため、今回は書きやすそうなポエムをテーマに選びました。
筆者はソフトウェアエンジニアです。
本記事は、私が所属する企業とは一切関係ありません。
至らぬ点もあるかと思いますが、ご容赦ください。

なぜこの記事を書いたか

次の目的で作成しました。

  • 技術力の伸び悩みを感じる方に、何かの一助となる情報を提供するため
  • エンジニアになりたいが、何をしたらよいか分からない方へ、指針を提供するため

本記事はエンジニア一個人の意見であり、考察もあくまで仮説に過ぎません。
視野を広げるための材料として頂ければ幸いです。

TL;DR

  • インプットとアウトプットの目的をよく考えましょう
  • 遅延"列挙"勉強法がおすすめです
  • まずは 業務でアウトプットしましょう
  • インプットは 頭を使ってきちんと理解することに重点を置きましょう
  • アウトプットは 教えたり、問題を解いたり、OSSに携わったりしましょう

目次

まず、本論の補足を行った上で、今まで筆者が行ってきたインプット・アウトプットを振り返ります。
次に、その考察を述べます。
最後に、具体的なアクションを提示します。

Notes:

本記事が対象とする「学び」について

算数の計算方法、文章の読解方法、絵画を描く方法、など、学ぶ対象となる事柄はいくつも考えられます。
その中でも、創造性を軸に以下の2つに絞り込むことができるかと思います。

  • 正解が決まっていて、創造性を求められないこと(プログラミング言語の文法など)
  • 正解が決まっておらず、創造性を求められること(ソフトウェア開発における設計など)

本記事では、前者の「正解が決まっていて、創造性を求められないこと」を学びの対象として想定するものとします。

本記事で用いている言葉の補足

  • 「文章」は、「技術書」「チュートリアル」「ドキュメント」などを指すものとし、ブログなどの記事は「記事」に集約するものとします。
  • 「手を動かす」は、開発環境の改善、インフラ環境の構築などを指すものとします。

振り返り

まず、筆者がこれまでに行ってきた、あるいは行ってこなかったインプット・アウトプットを以下に列挙します。
内容的におおよそ重複しているものも多数ありますが、後ほど詳細に考察するために記載しています。
各項目先頭のアルファベットと数字は、keyとして記載しています。
また、経験したことのない事柄には、末尾に❓を記載しています。

今までインプット・アウトプットしてきたこと、してこなかったこと一覧

A1. 文章や記事を読む
A2. 文章や記事を読みながら、重要と思われる箇所にマーカーを引く
A3. 文章や記事を読みながら、学んだことのメモを書く
A4. 文章や記事を読みながら、分からなかったことを調べてメモする
A5. 文章や記事を読みながら、例に沿って写経する
A6. 文章や記事を読みながら、例をアレンジした上で手を動かす
A7. 文章や記事を読んで、要約を書く
B1. (業務などで)失敗したことをメモする
B2. (業務などで)学んだことをメモする
C1. 動画を視聴する
C2. 動画を視聴しながら、手を動かす
D. 記事を書く
E1. コードを書く
E2. コードをリファクタリングする
E3. コードを読む
E4. 手を動かす
F1. コードレビューで指摘する
F2. コードレビューでご指摘頂く
F3. 対面で直接教える
F4. 対面で直接ご指導頂く
F5. オンライン上で質問に回答する
F6. オンライン上で質問し、ご回答・コメント頂いた内容を拝見する
G. 問題を解く
H. 資格を取得する
I1. イベントに参加する
I2. イベントで登壇する❓
J1. OSSを公開する
J2. OSSにコントリビュートする❓
K. 文章を書く
L. プログラミングスクールに通う❓
M. 翻訳した本が出版される❓
N. 作ったサービスを公開する❓
O. 学んだことを業務で生かす

効果が大きいと感じたこと

筆者はかつて業務外で週20時間独学する生活を1年間続けたことがあります。
そんな生活を通じて、上記のリストで効果が大きいと感じたものを、以下にピックアップします。
ここではインプット・アウトプットの区別はしていません。また、経験したことのない事柄は選んでいません。
ピックアップしたものがなぜ効果があったのかは、後ほど考察していきます。

A4. 文章や記事を読みながら、分からなかったことを調べてメモする
B1. (業務などで)失敗したことをメモする
E1. コードを書く
E2. コードをリファクタリングする
E3. コードを読む
E4. 手を動かす
F1. コードレビューで指摘する
F2. コードレビューでご指摘頂く
F3. 対面で直接教える
F4. 対面で直接ご指導頂く
F5. オンライン上で質問に回答する
F6. オンライン上で質問し、ご回答・コメント頂いた内容を拝見する
G. 問題を解く
J1. OSSを公開する
K. 文章を書く
O. 学んだことを業務で生かす

考察

振り返りで述べたインプット・アウトプットの一覧は、未だそれらを別々に区別してリスト化していません。
というのも、それらを区別するためには、インプットとアウトプットそのものから考察する必要があるためです。

インプットとアウトプットの大前提1

インプットとアウトプットを事象として捉えると、明確な違いがまず見えてきます。
結論を述べますと、以下となります。

  • インプットは何かを吸収すること
  • アウトプットは自分の手で何かを生み出すこと

インプットとアウトプットの大前提2

インプットとアウトプットの内容は、 その目的は何なのかによって大きく変わってきます。
サッカー選手と審判員の例で考えてみましょう。

サッカー選手は、サッカーのルールを理解した上で、プレーに必要な技術を習得する必要があります。(練習試合ではすることがあっても)審判をすること自体は目的でないはずです。
一方、審判員はサッカーのルールを理解し、試合で審判ができなければなりません。プレーに必要な技術を習得することは目的でないはずです。

サッカー選手の目的

  • サッカーのルールを理解し、戦術として使いこなすこと
  • プレーに必要な技術を習得すること

審判員の目的

  • サッカーのルールを理解すること
  • 試合で審判を行うこと

サッカー選手が、ルールを理解し戦術として使いこなすことはアウトプットになりますが、試合で審判を行うことはアウトプットではありません。

「今までインプット・アウトプットしてきたこと・してこなかったこと一覧」を分別する

目的を仮置きした上で、「今までインプット・アウトプットしてきたこと・してこなかったのことの一覧」をそれぞれ分別しましょう。
もし可能であれば、ご自身でインプットとアウトプットに分別してみてください。

ここでの「インプット・アウトプットの目的」は、「ソフトウェアエンジニアとして仕事ができるようになること」と仮定します。

また、「ソフトウェアエンジニアの仕事」を、以下のように仮定します。

  • コードを書く
  • コードをリファクタリングする
  • コードレビューする
  • ジュニアソフトウェアエンジニアを指導する

以下が分別の結果となります。

インプット一覧

A1. 文章や記事を読む
A2. 文章や記事を読みながら、重要と思われる箇所にマーカーを引く
A3. 文章や記事を読みながら、学んだことのメモを書く
A4. 文章や記事を読みながら、分からなかったことを調べてメモする
A5. 文章や記事を読みながら、例に沿って写経する
A6. 文章や記事を読みながら、例をアレンジした上で手を動かす
A7. 文章や記事を読んで、要約を書く
B1. (業務などで)失敗したことをメモする
B2. (業務などで)学んだことをメモする
C1. 動画を視聴する
C2. 動画を視聴しながら、手を動かす
D. 記事を書く
E3. コードを読む
F2. コードレビューでご指摘頂く
F4. 対面で直接ご指導頂く
F6. オンライン上で質問し、ご回答・コメント頂いた内容を拝見する
H. 資格を取得する
I1. イベントに参加する
I2. イベントで登壇する
K. 文章を書く
L. プログラミングスクールに通う
M. 翻訳した本が出版される

アウトプット一覧

E1. コードを書く
E2. コードをリファクタリングする
E4. 手を動かす
F1. コードレビューで指摘する
F3. 対面で直接教える
F5. オンライン上で質問に回答する
G. 問題を解く
J1. OSSを公開する
J2. OSSにコントリビュートする
N. 作ったサービスを公開する
O. 学んだことを業務で生かす

なぜこのように分別されるのか

インプットの「D. 記事を書く」は書いた記事を世間に公開しているので、「インプットとアウトプットの大前提1」のアウトプットの要件「アウトプットは自分の手で何かを生み出すこと」を満たすことから、アウトプットではないか?と疑問に思われる方もいたのではないでしょうか。

「サッカー選手がルールを戦術として使いこなすことはアウトプットであるが、試合で審判を行うことはアウトプットではない」と述べたことを思い出しましょう。
これはサッカー選手の目的が、試合で審判をすることではないためです。

つまり、 目的を果たせない方法はアウトプットとはいえず、インプットとして分別されます。

上記でのインプット・アウトプットの目的は、「ソフトウェアエンジニアとして仕事ができるようになること」です。
「ソフトウェアエンジニアの仕事」を上述のように定義していますが、アウトプットに分類している内容は、そのいずれかに該当するものです。
インプットに分類している内容は、そのいずれにも該当しないものです。

よって、「D. 記事を書く」はアウトプットではなくインプットに分別されます。

ただし 目的が「テクニカルライターとして仕事ができるようになること」であった場合、インプットとアウトプットの分類はまた変わってくるでしょう。

全てを再び分類することはしませんが、ソフトウェアエンジニアとってはインプットとなる 「記事を書く」ことは、テクニカルライターにとってはアウトプットそのものです。

また、「H. 資格を取得する」も、アウトプットではなくインプットです。「資格を取得する」という仕事をしている場合はアウトプットになります。

ところで、なぜ「G. 問題を解く」をアウトプットに含めたのでしょうか。
それは、問題を解くことが 目的を達成する上で経ることになる過程を模倣しているためです。

特定のケースが条件として与えられ、それを満たすSQLを書くといった、多数の問題を有しているWebサイトがあります。
ここで解く問題は、その問題が業務で発生しうるからこそ問題になっています。
一般的に、ビジネスで必要のないケースは問題にはならず、それを満たす非常に複雑なSQLを書いたところで、アウトプットにはならないでしょう。
ただし、 その非常に複雑なSQLがかけること自体は素晴らしい能力であり、より簡単な実際に要求されるアウトプットを出せることの証明にはなるかもしれません。

逆に、ビジネスでそのような特異なケースを解決する必要があるならば、その非常に複雑なSQLを書ける能力は高火力のアウトプットになり得るのです。

インプットとアウトプットを分別するには、 その目的に合致しているかにかかっているのです。

インプットとアウトプットの共通点

「アウトプットからも学ぶことができる」と筆者は考えています。
例えば、「コードをこう書いたらうまくいったけど、なるほどこういう仕組みだったのか」といった、トライアンドエラーによって学ぶことも多々あるのではないでしょうか。

しかし、チュートリアルを何周しても、OSSを作れるようにはならないでしょう。

よって、以下の結論を導き出せます。

  • インプットはアウトプットではない
  • アウトプットはインプットでもある

インプットとアウトプットにおける忘却について

筆者は理系の人間でしたが、高校数学の複雑な公式は何度インプットしても忘れてしまいました。歴史や地理の固有名詞であれば、言うまでもありません。
一方で、粉状の化学薬品を量る際、薬さじを動かすのではなく薬品ビンの方を動かして量ることで薬品をこぼすことがない、といった専門的な知識は全く忘れることがありません。

実際には、人間は忘却の生き物であり、アウトプットしてきたことであっても忘れています。

つまり、次のように結論づけられます。

  • インプットは次第に忘れる
  • 散々アウトプットしたことは忘れにくい

インプットとアウトプットの関係

現状のインプットが0であれば、アウトプットも0になるでしょう。
しかし、既にインプットが100あっても、 初回のアウトプットが必ずしも100になるとは限りません。

これは、先ほどのサッカー選手と審判員の例で再び考えてみましょう。
サッカーの試合があるとして、サッカーのルールを全く知らない人がいきなり試合で審判することは不可能でしょう。
一方、サッカーのルールを徹底的に理解し覚えた人であっても、初めて審判をやってみると

  • 素早い判断を下せなかった
  • 覚えたルールを思い出せなかった
  • 誤審してしまった

など、幾らかの失敗があったに違いありません。

「サッカーのルールを徹底的に理解し覚えて、初めて審判をやってみた人」が100試合審判を経験した後では、審判を行う技術は初回よりも相当伸びているに違いありません。

ところで、「サッカーのルールを徹底的に理解し覚えたが、審判をやらない人」がいたとしたら、そのインプットの本来の目的である、「審判ができる」ことは達成されません(スポーツバーではご意見番として重宝されるかもしれません)。

「インプットの最終目的はアウトプットされること」であるはずです。インプットしたことをアウトプットせず他の方に共有すること自体はできますが、どこかで誰かがそれを実践して初めてインプットした情報の価値が生まれます。

以上をまとめると、次の結論が導き出せます。

  • インプットが先にこないと、アウトプットできない
  • インプットはアウトプットされて初めて価値を発揮する
  • インプット量とアウトプット量は、初めのうちは比例しない
  • アウトプットを繰り返すほど、アウトプット量はインプット量の最大値に近づいていく

インプットとアウトプットの定義

さて、やっと定義の話ができるようになりました。ここまでの結論をそれぞれまとめてみましょう。

インプットの定義

  • 何かを吸収すること
  • アウトプットではない
  • 次第に忘れる
  • インプット量とアウトプット量は、初めのうちは比例しない
  • アウトプットされて初めて価値を発揮する

アウトプットの定義

  • 自分の手で何かを生み出すこと
  • インプットでもある
  • 散々アウトプットしたことは忘れにくい(忘れることもある)
  • アウトプットを繰り返すほど、アウトプット量はインプット量の最大値に近づいていく
  • インプットを先に行なっていないとできない

結局、インプットとアウトプットをどうしていけばいいのか

インプットとアウトプットの分別方法をご理解いただけたかと思います。
それでは実際に、どのようにインプットとアウトプットを行なっていくのが良いでしょうか。
おおよそ、次のような手順で行なっていくことを想像されたのではないでしょうか。

  1. インプットを先に行う
  2. アウトプットする
  3. 以降、1と2を繰り返す

しかし、上記の方法には大きなワナが仕掛けられています。
手順1のインプットがいつまでも完了せず、手順2のアウトプットの着手が遅れてしまうのです。

今のご時世、エンジニアが学ぶべきことは数え切れないほど挙げられるでしょう。
そのため、あれもこれもインプットすることに終始しがちです。ですが、インプットはアウトプットされて初めて価値を発揮します。
10使える時間があり、インプットに9、アウトプットに1を使っていたとすれば、最終的な価値は1となってしまいます。

最初にインプットしなければいけないが、いつまでもインプットし続けるわけにはいかない」というジレンマが存在することをご認識頂けたでしょうか。

ここで発想を180度転換してみましょう。 アウトプットを先に行うのです。

  1. アウトプットしようとする
  2. アウトプットするために必要なインプットを特定する
  3. 必要なインプットだけを行う
  4. アウトプットする
  5. 以降、1~4を繰り返す

この方法のメリットは、インプットのスコープが明確に限定されていることです。
また、アウトプットファーストのため、アウトプットの量を増やすことができます。

この方法は、 遅延勉強法と呼ばれます。「インプットは必要になった時に初めて行う」のです。

まとめ:

  • 遅延勉強法によって、アウトプットを先に行うべし

遅延勉強法の問題点と解決策

非常に合理的に見える 遅延勉強法には、大きな弱点があります。
それは、 自分が必要と感じなかった事柄はインプットしないままであることです。

遅延勉強法は、まずアウトプットをしようとして、不足しているインプットを洗い出します。
このとき、実は注意しなければいけない観点があるにもかかわらずそれに気づけなかったとすれば、インプットせずに終わらせてしまうでしょう。

例えばDBのテーブルを設計していて、アンチパターンであるにもかかわらず、「上手く動いているのでインプットの必要を感じなかった」場合、そのアンチパターンに気づくことはできません。

したがって、アウトプットする際には、そのアウトプットに関連するインプットの項目を網羅的に把握しておく必要があります。
具体的には、どんなことに注意しなければならないのかを全てリスト化することです。その詳細は、知らないものだけインプットすれば良いのです。
便宜のため、この方法を本記事では 遅延"列挙"勉強法と呼ぶこととします。

遅延列挙勉強法

遅延列挙勉強法のやり方をみてみましょう。

  1. アウトプットしようとする
  2. アウトプットに関連する領域のインプット項目を列挙する
  3. 知らなかったことをインプットする
  4. アウトプットする
  5. 以降、1~4を繰り返す

遅延勉強法と異なるのは、手順2と手順3です。
手順2は、 自分が知る必要のあるインプットを特定するのではなく、万人が知る必要のあるインプットを列挙するのです。
手順3は、 知りたいことだけではなく、今の自分が知らないことを全てインプットします。

遅延列挙勉強法の問題点と解決策

遅延列挙勉強法は、その領域において知るべきことをリスト化した上で、理解していないことを全てインプットします。
そのため、 インプットにかかる時間が大きく増し、アウトプットが遅れる可能性があります。

そこで、 知るべきことに優先順位をつけ、影響度の低いものは後でインプットすることで対策できます。

後でインプットするのがポイントです。 影響度が低いと判断していても、実は重大であった場合に後から気づけるようにするためです。

インプットの問題点と解決策

インプットには二つ問題があります。

  • インプットは次第に忘れる
  • インプットはアウトプットされて初めて価値を発揮する

後者は遅延(列挙)勉強法で解消できますが、前者はその性質上、抗えません。

ですが、 人間は自分の頭できちんと理解したことは忘れにくいのです。
インプットを行う際は、 きちんと理解することに時間を使いましょう。

また、インプットは 既に理解したことを復習するより、知らなかったことを理解する方が効果が大きいです。

アウトプットの問題点と解決策

アウトプットを行う上で、一つ問題があります。
それは、 一人では達成し難いアウトプットはどう行えば良いのかです。

例えば、利益を得ることを目的とし、大規模なサービスを作ることをアウトプットとして考えます。インフラ環境の運用には、かなりお金がかかりそうです。
将来このサービスが成功してユーザーも増加すると、そのサービスをスケールする必要もあり、より一層お金がかかりそうです。
貯金を使い果たすかどうかは、サービスが成功した場合は相応の利益を得ることができるため、難しい判断です。

上記の例では、リスクを承知で先行投資する場合もありますが、そうしない場合もあります。その場合、目的のアウトプットができません。

今まで暗黙的に「独学でどうアウトプットするか」を述べてきましたが、ここでも発想を転換しましょう。業務でアウトプットするのです。

業務で携わっているサービスやシステムは、既にある程度のユーザーがいるのではないでしょうか。
また、これからグロースしていくサービスであっても、システムの運用費は会社が負担するでしょう。

つまり、 業務でアウトプットしないのは、非常にもったいないことなのです。

考察まとめ

  • インプットとアウトプットの目的をよく考えましょう
  • 遅延列挙方勉強法がおすすめです
  • まずは業務でアウトプットしましょう

アクション

上述の考察を踏まえ、具体的なアクションを評価していきましょう。

比較のため、以下のフォーマットを用いて、5段階でそれぞれ相対評価しています。絵文字が多ければ多いほど、その割合が大きいことを示します。
絵文字一つを基準として、そこから足し算で相対評価しています。
時間:⌛️
効果:💡
筆者が経験してこなかった項目については、❓で同様に評価しています。
費用は評価していません。ものによって価格が違ってくるためです。

インプットの評価一覧

文章や記事を読む

A1. (⌛️、💡)文章や記事を読む
A2. (⌛️、💡)文章や記事を読みながら、重要と思われる箇所にマーカーを引く
A3. (⌛️、💡)文章や記事を読みながら、学んだことのメモを書く
A4. (⌛️⌛️、💡💡)文章や記事を読みながら、分からなかったことを調べてメモする
A5. (⌛️、💡)文章や記事を読みながら、例に沿って写経する
A6. (⌛️⌛️、💡💡)文章や記事を読みながら、例をアレンジした上で手を動かす
A7. (⌛️⌛️、💡💡)文章や記事を読んで、要約を書く

インプットの基本ですね。
わからなかったことを調べる、アレンジして手を動かす、要約を書く、ことで効果が大きくなります。

振り返ってメモする

B1. (⌛️⌛️、💡💡)(業務などで)失敗したことをメモする
B2. (⌛️⌛️、💡)(業務などで)学んだことをメモする

上記は行動そのものに違いはありませんが、失敗したことをメモする方がその原因を理解する良いきっかけになるでしょう。

動画を活用する

C1. (⌛️⌛️⌛️、💡💡)動画を視聴する
C2. (⌛️⌛️⌛️、💡💡💡)動画を視聴しながら、手を動かす

動画の視聴は、動画のペースにこちらの理解のペースを合わせる必要があり、適切な難易度を選択すれば効果の大きい手段です。
ボリュームのある動画は倍速を活用しましょう。

以下に有用な動画サイトを列挙します(随時追加予定)。
udemy

記事を書く

D. (⌛️⌛️⌛️、💡💡)記事を書く

既に知っていることではなく、知らなかったことをテーマに書くと効果が大きくなります。

コードを読む

E3. (⌛️⌛️⌛️、💡💡💡)コードを読む

ライブラリのコードを読むことで、コードの上手い書き方を盗めます。

ご指摘頂く

F2. (⌛️、💡💡💡)コードレビューでご指摘頂く
F4. (⌛️、💡💡💡)対面で直接ご指導頂く
F6. (⌛️、💡💡💡)オンライン上で質問し、ご回答・コメント頂いた内容を拝見する

ご指摘頂くことは非常に効果が大きいです。というのも、ご指摘頂いた内容は自分ができていなかったことだからです。

資格を取得する

H. (⌛️⌛️⌛️⌛️⌛️、💡💡)資格を取得する

時間さえ確保できれば、広く体系的な知識を得るには良い手段です。

イベントに参加する

I1. (⌛️⌛️⌛️、💡💡)イベントに参加する
I2. (❓、❓)イベントで登壇する(未評価)

LTで他社の事例を知ることができたり、他の方との交流ができるため、そのような目的もある場合は特に有効です。

文章を書く

K. (⌛️⌛️⌛️⌛️、💡💡)文章を書く

まとまった文章を書くことで、体系的な理解が得られます。

プログラミングスクールに通う

L. (❓、❓)プログラミングスクールに通う(未評価)

翻訳する

M. (❓、❓)翻訳した本が出版される(未評価)

アウトプットの評価一覧

コードを書く、手を動かす

E1. (⌛️⌛️⌛️、💡💡💡💡)コードを書く
E2. (⌛️⌛️⌛️、💡💡💡)コードをリファクタリングする
E4. (⌛️⌛️⌛️、💡💡💡💡)手を動かす

アウトプットの基本ですね。

教える

F1. (⌛️⌛️、💡💡💡💡)コードレビューで指摘する
F3. (⌛️、💡💡💡💡)対面で直接教える
F5. (⌛️⌛️⌛️、💡💡💡💡)オンライン上で質問に回答する

教えることで知識が定着し、アウトプットの速度が向上するでしょう。

問題を解く

G. (⌛️⌛️⌛️、💡💡💡💡💡)問題を解く

時間制約を課すことで、より効果が大きくなります。

以下にオンラインで問題を解けるサイトを列挙します(随時追加予定)。
SQL(PostgreSQL)
HackerRank
Kaggle
AtCoder
Topcoder
Codeforces

OSSに携わる

J1. (⌛️⌛️⌛️⌛️⌛️、💡💡💡💡💡)OSSを公開する
J2. (❓、❓)OSSにコントリビュートする(未評価)

OSSを公開することで自分のポートフォリオにもなりますし、メディアで取り上げて頂くこともあります。
実際に、筆者のタスク管理アプリは MOONGIFT に取り上げて頂きました。

OSSにコントリビュートしたい場合は、このサイトから探してみると良いでしょう。

作ったサービスを公開する

N. (❓、❓)作ったサービスを公開する(未評価)

学んだことを業務で活かす

O. (⌛️⌛️、💡💡💡💡💡)学んだことを業務で生かす

既にある知識を業務でアウトプットすることで、ほぼインプットすることなくアウトプットできる非常に効率の良い手段です。

まとめ

TL;DRに飛びます

さいごに

本記事に関する感想など、コメントをお待ちしております。
ご一読頂き、ありがとうございました。

JavaScriptに苦手意識のない世界を実現したい!!

$
0
0

スタートアップのビジョン風なタイトルはさておき、高機能なフレームワークが隆盛を誇る昨今、基礎固めが大事だと思うのです。

いつ書いたのか

2020年1月頃です。

対象読者

  • JavaScriptを触ったことがあるが、言語仕様は曖昧にしている。
  • JavaScriptになんとなく苦手意識がある。

本稿でやること、やらないこと

  • 言語仕様の特徴的なところ(私見)をまとめます。
  • ベストプラクティスが変化してきたところをまとめます。
  • 言語仕様を網羅はしません。

JavaScriptの今に追いつくまでの流れ

  1. 歴史を知る。
    • https://ja.wikipedia.org/wiki/ECMAScript
    • Edition1から始まり、2019年6月時点で10が公開されている。
    • Edition5までが旧時代、6以降が新時代みたいな雰囲気がある。
    • EditionのことをECMAScript○とかES○のように呼称する。例えば、Edition5はECMAScript5。
    • ECMAScript6(Edition6、ES6も同義)以降は年号で呼称されもする。例えばES6はES2015。
  2. 言語仕様の特徴を知る。(後述)
  3. 最新版の仕様を追いかける。(これを無限ループ)
    • 標準規格が毎年公開される。その後、ブラウザの仕様に反映されてゆく。(タイムラグがある)
    • 2019年版
  4. ブラウザの対応状況を追いかける。(これも無限ループ)

言語仕様は進化し続けています。ネット上には有用な情報が溢れていますが、時系列に整理されているわけではなく、陳腐化したものも溢れています。ですから、私(たち)は混乱しますし、時に間違いも冒します。そこで、まずは歴史を振り返ります。

本稿では参考資料をいくつか紹介していますが、それらが書かれた時期に注意する必要があります。現在にも当てはまる話と、そうでないものを識別しながら読み進める必要があります。

整理しておきたいトピック

  • データの型
  • 変数のスコープ
  • Hoisting(巻き上げ)
  • Namespace(名前空間)
  • 関数
  • モジュール
  • JavaScript風オブジェクトとオブジェクト指向
  • DOM
  • イベント
  • 非同期通信
  • 非同期処理
  • クロスブラウザ問題

環境構築が面倒な人へ

https://codepen.io/

ウォーミングアップ

JavaScriptのコードをHTMLに埋め込む方法

  1. <script></script>
    1. HTMLファイル中にコードを書く場合
      <script type="text/javascript">コード</script>
    2. 外部ファイルを読み込む場合
      <script src="path/to/sample.js"></script>
  2. <a href=”JavaScript:コード”> テキスト</a>
  3. イベントハンドラ
    <input type="button" value="Click me, if you can." onclick="コード">

    関数を呼び出すとHTMLがすっきりします。
    <input type="button" value="Click me, if you can." onclick="func();">

    ただ、そもそもHTML中にJavaScriptのコードを混在させることをよしとしない考え方もあります。

<script>を埋め込む位置

  1. <body>の中
    スクリプトの読み込みや実行が完了するまで描画が行われないので</body>の直前に埋め込むのが吉。
    注意事項:ここで使う関数は、ここより以前の<script>で定義されていなければなりません。
  2. <head>の中

表示速度を上げるために</body>の直前で埋め込むのがベストプラクティスとされていますが、個別事情により<head>で埋め込む場合もあります。
参考資料:Stack Overflow

ステートメント

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements

  • 基本、セミコロンで区切られた塊を一命令と解釈する。
    • 必ずしも一行が一命令ではなく、空白、改行、タブを含めてもよい。
  • 大文字小文字を区別する。
  • コメントは//または/**/

変数名

  • 1文字目は英字、アンダースコア、$。
  • 2文字目は、1文字目で使える文字か、数字。
  • 大文字小文字を区別する。
  • 予約語は使えない。

エスケープ表記

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#Escape_notation

演算子

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators

算術演算について、誤差により計算結果が期待通りにならない場合があるので注意しましょう。整数にしてから計算したり、ライブラリを利用して対処します。

ieee754.js
console.log(0.1*3);// 0.30000000000000004

参考資料:JavaScriptで小数点の誤差が発生する件の備忘録

繰り返し処理

様々な繰り返し処理の説明はこちら

ES2015でfor...ofが導入されました。for...ofは、反復可能オブジェクト(配列、Map、Set、argumentsのような配列ライクなオブジェクト、イテレータジェネレータ)のプロパティを順に処理します。

forof.js
constbros=['ラオウ','トキ','ケンシロウ'];bros.whoAmI='ジャギ';for(constbofbros){console.log(b);}// ラオウ// トキ// ケンシロウ

for...ofはプロパティの値に対して処理を行う一方、for...inはプロパティ名に対して処理を行います。また、for...ofを相手にするのに対して、for...in参照も相手にします。

forin.js
for(constbinbros){console.log(b);}// 0// 1// 2// whoAmI

ループからの脱出にはbreaklabelを使います。

break.js
for(){break;}
label.js
label:for(){for(){breaklabel;}}

配列

以下のコードは等価です。

array.js
constfriends=['ゴン','キルア'];constfriends=newArray('ゴン','キルア');

連想配列については後述します。

ES2015で値の取り出しが便利になりました。Destructuring assignmentの使い方はこちら。オブジェクト(後述)にも適用できます。

参考資料:ECMAScript 2015 の分割代入は奥が深かった

Strictモード

strict モードでは、通常の JavaScript の意味にいくつかの変更を加えます。第一に strict モードでは、JavaScript でエラーではないが落とし穴になる一部の事柄を、エラーが発生するように変更することで除去します。第二に strict モードでは、JavaScript エンジンによる最適化処理を困難にする誤りを修正します: strict モードのコードは、非 strict モードの同一コードより高速に実行できることがあります (Firefox 4 ではまだ strict モードにあまり最適化していませんが、将来のバージョンで実現するでしょう)。第三に strict モードでは、将来の ECMAScript で定義される予定の構文を禁止します。
MDN

何がうれしいか、使い方、使用上の注意はこちら

JavaScriptが使えないブラウザ向け

fossil.html
<noscript>メッセージ</noscript>

整理しておきたい言語仕様

以下、ブラウザの実行結果は主にFirefox(Quantum 60.8.0esrや72.0.2)で確認したものです。

データの型

元々は7つ、ECMAScript 2015(以降、ES2015と呼称)でSymbol型が追加されて8つの型が定義されています。

  • Java等とは違い、変数の宣言時に型を明示しない。
    • const, let, varのいずれかと共に変数(定数)を宣言する。(後述)
  • 型変換に要注意。
    参考資料:型変換のいろいろ
  • 演算にまつわる型変換(キャスト)
    • +-の違いに注目。
    • ==オペランドの型が異なる場合、キャスト後に評価する。===はキャストせず評価する。
typecasting.js
// string + numberの場合、numberをstringにキャストして文字列連結conststringPlusNumber="abc"+1;console.log(stringPlusNumber);// abc1// string - numberの場合、stringをnumberにキャストして減算(stringが非数字)conststringMinusNumber="abc"-1;console.log(stringMinusNumber);// NaN// string - numberの場合、stringをnumberにキャストして減算(stringが数字)constnumeralMinusNumber="123"-1;console.log(numeralMinusNumber);// 122// object + numberの場合、objectとnumberをstringにキャストして文字列連結(toStringなし)constPerson=function(){this.name='Thom Browne',this.greeting=function(){console.log('Hi! I\'m '+this.name+'.');}};constperson=newPerson();letobjectPlusNumber=person+1;console.log(objectPlusNumber);// [object Object]1// object + numberの場合、objectとnumberをstringにキャストして文字列連結(toStringあり)Person.prototype.toString=functionpersonToString(){returnthis.name;}objectPlusNumber=person+1;console.log(objectPlusNumber);// Thom Browne1

型を判定する方法がいくつかあります。
参考資料:JavaScriptの「型」の判定について

Symbol型は、ぱっとみ意味が分からないですね。参考資料があります。
ECMAScript6にシンボルができた理由

変数のスコープ

JavaScriptにはかつて、2つのスコープがありました。

  • 関数内でのみアクセス可能な、ローカルスコープ。
  • どこからでもアクセス可能な、グローバルスコープ。

ES2015で1つ追加されました。

  • ifforなどの{}の内側でのみアクセス可能な、ブロックスコープ。
    (ローカルスコープを関数スコープとブロックスコープに分て考えるようになったっぽい。)

(ざっくりとした)スコープの決定メカニズム

  • const, let, var を付けずに宣言した変数はグローバルスコープ。
  • var を付けた場合、宣言した場所による。
    • 関数内で宣言した場合、関数スコープ。
    • そうでない場合、グローバルスコープ。
  • const, let を付けた場合、宣言した場所がスコープになる。
  • 関数の(値渡しした)引数は関数スコープ。
scope.js
constc="c-global";letl="l-global";varv="v-global";functionscope(){constc="c-function";letl="l-function";varv="v-function";console.log(c);// c-functionconsole.log(l);// l-functionconsole.log(v);// v-functionif(true){constc="c-block";letl="l-block";varv="v-block";console.log(c);// c-blockconsole.log(l);// l-blockconsole.log(v);// v-block}console.log(c);// c-functionconsole.log(l);// l-functionconsole.log(v);// v-block  <-- ココに注目}scope();console.log(c);// c-globalconsole.log(l);// l-globalconsole.log(v);// v-global

ちなみに、letが無かった時代には、withを用いたテクニックを使ってブロックスコープを実現していました。withの使用は推奨されません。忘れましょう。
参考資料:Architect Note

const, let, varの使い分けについては、左から順に優先して使えばよさそうです。変数を書き換える(変数から取り出した値を加工して入れ直す)場合、加工してるので別名の変数に格納すべきと考えられ、ゆえにconstで事足りそうです。for中のiのように繰り返し上書きする場合にはletが使えそうです。多くの場合、varは不要なはずです。

いずれスコープチェーンについても理解する必要がありますが、まずはJavaScriptのオブジェクト(後述)を理解するのが先です。
参考資料:tacamy--blog

Hoisting(巻き上げ)

https://developer.mozilla.org/en-US/docs/Glossary/Hoisting

  • varの巻き上げ
    ローカル変数は、スコープの冒頭で宣言、初期化するのが無難なようです。
hoisting.js
varscope='g';functionlocalScope(){// 暗黙的にvar scope;が宣言されたと解釈される。// scopeにはまだ値が入っていないためundefinedとなる。console.log(scope);// undefinedvarscope='l';console.log(scope);// lreturnscope;}console.log(localScope());// lconsole.log(scope);// g
  • 関数の巻き上げ

    <script>は何度でも埋め込むことができますが、同一スコープ中で関数を定義、使用する場合、どちらを先に書いても構いません。巻き上げられるため。しかし、定義する<script>と使用する<script>が異る場合、先に定義しておく必要があります。

  • 関数式の巻き上げ

    巻き上げません。定義する前に関数式を使用できません。変数と考えれば自然な挙動ですね。

Namespace(名前空間)

JavaScript でネームスペースを作成する考え方はシンプルです。グローバルオブジェクトをひとつ作成して、すべての変数、メソッド、関数をそのオブジェクトのプロパティとすればよいのです。ネームスペースを使用すると、アプリケーション内で名前が衝突する可能性が低下します。これは各アプリケーションのオブジェクトが、アプリケーションで定義したグローバルオブジェクトのプロパティとなるからです。
MDN

スコープや名前空間に付随するあれこれ

JavaScriptには元々スコープが2つしかなく、モジュール(後述)にも非対応だった等の理由から、変数の汚染(意図せずに変数を上書きしてしまう事故)を防ぐためのテクニックが活用されていました。読みやすく、保守しやすいコードを書くために、変数を多用しすぎないのが吉という考え方がありますが、JavaScriptは比較的変数の汚染が起きやすいという性質も相俟って、このようなテクニックが発達したように見えます。

即時関数

即時関数という仕組みがありましたが、役割を終えた感があります。
参考資料:
JavaScriptで即時関数を使う理由
JavaScriptから即時関数を排除する

closure(クロージャ)

まずは見た目に慣れるところから始めたいと思います。

iamclosure.js
functioniAmClosure(){letval;// ローカル変数constfunc(){// 関数の中で関数を宣言する// ローカル変数valを参照する処理}}

使ってみます。

iamclosuretoo.js
functioniAmClosureToo(init){letcount=init;returnfunction(){// 関数を返すと、呼び出し元のプログラムで繰り返し呼び出せるreturncount++;}}constcounter=iAmClosureToo(1);// counterにはcountを参照する匿名関数がセットされるconsole.log(counter());// 1console.log(counter());// 2

クロージャを理解するには、まずレキシカルスコープ(静的スコープ)とダイナミックスコープを理解する必要がありそうです。

レキシカルスコープは関数を定義した時点でスコープが決まり、ダイナミックスコープは関数を実行した時点でスコープが決まるものです。どちらになるかは言語次第のようで、JavaScriptは前者です。

lexical.js
constval=1;functionsub(){console.log(val);// sub()の定義時点でvalは1}functionmain(){constval=2;sub();// sub()の実行時点でvalは2}main();// 1sub();// 1

MDNの例で、何が特徴的なのかを確認します。

他の言語に慣れている人は"関数内部のローカル変数はその関数が実行されている間だけ存在する"と考えることに慣れているかもしれません。つまり、var myFunc = makeFunc();の実行時点でローカル変数nameが消滅するように直感し、結果このコードは動かないと考えられます。しかし、JavaScriptでは、このコードが動きます。JavaScriptでは、displayName()の定義時点でスコープが決まり、nameにはMozillaが設定されるものと解釈します。クロージャでは、この時の環境への参照を保持しており、myFuncを実行した時に結果を返すことができます。

closure.js
functionmakeFunc(){varname="Mozilla";functiondisplayName(){console.log(name);}returndisplayName;}varmyFunc=makeFunc();myFunc();// Mozilla

で、何に使うんだよ?という疑問に答えてくれる人がたくさんいます。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures#Practical_closures
https://stackoverflow.com/questions/2728278/what-is-a-practical-use-for-a-closure-in-javascript/39045098
https://artgear.hatenablog.com/entry/20120115/1326635158
http://dqn.sakusakutto.jp/2012/02/javascript_13.html
クロージャ再考

で、オブジェクトとクロージャは何が違うんだよ?という疑問に答えてくれる人も見つけました。(実質答えてないけど)

https://www.ibm.com/developerworks/jp/opensource/library/itm-progevo3/index.html
https://www.ibm.com/developerworks/jp/opensource/library/itm-progevo4/index.html?ca=drs-

オブジェクトとクロージャに関する考察に関する参考資料をもう一つ。

http://kmaebashi.com/programmer/devlang/object.html

クロージャについては、様々な言語の成り立ちやコンピュータサイエンス的なことへの理解が試される気がします。個人的には、クロージャにしかできないことがまだ見つからないため、探求を続けたいと思います。

関数

定義の仕方が3つあります。

  1. 関数宣言
    • function functionName () {}
    • コードを解析、コンパイルするタイミングで関数を登録するため、同一の<script>内で、定義する前に呼び出しのコードがあっても正しく処理される。
  2. 関数式(匿名関数、無名関数)
    • const functionName = function(arg) {}; functionName(1);
    • この場合、関数は変数なので、呼び出しよりも先に定義する必要がある。
    • 変数を節約できる。
    • 再利用しない場合(高階関数の引数にする場合やコールバック関数等)に重宝する。
  3. Functionコンストラクタ
    • スコープの解釈が直感と一致しない上、セキュリティとパフォーマンスの問題もある。
    • この方法で定義するメリットは基本的にないらしい。
    • 但し、Object.prototype.constructorの戻り値として内部的に使われていたりもするため、(開発者が)使わないなら要らないじゃんってことにはならない。

そして、ES2015でアロー関数が導入されました。アロー関数は、関数式の短い代替構文で、2つの理由から導入されました。

  1. 簡潔に書ける。
  2. thisを束縛しない。

書き方はこんな感じ。

  • function(x) {}(x) => {}になる。
  • 1行で書ける時は{}とreturnを省略できる。
  • 引数が1つの場合()を省略できる。 function(x) {}x => {}になる。
  • 引数がない場合、()を必ず書く。 function() {}() => {}になる。

"thisを束縛しない"の意味がぱっとみ分からないと思います。参考資料があります。コメント欄にも注目です。
JavaScript の this を理解する多分一番分かりやすい説明
【JavaScript】アロー関数式を学ぶついでにthisも復習する話

引数

デフォルト引数

ES2015で、デフォルト引数の指定が可能となりました。それ以前は、argumentsオブジェクトを利用したテクニックを使って実装していました。デフォルト引数には以下のようなルールがあります。

  • デフォルト引数は、引数を指定しない時かundefinedを明示的に指定した時に適用される。
  • nullやfalseを指定した場合には適用されない。
  • デフォルト値には(先に宣言された)他の引数、関数の結果も指定できる。

使い方はこちら

必須パラメータを指定するのにも利用できます。

required.js
functionrequired(){thrownewError('Argument is required');}functionisString(value=required()){returntypeofvalue=="string"||valueinstanceofString;}console.log(isString("abc"));// trueconsole.log(isString(123));// falseconsole.log(isString());// Argument is required

Rest parameters(可変長引数と訳す?)

従来はargumentsオブジェクトを活用して実装していましたが、ES2015でRest parametersが使えるようになりました。ちなみにargumentsとの違いがいくつかあります。詳細はこちら

restparams.js
functionrestparams(...args){console.log(argsinstanceofArray);// truereturnargs.length;}console.log(restparams());// 0console.log(restparams("one"));// 1console.log(restparams("one","two"));// 2

名前付き引数(言語仕様ではなく、テクニックの話)

引数に名前を付けられると、以下のようなメリットが考えられます。

  • コードの可読性が上がる。
  • 引数の順番を変えられる。
  • 引数の省略を柔軟にできる。
namedarguments.js
// function bmi(weight_kg, height_m) {...}functionbmi(args){if(args.weight_kg==undefined){args.weight_kg=70;}if(args.height_m==undefined){args.height_m=1.9;}return(args.weight_kg/(args.height_m**2));}bmi({weight_kg:58,height_m:1.7});// 引数の意味が明確bmi({height_m:1.7});// 前方の引数を省略bmi({height_m:1.7,weight_kg:58});// 引数の順序を入れ替え

モジュール

かつてJavaScriptはWebサイトにちょっとした動きを与えるような小さなコードだったようです。しかし、昨今ではサーバーサイドでも使われたり、フロントエンドでも複雑な動き与えるなどゴリゴリに使い倒され、巨大なアプリケーションになりました。そのため、コードをモジュール化してスコープを分離したり、着脱可能にするアーキテクチャへの要請が高まったようです。結果、ES2015からモジュールが使えるようになりました。

使い方はこちら

ただし、IEは<script type="module">に非対応だそうです。

モジュールバンドラ

IEの問題やHTTP/1.1の問題(ファイルをたくさん読み込むと通信が非効率)等への対応や、その他のメリットもありwebpackなどのモジュールバンドラを利用します。
参考資料:最新版で学ぶwebpack 4入門 JavaScriptのモジュールバンドラ

JavaScript風オブジェクトとオブジェクト指向

オブジェクト指向にはクラスベースとプロトタイプベースがあります。JavaやPHPは前者、JavaScriptは後者です。その他のポイントも含めていくつか書き留めてみます。

JavaScriptにおいて、連想配列はオブジェクトです。

associativearray.js
constaArray={x:1,y:2};console.log(typeofaArray);// objectconsole.log(aArrayinstanceofArray);// falseconsole.log(aArray['x']);// 1console.log(aArray.x);// 1

連想配列に限らず様々なものがオブジェクトとして表現されます。標準ビルトインオブジェクトを参照のこと。標準ビルトインオブジェクトの他にもブラウザの操作に使うオブジェクト、DOMの操作に使うオブジェクト、Ajaxに使うオブジェクト等があります。

標準ビルトインオブジェクト

適当に例を列挙します。

Arrayオブジェクト

使い方はこちら。配列の操作(ソート等)に重宝する。

Dateオブジェクト

date.js
lettoday=newDate();letbirthday=newDate('1995/12/17 03:24:00');letbirthday=newDate('December 17, 1995 03:24:00');letbirthday=newDate('1995-12-17T03:24:00');letbirthday=newDate(1995,11,17);letbirthday=newDate(1995,11,17,3,24,0);

日付、時刻を加減算するメソッドはなく、getXxxx(), setXxxx()で実現します。期間の差は以下の様にして求めます。

tmn.js
conststart=newDate(1984,4,21);constend=newDate(1994,4,21);(end.getTime()-start.getTime())/(1000*60*60*24);

上述した通りJavaScriptにはdate型はありません。使い方はこちら。罠にご注意下さい。

参考資料:
JavaScript の Date は罠が多すぎる
【JavaScript】日付処理

Numberオブジェクト

number.js
constnum=123;constnumo=newNumber(123);console.log(num);// 123console.log(numo);// 123console.log(typeofnum);// numberconsole.log(typeofnumo);// objectconsole.log(numoinstanceofNumber);// true

使い方はこちら。ちなみに、NaNは、NaNを含む全ての値と等しくない。NaNを検出するにはisNaN関数を使用します。

isnun.js
console.log(Number.NaN==Number.NaN);// falseconsole.log(isNaN(Number.NaN));// true

Stringオブジェクト

string.js
conststr='文字列';conststro=newString('文字列');console.log(str);// 文字列console.log(stro);// 文字列console.log(typeofstr);// stringconsole.log(typeofstro);// objectconsole.log(stroinstanceofString);// true

使い方はこちら。文字列の操作(部分抽出等)に重宝します。

RegExpオブジェクト

正規表現を司ります。ざっくりとした使い方は以下のような感じ。詳しくはこちら。Editionが上るにつれて進化しているので、最新仕様をご確認のこと。

re.js
constre=newRegExp('正規表現','オプション');constre=/正規表現/オプション;

argumentsオブジェクト

関数の引数の情報を管理する配列ライクなオブジェクト1。引数のチェックや可変長引数(?)の実装に利用されていた部分は、新たに導入されたデフォルト引数やRest parametersにより代替できると考えられます。

使い方はこちら

再帰関数を作る時にcalleeプロパティが役に立ちます。

factorial.js
functionfactorial(n){if(n!=0){// calleeの代わりに関数名を直書きした場合、関数名を変更した時に修正が必要。// また、匿名関数の場合は、関数名がないのでcallee一択。returnn*arguments.callee(n-1);}return1;}console.log(factorial(3))// 6

Objectオブジェクト

すべてのオブジェクトの元になっているオブジェクトで、すべてのオブジェクトはObject.prototypeからメソッドとプロパティを継承しています。使い方はこちら

ところで、toString()は指定したオブジェクトを表す文字列を返します。toString()は人知れず内部的に使われていることがあります。暗黙の型変換の如く、オブジェクトが文字列に変換されていたりします。

object.js
object=newObject();date=newDate();array=newArray([1,2,3]);console.log(object.toString());// [object Object]console.log(date.toString());// Mon Jan 27 2020 22:57:56 GMT+0900 (JST)console.log(array.toString());// 1,2,3

匿名(無名)オブジェクトというものがあります。再利用する必要がない場合に利用します。

anonymous.js
constobj=newObject();// オブジェクトを宣言した後に外からプロパティを設定できる。obj.name='anonymous';obj.role='anything';console.log(obj.toString());// [object Object]console.log(obj.name);// anonymousconsole.log(obj.role);// anything// const obj = { name:'anonymous', role:'anything' }; でも同じ結果が得られる。

ES2015で追加されたオブジェクト

ProxyReflectMapSetWeakMapWeakSetPromise(後述)など。

Global object(単数形) と Global objects(複数形)

日本語訳注: 英語版では、JavaScript 実行時に作成される、グローバルスコープを表す唯一となるグローバルオブジェクトを単数形の global object とし、そのグローバルオブジェクトが持つ「グローバルにアクセスできる変数、関数などのオブジェクトの一群」のプロパティを複数形の global objects として表しています。日本語の文法は単数形、複数形を持たないため、上記では単数形の方に『』を付けてそれぞれを区別しています。
MDN

Global objectは他のオブジェクトのようにインスタンス化するものではなく、グローバル関数等を管理するための領域と考えられます。グローバルプロパティや関数の使い方はこちら

JavaScriptではところどころで暗黙的に型変換が行われますが、明示的に行うこともできます。バグを出さないために、関数の癖をつかんでおく必要があります。

typecast.js
console.log(Number('123abc'));// NaNconsole.log(parseFloat('123abc'));// 123console.log(parseInt('123abc'));// 123console.log(Number('abc123'));// NaNconsole.log(parseFloat('abc123'));// NaNconsole.log(parseInt('abc123'));// NaNconsole.log(Number(newDate(1984,4,21)));// 453913200000console.log(parseFloat(newDate(1984,4,21)));// NaNconsole.log(parseInt(newDate(1984,4,21)));// NaNconsole.log(Number('0o123'));// 83console.log(parseFloat('0o123'));// 0console.log(parseInt('0o123'));// 0console.log(Number('314e-2'));// 3.14console.log(parseFloat('314e-2'));// 3.14console.log(parseInt('314e-2'));// 314

decodeURI(), encodeURI(), decodeURIComponent(), encodeURIComponentなんかも要チェック。escape()は非推奨。eval()はセキュリティホールになりがちなので要注意、パフォーマンスもいまいちらしい。

ブラウザを操作するオブジェクト

ECMAScriptにより標準されているわけではなく、ブラウザベンダーが独自に実装しています(尚、本稿で主に参照しているmozillaの仕様においてはDOMやHTML Living Standardなどを参照しているようです)。共通して使えるものもたくさんありますが、標準ではありません。異るブラウザで動作するようにコードを作るのは大変です。標準化されているDOMを操作するオブジェクトを利用するのが望ましいという考え方もあります。

w3schools.comによると、Browser Objectsには、Window Object, Screen Object, Location Object, History Object, Navigator Objectがあります。

ブラウザオブジェクトは階層構造になっているそうです。参考資料中にあるDocumentオブジェクトはw3schoolsが示すブラウザオブジェクトの中には見当たりません。
参考資料:JavaScript 〜ブラウザオブジェクトを操作してみよう〜

MDNによると、
Window.screenプロパティは、読み取り専用で、Screen objectへの参照を返します。
Window.locationプロパティは、読み取り専用で、Location objectへの参照を返します。
Window.historyプロパティは、読み取り専用で、History objectへの参照を返します。
Window.navigatorプロパティは、読み取り専用で、Navigator objectへの参照を返します。
Window.documentプロパティは、読み取り専用で、そのウィンドウが含むdocumentへの参照を返します。

ここで、Windowとwindowの違いを確認しておきます。Stack Overflowによると、Windowはfunctionで、windowはグローバル変数です。windowはWindowのインスタンスを保持しています。

Window Object

documentについては後述しますが、windowのプロパティにアクセスする時、window.を明記してもしなくても構いません。Windowは開発者が触るもんじゃないようです。

window.js
document.write('abc');// OKwindow.document.write('abc');// OKだけどwindow.が不要Window.document.write('abc');// エラー

alert(), confirm()なども同様に使えます。使い方はこちら

Screen Object

ざっくりURLの情報を取得するのに使うオブジェクトという認識。使い方はこちら

Location Object

ざっくりURLの操作に使うオブジェクトという認識。使い方はこちら

History Object

ざっくりブラウザが管理する閲覧履歴の操作に使うオブジェクトという認識。使い方はこちら

Navigator Object

ざっくりユーザーエージェントの操作に使うオブジェクトという認識。使い方はこちら

Document

windowよろしくdocumentもDocumentのインスタンスを保持していると考えればいいのかしら。ざっくりDOMの操作に使うオブジェクトという認識。使い方はこちら

document.html
<script type="text/javascript">functionaccessToForm(){// 以下は全て等価console.log(document.formName.textName.value);console.log(document.forms[0].elements[0].value);console.log(document.forms['formName'].elements['textName'].value);console.log(document['formName']['textName'].value);constsT=Object.prototype.toString;console.log(sT.call(document));// [object HTMLDocument]console.log(sT.call(document.formName));// [object HTMLFormElement]console.log(sT.call(document.formName.textName));// [object HTMLInputElement]}</script><formname="formName"onsubmit="accessToForm(); return false;"><inputtype="text"name="textName"></form>
  • HTMLFormElementを使って<form>を操作する。
    • document.formNameで取得した<form>の属性にdocument.formName.<属性名>でアクセスすることもできる。
  • HTMLInputElementオブジェクトを使って<input>を操作する。
  • ラジオボタンやチェックボックスの場合はNodeListを継承しているRadioNodeListで操作する。
  • <select>は、HTMLSelectElementで操作する。

プロトタイプベースなオブジェクト指向

  • JavaScriptにはクラスという概念はなく、プロトタイプという概念がある。
  • プロトタイプオブジェクトというものがあり、すべてのオブジェクトはプロトタイプオブジェクトのメソッドとプロパティを継承する。
  • newすることを想定した関数オブジェクトのことをコンストラクタと呼ぶ。
    • コンストラクタは戻り値を返してはならない。
  • オブジェクトに対して外部からメンバを追加できる。
    • その結果、同一のコンストラクタをもとに生成されたインスタンスであっても、それぞれが持つメンバが異なる場合がある。
  • JavaScriptにおけるクラスベース風なオブジェクト指向
    ES2015でクラスベースなオブジェクト指向の書式が導入されたが、これはシンタックスシュガー(糖衣構文)で、JavaScriptのオブジェクト指向は引き続きプロトタイプベース。

ちなみに、厳密には"メソッド"という言い方はふさわしくないかもしれませんが、本稿では便宜的にそう呼びます。

JavaScript には、クラスベースの言語が定義する形式の「メソッド」はありません。 JavaScript ではどの関数も、オブジェクトのプロパティという形で追加することができます。
MDN

constructor.js
// コンストラクタの定義constPerson=function(name){// thisキーワードを用いてメンバを定義するthis.name=name;// メソッドの定義this.introduce=function(){return'I am '+this.name+'.';}};constperson=newPerson('Michael');console.log(typeofperson);// objectconsole.log(personinstanceofPerson);// trueconsole.log(person.introduce());// I am Michael.// オブジェクトの定義後にメンバを追加できるperson.nickname='Mike';person.callme=function(){return'Please call me '+this.nickname+'.';}console.log(person.callme());// Please call me Mike.

さて、コンストラクタをnewして生成されるインスタンスは、個々に異るメモリ領域を確保します。上記の例でPersonのインスタンスを複数作成すると、全てのインスタンスは同じintroduceメソッドを持ちますが、それぞれ別のメモリ領域を確保してしまいます。この非効率を、prototypeプロパティを用いて解消します。prototypeはデフォルトで空のオブジェクトを参照していて、これにメンバを追加できます。以下の様にコードを書き換えます。

prototype.js
// 変更前person.callme=function(){return'Please call me '+this.nickname+'.';}// 変更後// 'p'ersonインスタンスではなく、'P'ersonコンストラクタのprototypeにメソッドを定義Person.prototype.callme=function(){return'Please call me '+this.nickname+'.';}console.log(person.callme());// Please call me Mike.

Personはprototypeプロパティを通じてcallmeメソッドを参照しています。Personを元にして生成されたpersonもcallmeメソッドを参照しています。なので、person.callme()のようにしてcallmeメソッドを利用できます。const another_person = new Person('Mary');のようにして生成したanother_personもcallmeメソッドを参照しており、another_person.callme()のようにして利用できます。callme()はメモリ上に一つあり、個々のインスタンスはそれを参照するため、別々のメモリ領域を確保することはありません。

プロトタイプにメソッドをたくさん定義する時は、以下の様にすると楽です。

prototype.js
Person.prototype={callme:function(){return'Please call me '+this.nickname+'.';},initialIs:function(){returnthis.name.slice(0,1);}};constperson=newPerson('Michael');person.nickname='Mike';console.log(person.callme());// Please call me Mike.console.log(person.initialIs());// M.

prototype中のメソッドを書き換えると、それを参照する全てのインスタンスに影響があります。

s_DD270B68D27518943D49DED4298C9E2331541FFEBFA1DA6251D773064106AE8A_1579138403353_image.png

ところで、personインスタンスに後から追加したcallmeメソッドはpersonに固有のメソッドとなり、Personから生成される他のインスタンスに引き継がれることはありません。(ゆえに、同一のコンストラクタをもとに生成されたインスタンスであっても、それぞれが持つメンバが異なるケースが発生します。)

プロトタイプチェーン

あるオブジェクトのプロパティにアクセスを試みるとき、そのオブジェクトのみならず、そのオブジェクトのプロトタイプ、プロトタイプのプロトタイプ…と、一致する名前のプロパティが見つかるか、プロトタイプチェーンの終端に到達するまで、そのプロパティが捜索されます。
MDN

上記の例で、person.callme()というコードが実行される時、まずpersonの中にcallmeメソッドを探しに行きます。存在しないため、プロトタイプの中に探しに行きます。そこで見つかったので実行します。

ここで確認しておきたいことがあります。

Person.prototype.callmeが定義済みの状態で、以下のコードを実行します。

prototype.js
person.callme=function(){return'Do NOT call me '+this.nickname+'.';}

この時、プロトタイプチェーンを辿りプロトタイプの中のcallmeメソッドを書き換えることはありません。この場合、person中に新たにcallmeメソッドが定義されます。その後、person.callme()を実行すると、プロトタイプチェーンの仕組みに則り、personの中にcallmeメソッドを探しに行きます。そこで見つかるため実行します。プロトタイプ中のcallmeメソッドが上書きされることはないので、他のインスタンスに影響を与えることはありません。

ここまでの内容を、もし俺がまとめてこられてきてたとしたら2、こう。

prototype.js
constPerson=function(name){this.name=name;this.introduce=function(){return'I am '+this.name+'.';}};constperson=newPerson('Michael');console.log(typeofperson);// objectconsole.log(personinstanceofPerson);// trueconsole.log(person.introduce());// I am Michael.person.nickname='Mike';Person.prototype.callme=function(){return'Please call me '+this.nickname+'.';}console.log(person.callme());// Please call me Mike.person.callme=function(){return'Do NOT call me '+this.nickname+'.';}console.log(person.callme());// Do NOT call me Mike.constanother_person=newPerson('Mary');another_person.nickname='May';console.log(another_person.callme());// Please call me May.

もう一つ注意事項があります。

overrideprototype.js
constMoten=function(){};constKanki=function(){};constPerson=function(){};Moten.prototype={strategize:function(){return'全軍撤退します。';}};Kanki.prototype={strategize:function(){return'鄴をぶんどります。';}};// prototypeにオブジェクトへの参照を設定Person.prototype=newMoten();constperson=newPerson();// Personをnewした後に別のオブジェクトを設定すると...Person.prototype=newKanki();// prototypeが上書きされていないconsole.log(person.strategize());// 全軍撤退します。

静的メソッド

static.js
constPerson=function(){};Person.bePeaceful=function(){return'We are the one.';}// Personをnewせずにメソッドを呼び出すconsole.log(Person.bePeaceful());// We are the one.// インスタンスから呼び出そうとするとエラーになるconstperson=newPerson();console.log(person.bePeaceful());// TypeError: person.bePeaceful is not a function

静的メンバはprototypeを参照しません。

クラスベース風なオブジェクト指向の静的メソッドはこちら

プライベートメンバ

JavaScriptにはアクセス修飾子(public、protected、private)がありません。言語仕様として、プライベートメンバを定義することができません。しかし、それっぽくするテクニックはあります。例えば、クロージャを利用したやり方があります。その他にも様々な方法が提案されています。

クロージャ派、Symbol型派、WeakMap派と、運用でなんとかする(privateメンバに名前の頭に_を付ける)派をよく見かけます。

クラスベースなオブジェクト指向

ES2015でクラスベースなオブジェクト指向の書式が導入されました。しかし、これはシンタックスシュガー(糖衣構文)です。JavaScriptのオブジェクト指向は引き続きプロトタイプベースです。

書き方はこんな感じです。クラスの巻き上げはないの定義に呼び出すとエラーになります。

classbaseclass.js
classPerson{constructor(name){this.name=name;}introduce(){return`I am ${this.name}.`;}}constperson=newPerson('Michael');console.log(person.introduce());

匿名クラスが宣言できます。

anonymousclass.js
constPerson=class{// 同上}

プロパティを単独で宣言することはできず、constructor中で宣言するか、getter, setterを使うかのどちらかっぽい。getter, setter, 継承など、詳細はこちら

DOM

DOMを正確に理解するには調べていただくとして、ざっくり以下の様に認識しています。

  • DOMはオブジェクトである。
  • Webページを、ある決まりに従ってDOMで表現する。
  • JavaScriptはDOMを通じてWebページを操作する。

DOMは標準に則り生成されるオブジェクトですが、ブラウザやバージョンによって若干異るようです。

標準はこちら。特にここ

DOMでは、文書(Webページ)の構成要素(<html>, <body>, <p>やタグで囲まれたテキスト等)をノードとみなします。JavaScriptはノードを取得して、中身を参照したり、書き換えたりします。

要素(タグ)の操作

取得するノードを識別する方法は2つあります。

  • idのようなキーで識別する。(document.getElementByIdなど)
  • あるノードからの相対的な位置関係で識別する。
direct.html
<script type="text/javascript">functionaccessToForm(){constform=document.getElementsByTagName('form');constinput=document.getElementsByTagName('input');console.log(form[0]);// <formname="form"onsubmit="accessToForm(); return false;">// <inputname="name"type="text">// <inputname="address"type="text">// <inputvalue="submit"type="submit">// </form>
console.log(form[0][0]);// <inputname="name"type="text">console.log(form[0][1]);// <inputname="address"type="text">console.log(form[1]);// undefinedconsole.log(input[0]);// <inputname="name"type="text">console.log(input[1]);// <inputname="address"type="text">console.log(input[3]);// undefined}</script><formname="form"onsubmit="accessToForm(); return false;"><inputtype="text"name="name"><inputtype="text"name="address"><inputtype="submit"value="submit"></form>
walking.html
<script type="text/javascript">functionaccessToForm(){constselect=document.getElementById('finish');constoptions=select.childNodes;for(leti=0;i<options.length;i++){constoption=options.item(i);if(option.nodeType==1){console.log(option.value+''+option.textContent);// right ひ…ひと思いに右で…やってくれ// left ひ…左?// both もしかしてオラオラですかーッ!?}}}</script><formname="form"onsubmit="accessToForm(); return false;"><selectid="finish"><optionvalue="right">ひ…ひと思いに右で…やってくれ</option><optionvalue="left">ひ…左?</option><optionvalue="both">もしかしてオラオラですかーッ!?</option></select><inputtype="submit"value="やれやれだぜ"></form>

指定したノードが存在しない場合undefinedを出力しています。存在する場合、ノードに応じたオブジェクトを返します。例えば、forminputの場合HTMLCollection<select>の場合HTMLSelectElementoptionの場合NodeList。オブジェクトが持つメンバを使って操作できます。

ノードを追加するには以下の様にします。詳細はDOMの仕様書等をご参照のこと。

addnode.html
<script type="text/javascript">functionadd(form){constgraffiti=form.graffiti.value;constnote=document.getElementById('note');// 要素を作成するconstbutton=document.createElement('button');// 属性を作成するconstvalue=document.createAttribute('value');value.nodeValue=graffiti;// 要素に属性、テキストを関連付けるbutton.setAttributeNode(value);button.textContent=graffiti;// ページに要素を関連付けるnote.appendChild(button);// テキストノードを作成するconsttext=document.createTextNode(graffiti);// ページにノードを関連付けるnote.insertBefore(text,button);}</script><form><inputtype="text"name="graffiti"><inputtype="submit"value="ノードを追加する"onclick="add(this.form); return false;"></form><divid="note"></div>

ノードを書き換える場合は<親ノード>.replaceChild(<置換後のノード>, <置換対象のノード>)、削除する場合は <親ノード>.removeChild(<削除対象ノード>)

属性の操作

要素中の属性にアクセスしたい場合、上記の様にして要素を取得してから、<要素>.<属性>のようにしてアクセスできる属性が多いですが、classclassNameでアクセスするなど、変則的なものもあります。

あるいは、Elementのメンバを利用して、<要素>.getAttribute(<属性>)<要素>.setAttribute(<属性>, <値>)のようにして操作することもできます。attributesにより、要素に関連したすべての属性のリスト(NamedNodeMap)を得られます。IEはNamedNodeMapのサポートが不完全なようなので注意が必要です。

属性を追加する場合は<要素>.setAttribute(<属性>, <値>);、属性を削除する場合は<要素>.removeAttribute(<属性>)

スタイルシートの操作

<要素>.style.<スタイルプロパティ>でアクセスする。スタイルプロパティについてはこちら

DOMの構築やらJavaScriptが処理をするまでの流れやら

参考資料を紹介します。とてもおもしろいです。

【JavaScript基礎】JavaScriptの実行順序について
実際のところ「ブラウザを立ち上げてページが表示されるまで」には何が起きるのか
Life of a Pixel

仮想DOM

JavaScriptの仕様とは直接的に関係ないと思いますが、ついでに仮想DOMについて。仮想DOMを正確に理解するには調べていただくとして、ざっくり以下の様に認識しています。

  • なにがうれしいのか?
    高速な処理が可能。従来はリクエスト毎にDOMを0から作っていた。仮想DOMがある世界では、古い仮想DOMと新しい仮想DOMの差分をDOMに反映するだけで済む。
    (数年前から優位性が薄れている説も見かける。)

  • どうやって使うのか?
    仮想DOMをサポートしたフレームワークを利用する。ReactとかVueとか。

イベント

画面のロードやクリックなど、ブラウザ上(というのが厳密に正しいかはおいといて)で起きることをイベントと呼びます。イベントが起きたことをトリガーとしてJavaScriptで処理を行います。指定できるイベントはこちら

イベントハンドラ

以下の様な流れで実装、実行します。

  1. イベントハンドラと関連付ける処理をJavaScriptで定義する。
  2. イベントハンドラとその処理を関連付ける。
  3. イベントが起きた時、イベントハンドラが検知し、関連づけられた処理を実行する。

イベントハンドラの仕掛け方は2つあります。(似たような仕組みとしてイベントリスナがありますが後述します。)

  1. HTMLタグにonイベント名属性(イベントハンドラ)とJavaScriptのコードを関連付ける

    htmlhandler.html
    <script type='text/javascript'>functionclickEvent(){alert('A handler is executed!');}</script><inputtype="button"value="Why don't you click?"onclick="clickEvent(); return false;">

    HTML中にJavaScriptのコード(スクリプト)を混在させることをよしとしない考え方もあります。
    HTMLタグにスクリプトを埋め込む場合は、デフォルトのスクリプト言語を宣言しておくのが望ましいとされていましたが、HTML5ではデフォルト扱いとなり省略されることになりました。
    <meta http-equiv="Content-Script-Type" content="text/javascript">

  2. (ページロード時等に)JavaScriptで登録する。

    jshandler.html
    <script type='text/javascript'>// onloadによりロード完了後に下記のコードが実行されるため、セレクタが空振らないwindow.onload=function(){// クリックイベントを検知するonclick(イベントハンドラ)と関数を関連付けるdocument.getElementById('btn').onclick=function(){alert('A handler is executed!');}}</script><inputtype="button"value="Why don't you click?"id="btn">

イベント発生時の標準の挙動

以下の様に予め挙動が決まっているものがあります。

  • リンクがクリックされたらページを移動する。
  • サブミットボタンがクリックされたらフォームを送信する。
  • ページ上で右クリックされたらコンテキストメニューを表示する。

このような挙動を抑止したい時があります。抑止できます。

cancelevent.html
<!-- onclick="return false;"でクリックの標準挙動を抑止する --><inputtype="submit"value="Why don't you submit?"onclick="return false;">

イベントリスナの場合は後述します。

イベントリスナ

イベントハンドラとイベントリスナの違いがまだ腹落ちしきっていません3が、一つ分かっていることは、イベントハンドラに関連付けられる処理は1つですが、インベントリスナの場合、複数関連付けられます。

登録

IEの場合attachEvent、それ以外の場合addEventListenerでイベントと処理を関連付けます。ここにもクロスブラウザの問題が横たわっています。attachEventについてはこちら。addEventListenerについてはこちら

eventlistener.html
<!-- jshandler.htmlと見比べて見るとよいかも --><script type="text/javascript">// イベントリスナ登録のラッパー関数(クロスブラウザ対策)functionaddListener(element,event,listener){if(element.addEventListener){// IE以外element.addEventListener(event,listener,false);}elseif(element.attachEvent){// IEelement.attachEvent('on'+event,listener);}else{thrownewError('利用できるイベントリスナがありません。');}}// loadによりロード完了後に下記のコードが実行されるため、セレクタが空振らないaddListener(window,'load',function(){addListener(document.getElementById('btn'),'click',function(){alert('A listener is executed!');});});</script><inputtype="button"value="Why don't you click?"id="btn">

Eventオブジェクト

リスナはEventオブジェクトを受け取ります。このあたりもブラウザとバージョンによって仕様が異なるので注意が必要です。

eventlistener.html
  addListener(window, 'load', function (e) {
    console.log(Object.prototype.toString.call(e));  // [object Event]
  });

e.targetwindow.event.srcElemente.buttonwindow.event.buttonの違いなど要チェックです。

削除

IEの場合detacheEvent、それ以外の場合removeEventListenerでイベントと処理を関連付けを解除します。detacheEventについてはこちら。removeEventListenerについてはこちら

バブリング

バブリングを正確に理解するには調べていただくとして、ざっくり「文書(Webページ)の下位の要素で発生したイベントは、上位の要素でも発生する。但し例外もある。」と認識しています。

bubbling.html
<script type="text/javascript">window.addEventListener('load',function(){document.getElementById('higher').addEventListener('click',function(e){window.alert("The higher listener is executed!");});document.getElementById('lower').addEventListener('click',function(e){window.alert("The lower listener is executed!");});});</script><divid="higher"style="width:100px; height:100px; border: solid 1px #000;"><divid="lower"style="width:50px; height:50px; border: solid 1px #f00;">
    Why don't you click?
  </div></div>

上位の要素でイベントが発生するのを抑止したいことがあります。抑止できます。IE以外の場合eventObject.stopPropagation()、IEの場合window.event.cancelBubble=trueとします。

bubbling.html
    document.getElementById('lower').addEventListener('click', function(e) {
      window.alert("The lower listener is executed!");
      e.stopPropagation();  // この行を追加
    });

バブリングの参考資料がありました。
DOMイベントのキャプチャ/バブリングを整理する 〜 JSおくのほそ道 #017

イベント発生時の標準の挙動を抑止するには、イベントハンドラではreturn false;しましたが、イベントリスナでは、IE以外の場合eventObject.preventDefault()、IEの場合window.event.returnValue=falseとします。

非同期通信

Ajax

Ajaxによる非同期通信を正確に理解するには調べていただくとして、ざっくり「画面を丸々ロードするのではなく、一部を差し替える技術。HTTPリクエストの応答をXMLやJSON等の形式で受けてDOMに反映しページを更新する。」くらいに認識しています。資料は山ほどあると思いますので、軽く流します。

クロスブラウザ問題はここにもあり(と思ったけどさすがにもう気にしなくていいか)、Ajaxに使うオブジェクトが何種類かあります。

オブジェクトブラウザ
XMLHttpRequestIE 7.0以降及びその他のブラウザ
ActiveXObject('Msxml2.XMLHTTP')IE 6.0
ActiveXObject('Microsoft.XMLHTTP')IE 5.5以前

XMLHttpRequestの使い方はこちら。メンバをいくつかメモ。

メンバメモ
responseText応答をテキストやJSON4で受け取る
responseXML応答をDocumentオブジェクトで受け取る。前述の通り操作できる。
readyState0~4(4が完了)
statusHTTPステータスコード(200がOK)
open(method, url, async, user, password)async=falseの時、同期通信を行うためサーバーが応答を返すまで後続の処理を行わない。URLは相対パスで指定する。
setRequestHeader(header, value)HTTPリクエストヘッダを設定する。
send(body)リクエストを送信する。

セキュリティのためクロスドメインのAjax通信は禁じられています。(サーバーサイドで別ドメインから取得した情報をフロントエンドに渡すことは可能。)かつてJSONPという技術でクロスドメイン通信するテクニックがありましたが、役割を終えた感があります。CORSの実装が推奨されています。

Fetch API

Fetch API を利用すると、リクエストやレスポンスといった HTTP のパイプラインを構成する要素を操作できるようになります。また fetch() メソッドを利用することで、非同期のネットワーク通信を簡単にわかりやすく記述できるようになります。
従来、このような機能は XMLHttpRequest を使用して実現されてきました。 Fetch はそれのより良い代替となるもので、サービスワーカーのような他の技術から簡単に利用することができます。 Fetch は CORS や HTTP 拡張のような HTTP に関連する概念をまとめて定義する場所でもあります。
MDN

ECMAScriptの標準ではなく、Fetch Living Standardに準拠しています。後述するPromiseを理解しておく必要があります。

fetchメソッドの使い方はこちら。Fetchがサポートされていないブラウザ向けにFetch Polyfillが利用できます。Polyfillについては後述します。

非同期処理

非同期を正確に理解するには調べていただくとして、ざっくり「複数の処理を想定した時、非同期処理とは、一方の処理を実行している最中に他方の処理を同時に行うこと。ちなみに同期処理の場合、一方の処理を実行が完了するまで他方の処理を行わない。」くらいの認識です。

JavaScriptではかつて非同期処理を実現するのにsetTimeoutsetIntervalを利用していましたが、課題がありました。新しい仕組みが導入され、徐々に改善されてきています。

参考資料:
JavaScriptとコールバック地獄
JavaScriptと非同期のエラー処理

Promise

ES2015で標準ビルトインオブジェクトに追加されました。非同期処理を実現します。使い方はこちら

promise.js
functionasynchronous(testCase){returnnewPromise(function(resolve,reject){setTimeout(function(){if(testCase==='normal'){// 正常系はresolveを呼び出し、結果をthenに渡す。resolve('Normal');}else{// 異常系はrejectを呼び出し、結果をcatchに渡す。reject('ABEND');}},1000);})}console.log('Before asynchronous()');// ①// asynchronous('abnormal')  // 異常系asynchronous('normal')// 正常系     // ②.then(function(ret_resolve){console.log(ret_resolve);}).catch(function(ret_reject){console.log(ret_reject);}).finally(function(){console.log('Finish');});console.log('After asynchronous()');// ③

1秒待つため、①、③、②の順に実行されます。Promiseはresolve関数とreject関数を受け取ります。resolveの結果はthenが受け取り、rejectの結果はerrorが受け取ります。どちらに転んでもfinallyは実行されます。

下記のコードでも同じ結果が得られます。理由はこちら

promise.js
asynchronous('normal').then(function(ret_resolve){console.log(ret_resolve);},function(ret_reject){console.log(ret_reject);})// .catch()がない.finally(function(){console.log('Finish');});

Promise.prototype.then()Promise.prototype.catch()もPromiseを返すので、連鎖させられます。(then()catch()を連ねて書ける。)

サンプルコードをもう一つ。

promiseall.js
functionasynchronous(canary){returnnewPromise((resolve)=>{setTimeout(()=>{resolve(canary);},1000*Math.random());})}Promise.all([// 前のasynchronous()の完了を待たずして、後のasynchronous()が呼び出される。asynchronous('1'),asynchronous('2'),asynchronous('3'),])// all()では全てのasynchronous()が完了すると呼び出される。// race()の場合、全完了を待たず、どれか一つが完了した時点でthenなりcatchなりを実行する。.then(ret_resolve=>{// asynchronous()の完了順にかかわらず配列の順番は一定(呼び出し順)。console.log(ret_resolve);// [ "1", "2", "3" ]});

async/await

ES2017で追加されました。非同期処理を実現します。使い方はこちらこちら。サンプルコードを一つ。

asyncawait.js
functionasynchronous(testCase){returnnewPromise((resolve,reject)=>{setTimeout(()=>{if(testCase==='normal'){resolve('血祭りだ');}else{reject('来ませんでした');}},1000);})}asyncfunctionseries(){// 非同期処理の完了を待つ。その一方で呼び出し元に処理を戻す。result=awaitasynchronous('normal');// 正常系// result = await asynchronous('abnormal');  // 異常系// awaitの完了後に処理する。console.log('しかも7日で');// ①returnresult;}series()// ②.then(ret_resolve=>{console.log(ret_resolve);}).catch(ret_reject=>{// 異常系の場合、awaitの処理を中断してここに飛んでくる。console.log(ret_reject);});// series()よりも後ろにあるけど、seriesがasyncだから並列実行される。// seriesは1秒かかるので、こちらの結果が先に出力される。console.log('ほ…本当に 来てくれたのか');// ③

正常系の場合、③、①、②の順に実行されます。異常系の場合、③、②の順に実行されます。

Promiseやasync/awaitが登場する前jQuery.Deferred()がよく利用されていたようですが、生のJavaScriptで使える非同期処理を使いこなしたいですね。

参考資料:async/await 入門(JavaScript)

クロスブラウザ問題

ブラウザ間やバージョン間の実装の違いによるJavaScriptの解釈の違いが開発者を悩ませます。

ES2015以降の様式で書かれたコードを古いJavaScriptの様式に変換するコンパイラ(トラスコンパイラ、トランスパイラなどと呼ばれる)にBabelというものがあります。例えば、IEをサポートしなければならないけれども、ES2015の機能を使いたい等の場面で利用します。

Babelが変換できないものもあるので、Polyfillというものも利用します。使い方は@babel/polyfill/core-jsPolyfill.ioをご参照のこと。

ES2015(ES6)以降に追加された機能

まとめがありました。

ECMAScript6の新機能
ES2016 / ES2017の最新動向を追ってみた
ES2015・ES2016・ES2017・ES2018を手早く学習するTHE ES Guide

さいごに

JavaScriptの学習を楽にするために、散在する情報の整理を試みてみました。何かの役に立てば幸いです。有益な情報を公開して下さった先人たちに敬意と感謝の気持ちでいっぱいです。ありがとうございます。


  1. lengthプロパティと0から始まる添字のプロパティを持つが、forEachやmapのようなArrayの組み込みメソッドを持たない。 

  2. M-1 2019 

  3. 諸説ある模様。Stack OverflowQuora檜山正幸のキマイラ飼育記 (はてなBlog)。 

  4. HTTPプロトコルの仕様上JSONのオブジェクトを授受できないのでシリアライズ(テキスト形式に変換)して授受する。eval('(' + XMLHttpRequestObject.responseText + ')')でテキストからJSONオブジェクトに戻す。 

WEB開発に役に立つAPI一覧+API毎に関連するQiita記事を分類 !

$
0
0

前回: Qiita APIで記事からYoutube動画を集めてみた 🎬、Qiita APIを使って、Qiita記事を取得してYoutube動画のURLを抽出することができました。

今回は、特定APIに関連したQiita記事を取得して、API毎に分類、タグを集計してドーナツグラフ化することでAPIの特徴を表してみました

API一覧 | DOGAKIITAA! ~ APIごとにQiita記事を分類 ~

Google系

Cloud Vision API

https://cloud.google.com/vision/docs/quickstart

📝 機械学習を使用して画像を解析します。画像ラベリング、顔やランドマークの検出、光学式文字認識(OCR)、不適切なコンテンツへのタグ付けなどができます。

他のQiita関連記事またはドーナツグラフを見る

Natural Language API

https://cloud.google.com/natural-language/?hl=ja

📝 機械学習を使用してテキストを解析します。文書を構文解析、単語のエンティティ分析、感情分析などができます。

他のQiita関連記事またはドーナツグラフを見る

Translation API

https://cloud.google.com/translate/docs?hl=ja

📝 テキストを任意の言語に翻訳します。事前トレーニング済みニューラル機械翻訳を活用して、高速かつ動的に翻訳できます。1~500,000文字まで無料。

他のQiita関連記事またはドーナツグラフを見る

Dialogflow API

https://cloud.google.com/dialogflow?hl=ja

📝 チャットボットに使う自然言語対話用APIです。ウェブサイトやモバイル アプリケーション、一般的なメッセージング プラットフォーム、IoT デバイス向けの会話インターフェースの作成に使用できます。

他のQiita関連記事またはドーナツグラフを見る

Cloud Speech-to-Text API

https://cloud.google.com/speech-to-text/docs/?hl=ja

📝 音声をテキストに変換します。機械学習を利用し、120の言語と方言を認識、話し言葉を自動的に特定などできます。

他のQiita関連記事またはドーナツグラフを見る

Cloud Video Intelligence API

https://cloud.google.com/video-intelligence/?hl=ja

📝 動画コンテンツを分析します。オブジェクト、場所、アクションを自動的に認識します。シーンの変化も区別し、動画レベル、ショットレベル、フレームレベルで豊富なメタデータを抽出できます。

他のQiita関連記事またはドーナツグラフを見る

Gmail API

https://developers.google.com/gmail/api?hl=ja

📝 Gmailへのアクセスとメール送信に使用します。メッセージの読み取りと送信、下書きと添付ファイルの管理、スレッドとメッセージの検索、ラベルの操作、プッシュ通知の設定、Gmail設定の管理などできます。

他のQiita関連記事またはドーナツグラフを見る

Google Calendar API

https://developers.google.com/calendar

📝 Googleカレンダーと連携できるAPIです。カレンダーイベントを表示、作成、変更、カレンダーやアクセス制御など、他のカレンダーオブジェクトを操作できます。

他のQiita関連記事またはドーナツグラフを見る

Google Drive API

https://developers.google.com/drive/?hl=ja

📝 Google Drive を操作できます。ファイルをアップロード、ダウンロード、ファイル検索などできます。

他のQiita関連記事またはドーナツグラフを見る

Google Slides API

https://developers.google.com/slides/how-tos/overview?hl=ja

📝 Googleスライドと連携するAPIです。スライドを作成したり、テキスト、図形や表などの要素をスライドに追加したりできます。

他のQiita関連記事またはドーナツグラフを見る

Analytics API

https://developers.google.com/analytics/devguides/reporting/core/v3?hl=ja

📝 Google アナリティクスの統計情報を操作できます。

他のQiita関連記事またはドーナツグラフを見る

Sheets API

https://developers.google.com/sheets/api/reference/rest/

📝 Google Spread Sheetsを操作できます。スプレッドシートを新規作成、更新、値の読み取りや書き込みなどができます。

他のQiita関連記事またはドーナツグラフを見る

YouTube Data API

https://developers.google.com/youtube/v3/docs/

📝 YouTubeを操作します。動画、チャンネル検索や動画のアップロードなどができます。一日あたりのAPI使用量(クォータ)の上限があります。

他のQiita関連記事またはドーナツグラフを見る

Google Maps JavaScript API

https://developers.google.com/maps/documentation/javascript/tutorial

📝 地図をカスタマイズして、ウェブページや携帯端末に表示します。マップタイプ(ロードマップ、衛星、ハイブリッド、および地形)を表示、マーカ作成、オーバーレイ作成、ヒートマップ、交通を表示、ルート案内、標高、ジオコーディング、ストリートビューを利用できます。

他のQiita関連記事またはドーナツグラフを見る

Google Earth Engine API

https://developers.google.com/earth-engine?hl=ja

📝 クラウド型の衛星画像解析プラットフォームと連携するAPIです。森林変化や地表水の変化を可視化、衛星画像を視覚化したり計算に使用したりできます。

他のQiita関連記事またはドーナツグラフを見る

開発ツール系

GitHub API

https://developer.github.com/v3/

📝 GitHubを操作できるようになるAPIです。

他のQiita関連記事またはドーナツグラフを見る

Bitly API

https://dev.bitly.com/v4_documentation.html

📝 短縮URLサービスBitlyを使用できるAPIです。

他のQiita関連記事またはドーナツグラフを見る

Qiita API

https://qiita.com/api/v2/docs

📝 エンジニア情報共有サイトQiitaの情報を取得したり、記事の作成やストックなどの操作ができるAPIです。

他のQiita関連記事またはドーナツグラフを見る

Amazon 系

Amazon PERSONALIZE

https://aws.amazon.com/jp/personalize/

📝 自分のサービスのユーザーに機械学習の知識がなくても、オススメを提案できるサービスです。

他のQiita関連記事またはドーナツグラフを見る

Amazon FORECAST

https://aws.amazon.com/jp/forecast/

📝 過去の時系列データを用意して、機械学習によって時系列予測ができるサービスです。

他のQiita関連記事またはドーナツグラフを見る

Amazon TRANSCRIBE

https://aws.amazon.com/jp/transcribe/

📝 ディープラーニングを使用して、音声をテキストに変換することができます。

他のQiita関連記事またはドーナツグラフを見る

Amazon RECOGNITION

https://aws.amazon.com/jp/rekognition/

📝 ディープラーニングを使用して、画像およびビデオ分析します。ラベル、テキスト検出、顔検出と感情分析、有名人の認識、不適切なコンテンツへのタグ付けができます。

他のQiita関連記事またはドーナツグラフを見る

Amazon COMPREHEND

https://aws.amazon.com/jp/comprehend/

📝 機械学習を使用した自然言語処理です。テキストを分析して、キーフレーズ、場所、人物、ブランド、またはイベントを抽出し、テキストが肯定的か否定的か分析などを行うことができます。

他のQiita関連記事またはドーナツグラフを見る

Amazon TEXTRACT

https://aws.amazon.com/jp/textract/

📝 機械学習を使用した文章からテキストやデータをOCRよりも正確に抽出できるサービスです。

他のQiita関連記事またはドーナツグラフを見る

Amazon POLLY

https://aws.amazon.com/jp/polly/

📝 ディープラーニングを使用した文章をリアルな音声に変換するサービスです。

他のQiita関連記事またはドーナツグラフを見る

Amazon LEX

https://aws.amazon.com/jp/lex/

📝 音声やテキストを使用して、任意のアプリケーションに対話型インターフェイスを構築するサービスです。Amazon Alexa に採用されている深層学習技術と同じ技術を利用し、自然言語での高度な対話ボットを短時間で構築できます。

他のQiita関連記事またはドーナツグラフを見る

Amazon TRANSLATE

https://aws.amazon.com/jp/translate/

📝 ディープラーニングを使用して、正確で自然な翻訳を提供する言語翻訳サービスです。

他のQiita関連記事またはドーナツグラフを見る

Amazon FRAUD DETECTOR

https://aws.amazon.com/jp/fraud-detector/

📝 オンライン決済の不正利用や偽のアカウントの作成などを自動的に判断してくれるサービスです。

他のQiita関連記事またはドーナツグラフを見る

Amazon CODEGURU

https://aws.amazon.com/jp/codeguru/

📝 コードレビューとアプリケーションパフォーマンスの推奨事項を提供する機械学習サービスです。

他のQiita関連記事またはドーナツグラフを見る

Microsoft系

Azure Computer Vision

https://azure.microsoft.com/ja-jp/services/cognitive-services/computer-vision/

📝 機械学習を使用した画像認識サービスです。

他のQiita関連記事またはドーナツグラフを見る

Azure Face API

https://azure.microsoft.com/ja-jp/services/cognitive-services/face/

📝 機械学習によって顔認識をします。似た顔の検索、顔認証、感情分析、タグ付けなどができます。

他のQiita関連記事またはドーナツグラフを見る

Azure Speech Translation

https://azure.microsoft.com/ja-jp/services/cognitive-services/speech-translation/

📝 クラウドベースのリアルタイムの自動音声翻訳サービスです。

他のQiita関連記事またはドーナツグラフを見る

Azure Speech to Text

https://azure.microsoft.com/ja-jp/services/cognitive-services/speech-to-text/

📝 ディープラーニングを用いて、音声をテキストに変換できます。

他のQiita関連記事またはドーナツグラフを見る

Azure Video Indexer

https://azure.microsoft.com/ja-jp/services/media-services/video-indexer/

📝 動画から、話し言葉、文字テキスト、顔、話し手、有名人、感情、トピック、ブランド、シーンなどのメタデータを抽出できます。

他のQiita関連記事またはドーナツグラフを見る

Microsoft Translator API

https://azure.microsoft.com/ja-jp/services/cognitive-services/translator-text-api/

📝 機械学習を使用したテキスト翻訳APIです。

他のQiita関連記事またはドーナツグラフを見る

AI&解析系

Clarifai

https://docs.clarifai.com/

📝 人工知能を使用した画像、動画認識サービスです。画像を自動でタグ付けしたり解析したりできます。

他のQiita関連記事またはドーナツグラフを見る

Watson Natural Language Understanding

https://www.ibm.com/cloud/watson-natural-language-understanding

📝 自然言語によるテキスト分析により、概念、エンティティ、キーワード、などのメタデータを抽出できます。

他のQiita関連記事またはドーナツグラフを見る

Repl-AI

https://repl-ai.jp/

📝 docomoが提供するシナリオ対話および雑談対話を組み合わせ、好みの対話AIです。プログラミング不要で誰でも簡単にチャットボットを作れます。

他のQiita関連記事またはドーナツグラフを見る

エンターテイメント系

スナップショット検索API v2

http://site.nicovideo.jp/search-api-docs/snapshot.html

📝 ニコニコ動画のコンテンツを解析する目的で検索/取得する際に利用できます。キーワードやフィルタ条件を指定して、動画を検索できます。

他のQiita関連記事またはドーナツグラフを見る

NHK番組表API

http://api-portal.nhk.or.jp/

📝 全国のNHKの放送番組のタイトルや放送時間などの番組情報を取得できるAPIです。

他のQiita関連記事またはドーナツグラフを見る

MarvelAPI

https://developer.marvel.com/

📝 70年前からのマーベル・コミックのライブラリ資料を利用できるAPIです。スパイダーマンが登場するコミックの名前など検索できます。

他のQiita関連記事またはドーナツグラフを見る

twitch API

https://dev.twitch.tv/docs/v5

📝 ゲームライブストリーミング配信プラットフォーム「Twitch」提供のAPI。チャンネル、クリップ、ストリーム情報などを取得できます。

他のQiita関連記事またはドーナツグラフを見る

Vimeo API

https://developer.vimeo.com/jp/

📝 Vimeoのデータを利用できます。

他のQiita関連記事またはドーナツグラフを見る

BBS&SNS系

Facebook Graph API

https://developers.facebook.com/docs/graph-api

📝 Facebookデータを取り込んだり、取り出したりするためのAPIです。ほとんどのデータを取得するにはレビューを受けなければならず、簡単には利用ができなくなってます。

他のQiita関連記事またはドーナツグラフを見る

Instagram Graph API

https://developers.facebook.com/docs/instagram-api

📝 Instagramデータを取り込んだり、取り出したりするためのAPIです。Facebookと同様にほとんどのデータを取得するにはレビューを受けなければならず、簡単には利用ができなくなってます。

他のQiita関連記事またはドーナツグラフを見る

Twitter API

https://developer.twitter.com/en/docs

📝 Twitterデータを取得したり、ツィートしたりするためのAPIです。使用する前にアカウント登録し、twitterの承認を得る必要があります。

他のQiita関連記事またはドーナツグラフを見る

LINE Messaging API

https://developers.line.me/ja/docs/messaging-api/overview/

📝 LINE上で動くボットを作成するAPIです。ユーザーにLINE上で、応答メッセージ、プッシュメッセージ、動画や画像いろいろなメッセージを送ることができます。

他のQiita関連記事またはドーナツグラフを見る

Pinterest API

https://developers.pinterest.com/docs/getting-started/introduction/

📝 PinterestデータにアクセスできるAPIです。ボード、ピン、フォロワーなどのデータを取得できます。

他のQiita関連記事またはドーナツグラフを見る

LinkedIn API

https://developer.linkedin.com/docs/rest-api

📝 ビジネス特化型SNS LinkedInのデータにアクセスできるAPIです。

他のQiita関連記事またはドーナツグラフを見る

ツイキャスAPI

https://apiv2-doc.twitcasting.tv/#introduction

📝 ライブ配信TwitCasting(ツイキャス) のデータにアクセスできるAPIです。ユーザー情報、ライブ配信情報やコメントなどの情報が取得できます。

他のQiita関連記事またはドーナツグラフを見る

Reddit API

https://www.reddit.com/dev/api/

📝 英語圏の巨大BBSサイトRedditのデータを取得できるAPIです。

他のQiita関連記事またはドーナツグラフを見る

仕事効率化系

Evernote API

https://dev.evernote.com/doc/

📝 Evernoteと連携できるAPIです。

他のQiita関連記事またはドーナツグラフを見る

Office 365 API

https://docs.microsoft.com/ja-jp/previous-versions/office/office-365-api/

📝 OneNote、Outlook、Excel、OneDrive、Microsoft Teams、Planner、SharePoint などの Office 365 のサービスと連携できるAPIです。

他のQiita関連記事またはドーナツグラフを見る

Slack API

https://api.slack.com/

📝 ビジネスコミュニケーションツール「slack」と連携できるAPIです。

他のQiita関連記事またはドーナツグラフを見る

ChatWork API

http://developer.chatwork.com/ja/

📝 クラウド型ビジネスチャットツール「Chatwork」と連携できるAPIです。

他のQiita関連記事またはドーナツグラフを見る

Dropbox API

https://www.dropbox.com/developers/documentation/http/overview

📝 オンラインストレージサービス「DropBox」と連携できるAPIです。

他のQiita関連記事またはドーナツグラフを見る

ライフスタイル系

ぐるなびAPI

https://api.gnavi.co.jp/api/

📝 飲食店の情報を集めたウェブサイト「ぐるなび」の情報を取得できるAPIです。

他のQiita関連記事またはドーナツグラフを見る

DMM Webサービス

https://affiliate.dmm.com/api/

📝 DMMが保有するデータベースを外部から利用するAPIです。

他のQiita関連記事またはドーナツグラフを見る

Amazon Product Advertising API

https://images-na.ssl-images-amazon.com/images/G/09/associates/paapi/dg/index.html

📝 Amazonの製品カタログデータにアクセスできるようにするAPIです。

他のQiita関連記事またはドーナツグラフを見る

Yahoo!ショッピングWeb API

https://developer.yahoo.co.jp/webapi/shopping/

📝 Yahoo!ショッピングが持つ日本最大級の商品データベースや最先端のEC機能を直接利用できるAPIです。

他のQiita関連記事またはドーナツグラフを見る

LINE Pay

https://pay.line.me/jp/developers/apis/onlineApis?locale=ja_JP

📝 LINEの決済サービスLINE Payと連携できるAPIです。

他のQiita関連記事またはドーナツグラフを見る

Stripe

https://stripe.com/docs/api

📝 決済サービス「Stripe」と連携できるAPIです。

他のQiita関連記事またはドーナツグラフを見る

ホットペッパーAPI

https://webservice.recruit.co.jp/hotpepper/reference.html

📝 ホットペッパーWebサービスのデータを取得できるAPIです。

他のQiita関連記事またはドーナツグラフを見る

画像系

Cloudinary

https://cloudinary.com/documentation/cloudinary_references

📝 クラウドベースの画像およびビデオ管理サービス「Cloudinary」と連携するAPIです。画像やビデオをアップロード、保存、管理、操作、配信できます。

他のQiita関連記事またはドーナツグラフを見る

imgIX

https://docs.imgix.com/apis/url

📝 画像ファイルの配信向けに特化したCDN 「imgix」と連携できるAPIです。

他のQiita関連記事またはドーナツグラフを見る

Flickr API

https://www.flickr.com/services/api/

📝 写真投稿コミュニティflickrと連携できるAPIです。写真を検索したり画像情報を取得できたりします。

他のQiita関連記事またはドーナツグラフを見る

Giphy APi

https://developers.giphy.com/

📝 GIF画像検索共有サイト 「GIPHY」と連携できるAPIです。膨大なGIF画像ライブラリにアクセスすることができます。

他のQiita関連記事またはドーナツグラフを見る

Imgur API

https://apidocs.imgur.com/?version=latest

📝 オンライン画像共有と画像管理サービス「imgur」と連携できるAPIです。

他のQiita関連記事またはドーナツグラフを見る

天気系

Yahoo! 気象情報API

https://developer.yahoo.co.jp/webapi/map/openlocalplatform/v1/weather.html

📝 指定した緯度経度の雨の強さを取得できるAPIです

他のQiita関連記事またはドーナツグラフを見る

Livedoor Weather Web Service

http://weather.livedoor.com/weather_hacks/webservice

📝 お天気Webサービス(Livedoor Weather Web Service / LWWS)は、現在全国142カ所の今日・明日・あさっての天気予報・予想気温と都道府県の天気概況情報を取得できるAPIです。

他のQiita関連記事またはドーナツグラフを見る

OpenWeatherMap API

https://openweathermap.org/api

📝 無料で使える気象情報を提供しているAPIです。

他のQiita関連記事またはドーナツグラフを見る

旅行系

楽天トラベル施設検索API

https://webservice.rakuten.co.jp/api/simplehotelsearch/

📝 楽天トラベルの施設を施設番号、緯度経度、区分コードなどで検索し、施設情報を取得することができるAPIです。

他のQiita関連記事またはドーナツグラフを見る

アンチウイルス系

AbuseIPDB

https://www.abuseipdb.com/api

📝 スパム、ハッキング、脆弱性スキャン、およびその他の悪意のある活動に関与するIPアドレスをレポートおよびチェックするためのAPIです。 IPアドレスを確認してネットワークを保護し、検出した悪意のあるIPアドレスを送信できます。

他のQiita関連記事またはドーナツグラフを見る

Google Safe Browsing

https://developers.google.com/safe-browsing/v4

📝 ソーシャルエンジニアリングサイト(フィッシングサイトや詐欺サイト)やマルウェアや不要なソフトウェアをホストするサイトなど安全でないURLをチェックすることができるAPIです。

他のQiita関連記事またはドーナツグラフを見る

VirusTotal

https://developers.virustotal.com/reference

📝 ファイルまたはURLをアップロードしてウイルススキャンできるAPIです。

他のQiita関連記事またはドーナツグラフを見る

本系

Google Books API

https://developers.google.com/books

📝 Google Booksと連携できる書籍検索APIです。

他のQiita関連記事またはドーナツグラフを見る

楽天ブックス書籍検索API

https://webservice.rakuten.co.jp/api/booksbooksearch/

📝 楽天ブックスで販売されている書籍の情報を取得することができるAPIです。

他のQiita関連記事またはドーナツグラフを見る

国立国会図書館サーチ

https://iss.ndl.go.jp/

📝 国立国会図書館をはじめ、全国の公共図書館、公文書館、美術館や学術研究機関等が提供する資料、デジタルコンテンツを統合的に検索できるAPIです。

他のQiita関連記事またはドーナツグラフを見る

openBD

https://openbd.jp/

📝 openBDプロジェクトによる書誌情報・書影を、だれでも自由に使える、高速なAPIです。

他のQiita関連記事またはドーナツグラフを見る

音楽系

iTunes Search API

https://affiliate.itunes.apple.com/resources/documentation/itunes-store-web-service-search-api/

📝 iTunes Store や Apple Books Storeからデータを取得できるAPIです。

他のQiita関連記事またはドーナツグラフを見る

Spotify

https://developer.spotify.com/documentation/web-api/

📝 音楽ストリーミングサービス「Spotify」と連携できるAPIです。

他のQiita関連記事またはドーナツグラフを見る

辞書系

MediaWiki API

https://www.mediawiki.org/wiki/API:Main_page/ja

📝 オンライン百科事典ウィキペディアからデータを取得できるAPIです。

他のQiita関連記事またはドーナツグラフを見る

科学系

NASA

https://api.nasa.gov/

📝 NASAが公開しているデータにアクセスするAPIです。

他のQiita関連記事またはドーナツグラフを見る

政府系

e-Stat API

https://www.e-stat.go.jp/api/

📝 政府統計の総合窓口(e-Stat)で提供している統計データを取得できるAPIです。

他のQiita関連記事またはドーナツグラフを見る

地図系

Foursquare Places API

https://developer.foursquare.com/docs/api

📝 Foursquareが提供するデータへアクセスするAPIです。

他のQiita関連記事またはドーナツグラフを見る

what3words API

https://developer.what3words.com/public-api/docs

📝 3つのことばで全世界のアドレスを表現しようとするwhat3wordsのAPIです。3つのことばのアドレスを座標に変換、またその逆変換できます。

他のQiita関連記事またはドーナツグラフを見る

Yelp

https://www.yelp.com/developers

📝 ローカルビジネスレビューサイトYelpに掲載されているデータを取得できるAPIです。

他のQiita関連記事またはドーナツグラフを見る

駅すぱあとWebサービス

https://ekiworld.net/service/sier/webservice/free_provision.html

📝 「駅すぱあと」が集めた駅情報や路線情報をオープンデータにアクセスするAPIです。

他のQiita関連記事またはドーナツグラフを見る

APIの導入が簡単スムーズになりますように(笑)

laravel view内でjQueryを使おうとしたら「$ is not defined」エラーが出た話

$
0
0

超超まぬけな話です。
同じことをやらかしそうな未来の私のために書きました。

view内でjQueryを使おうとした

view内でjQueryを使おうとしていました。
jQueryはすでに読み込んであったので、 @section('script')からはじめて、スクリプトを書いていました。

@section('script')<script>// jQueryの中身$('.hoge').find('.hoge_hoge').blur(function(){hogeFunction();});</script>

$ is not defined!!

いざ表示を確認してみると、consoleタブにエラーが出ていました。
「$ is not defined」
jQueryの読み込みがおかしいか、jQueryが読み込まれる前に実行された場合に起きるやつです。

ソースを確認すると、↑に書いたスクリプト文が、<!doctype html>より上にいました。
それでjQueryが読み込まれてないのか!そう思い、私はviewのscriptをwindow.onload = function(){}で囲って対応しましたとさ。

そのすぐ後に、そんな対応が不要になりました。

原因

@endsectionがなかった。

@section('script')<script>// jQueryの中身$('.hoge').find('.hoge_hoge').blur(function(){hogeFunction();});</script>
@endsection// ← これ!!

結局

付け足したら、window.onloadなど書かなくても普通に動いてくれました。
ソースがおかしいと思った時点で、調べましょう、過去の私。


ChromeでうまくいったものをIEにするとうまくいかなかったこと事例

$
0
0

はじめに

WEBページ制作においてどのブラウザでも表示できることはとても大切だと思います。
今回Chromeでうまく表示できていたものがIEではうまくできなかったことと、解消方法を備忘録として記載します。事例が追加されれば追記したいと思います。

① 画像が表示できない

Chromeでは問題なく表示できていた画像がIEだと出てこない。。。。orz

解決方法

調べるとカラーモードが 「CMYK」になっているとIEでは表示されないとのこと。
画像軽量化ツールを利用し画像を軽量化することで解決できました!

■参考サイト
JPGなどの画像が表示されない原因、チェックしたいこと まとめ

② flex-directionを指定すると余計な余白が発生する

Chromeでは出なかった不自然な余白がIEで発生し、確認したところflex-directionを指定している箇所でした。

どうやら flex-directioncolumncolumn-reverseを指定した子要素に画像があると、その子要素に画像の元サイズの高さ分のスペースができてしうとのことです。この元サイズの高さ分のスペースを消す必要があります。

解決方法

min-height: 0%;を指定することで解決できました!

■参考サイト
flex-directionを指定した時に IE11で表示がおかしくなる

まとめ

まだまだ初心者なのでブラウザごとに表示状況が変わっていることにかなりストレスを感じていましたが、きちんと調べて対処していけば解消できる(と思う)ので、これからもトライしていきます。

また、これからまだまだたくさんでてくることだと思うので随時更新していきます!

git コマンド まとめ 基礎 自分用

$
0
0

環境

前提としている知識

command line

使用した教材

progate:Git レッスン
Udemy:はじめてのGitとGithub

大まかなワークフロー

プロジェクトにリポジトリを作成し、github等のリモートリポジトリにアップするまで

  • バージョン管理したいフォルダのディレクトリに移動し、git initと入力しリポジトリを作成する。
  • ファイルを編集する
  • git add .というコマンドでファイルの変更をステージングエリアへ追加する。(ファイルを削除した場合は代わりにgit rm
  • git commit -vというコマンドで変更を記録する。
    • 一行目:変更内容の要約
    • 二行目:空欄
    • 三行目:変更した理由
  • git pushというコマンドでリモートリポジトリにアップする。

現在の状況を確認

git status

ブランチ、追記されたコミットの数、ファイルの状況を確認できる
- 赤字:変更したファイルがまだaddされていない状態
- 緑字:addされたがコミットされてない状態

変更履歴を確認

git log

ハッシュ値、編集した人、日付、コミットメッセージを確認できる。

LOGICOOL OPTION logicool optionをmacのPCに導入する

$
0
0

目的

  • macのPCにlogicool optionをインストールし使えるようにする

作業概要

  1. ダウンロード
  2. インストールして設定

作業詳細

  1. ダウンロード

    1. 下記のリンク先にアクセするする。
    2. 「ダウンロード(macOS用)」をクリックする。

    スクリーンショット 2020-01-29 12.20.12.png
    1. ダウンロードが開始される。

    スクリーンショット 2020-01-29 12.21.39.png

  2. インストールして設定

    1. zipで取得したインストーラーを解凍する。
    2. 下記のウインドウが出たら「開く」をクリックする。

    スクリーンショット 2020-01-29 12.24.35.png
    1. パスワードの入力を求められたらパスワードを入力する。

    スクリーンショット 2020-01-29 12.25.56.png
    1. 「LOGICOOL OPTIONのインストール」をクリックする。

    スクリーンショット 2020-01-29 12.26.18.png
    1. 製品強化にご協力くださいの画面で「いいえ、共有しません」をクリックする。

    スクリーンショット 2020-01-29 12.28.42.png
    1. 下記の画面が出るので待つ。

    スクリーンショット 2020-01-29 12.30.51.png
    1. 待っていると下記画面出るのでログインはお好みで実施する。ログインしなくても十分に使用できるがデバイスの設定を引き継げるらしいのでログインした方が良いかもしれない。

    スクリーンショット 2020-01-29 12.32.11.png
    1. すでにデバイスを接続している場合はデバイスの説明が始まる。

    スクリーンショット 2020-01-29 12.33.21.png
    1. まだデバイスが登録されていない時はデバイスの登録が画面の案内に沿って実施される。

logicool option起動後にウインドウが黒画面になり一向に進む気配がない時

余談

  • logicoolのキーボードである「craft」を自分のmacbook proに接続して設定したところmacの設定からJISにしてたがUS配列として認識されていた。
  • logicool optionを導入し接続したところJIS配列として入力できるようになった。
  • 家にある全てのデバイスを登録してみたらデバイス選択画面が充実してニヤニヤが止まらない。

スクリーンショット 2020-01-29 12.46.36.png

enum属性をもつカラムの値を取得する [初心者][rails]

$
0
0

enum属性をもつカラムの値を取得したい

モデルに記述するこういうのです:point_down_tone2:

enumstatus: {error: 0,shipping: 1,completed: 2,}

errorはなんらかの不具合、shippingは配送中、completedは配送完了

ちなみにstatusカラムの error: 0
errorがkey
0がvalue

key取得方法

上記のようなstautsカラムをもつOrderモデルで

Order.shipping?

で取得可能
enumの便利なメソッドです:thumbsup_tone2:

間違えた例

Order.status.shipping?

と記述してしまいエラーになっていました

HTMLメールで画像を載せる [rails][初心者]

$
0
0

HTMLメールに画像を載せたい

すでにメール送信はできるけど、画像がうまく表示されない

これを記述する:point_down_tone2:

mailer.rb
attachments.inline['画像file名']=File.read('app/assets/images/画像file名')

おそらくここの部分'app/assets/images/画像file名'
はpublic配下とかでも大丈夫だと思います。

mailer.rb
defsend_when_creater(user)attachments.inline['vegetable.png']=File.read('app/assets/images/vegetable.png')@user=usermailto: user.email,subject: "こんにちは"endend

mailer view

画像を表示したいところに記述しましょう:point_down_tone2:

html.erb
省略
<body>
  <%= image_tag attachments['vegetable.png'].url, alt: 'Vegetable' %>
</body>

メール結果

こんにちは_-_ryosukedapyon_gmail_com_-_Gmail.png

うまく表示できました。
いろいろな記事を参考にしましたが、railsガイドを参考にしています。
もっと綺麗な方法やhelperを使ったやり方もあるみたいなので、参考にしたいと思いました。

ゼロからつくる、ES6+Babel7でJestによるフロントエンド用アプリのテストを動かすまでハンズオン

$
0
0

概要

  • JavaScriptのテストフレームワークJestをES6+Babel7の環境で使う方法について書きます
  • 仕掛けを理解するために、ゼロからnpmプロジェクトを作っていきます

npmプロジェクトを作る

mkdir babel7jest
cd babel7jest 
npm init

npm initしたらエンターを10回たたけばOK。以下のようなpackage.jsonができる。

package.json
{"name":"babel7jest","version":"1.0.0","description":"","main":"index.js","scripts":{"test":"echo \"Error: no test specified\"&& exit 1"},"author":"","license":"ISC",}

インストール

関連モジュールのインストールをする。

Babelのインストール

npm install--save-dev @babel/core @babel/preset-env

Jestのインストール

npm install--save-dev jest babel-jest

ぜんぶで4つのモジュールをインストールしたので、package.jsonは以下のようになった

package.json
{"name":"babel7jest","version":"1.0.0","description":"","main":"index.js","scripts":{"test":"echo \"Error: no test specified\"&& exit 1"},"author":"","license":"ISC","devDependencies":{"@babel/core":"^7.8.4","@babel/preset-env":"^7.8.4","babel-jest":"^25.1.0","jest":"^25.1.0"}}

さて、インストールしたモジュールは以下のような役割をもっている

モジュール名役割
1@babel/coreBabelの本体
2@babel/preset-env指定したターゲットに合うように
「よしな1」にコード変換(transpile)してくれる
3jestFacebookが開発したJavaScript(とその仲間達)用の
テストフレームワーク
4babel-jestテスト実行時にBabelの設定ファイルを
読み込んでコードを変換する

ソースコードを書く

srcディレクトリを作ってES6文法で以下のようなコードを書いた。

hello.js
import{greetings}from"./words";exportdefaultclassHello{constructor(){}sayHello(){returngreetings;}}
words.js
exportconstgreetings='Hi, there!';

words.jsでは定数を定義しており、それをhello.jsにあるHelloクラスのsayHelloメソッドで返す というシンプルな構成。
わざわざword.jsを外だししているのはES6らしくimport文を使いたかった為。

ここまででディレクトリ構成

ディレクトリ構成
babel7jest
├── node_modules
├── src
│   └── hello.js
├── package.json
└── package-lock.json

Babelの設定ファイルを書く

Babelの設定ファイル babel.config.jsを準備する。

babel.config.js
module.exports={presets:[['@babel/preset-env',{'modules':'false','useBuiltIns':'usage','targets':'> 0.25%, not dead',}]],};

ここまでのディレクトリ構成

ディレクトリ構成
babel7jest
├── node_modules
├── src
│   ├── hello.js
│   └── words.js
├── babel.config.js
├── package.json
└── package-lock.json

ここでは、 "targets": "> 0.25%, not dead"の部分で、「市場シェアが0.25%を超えるブラウザーで実行可能な最低限のコード出力せよ」と指定している。
(こうすることで、BabelはES6文法で書かれたJavaScriptコードをES5文法にコード変換してくれたりする。、詳しくはこちらの記事などを参照)

ちなみに、Babelの設定ファイルはいくつかの書き方があり
babel.config.jsを書く、.babelrcに書く、webpack.config.jsの中のbabel-loader設定内に書く、などいろんなパターンが許されている。ただし、Jestを使うときは、babel.config.jsまたは.babelrcに書くのが正解。もしwebpack.config.jsに書いていたら、babel.config.jsまたは.babelrcに外だしする。理由は、さきほどインストールしたbabel-jestがJestでテストを実行しにいくとき、babel.config.jsまたは.babelrcを読みに行く為。

Jestの設定ファイルを書く

次は、
テストコードを書く前に、Jestの設定ファイルである jest.config.jsを作る

jest.config.js
module.exports={verbose:true,testMatch:["**/test/**/*.test.js"],};

ここでは、testMatchで、テストケースのファイルがtestディレクトリ以下にあること、*.test.jsという名前であることを設定している。

(他の詳しい設定については公式参照)

ここまでのディレクトリ構成

ディレクトリ構成
babel7jest
├── node_modules
├── src
│   ├── hello.js
│   └── words.js
├── babel.config.js
├── jest.config.js
├── package.json
└── package-lock.json

Jestをつかったテストコードを書く

testディレクトリを作り、その中にhello.test.jsというファイルを作る

hello.test.js
import{defaultasHello}from'../src/hello'test('greeting#sayHello returns hello',()=>{constgreeting=newHello();expect(greeting.sayHello()).toBe('Hi, there!');});

このテストコードは、HelloクラスのsayHelloメソッドが'Hi, there!'を返すことを期待するテストケースとなる

ここまでのディレクトリ構成

ディレクトリ構成
babel7jest
├── node_modules
├── src
│   ├── hello.js
│   └── words.js
├── test│   └── hello.test.js
├── babel.config.js
├── jest.config.js
├── package.json
└── package-lock.json

package.jsonのテスト起動用スクリプトを変更する

package.jsonのscriptsを以下のように変更する

package.json(変更前)
"scripts":{"test":"echo \"Error: no test specified\"&& exit 1"}

package.json(変更後)
"scripts":{"test":"jest"}

これで、npm testでJestでテストができるようになる

npm test

とすると、見事にエラーになる。

> babel7jest@1.0.0 test babel7jest
> jest

 FAIL  test/hello.test.js
  ● Test suite failed to run

    Jest encountered an unexpected token

    This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.

    By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".

    Here's what you can do:
     ・ To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
     ・ If you need a custom transformation specify a "transform" option in your config.
     ・ If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.

    You'll find more details and examples of these config options in the docs:
    https://jestjs.io/docs/en/configuration.html

    Details:

    babel7jest\test\hello.test.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import { default as Hello } from '../src/hello';
                                                                                             ^^^^^^

    SyntaxError: Unexpected token import

      at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1059:14)

Test Suites: 1 failed, 1 total
Tests:       0 total
Snapshots:   0 total
Time:        1.64s
Ran all test suites.
npm ERR! Test failed.  See above for more details.

Unexpected token importなどと表示されてエラーになった原因は、JestはCommonJSに従っていない構文(例:ES6のimport文など)を解釈できないため。そこで次のステップでCommonJSに従うようにする。理屈がわかっていれば、そんなに大変ではない。

JestはCommonJS形式のコードしかテストできないので、CommonJS形式に変換する

Jestではテスト実行にnode.jsをつかうので、CommonJSのお作法に従う必要がある。

CommonJSのモジュール管理ではrequire構文をつかうが、
さきほど書いたhello.jsではES6より導入されたimport文によるモジュール管理をつかっている。

そこで、本番向け開発はいままでどおりES6で書いて、Jestでテストするときには、CommonJS形式にしよう、というのが良くやられている。

CommonJS形式にするコード変換はBabelにやらせようというのが今回のポイントとなる。

babel.config.jsにJest用の設定を追記する

さて、テストのときだけ(Babelが)CommonJSに変換してからJestを実行するには、babel.config.jsを以下のようにする。

babel.config.js
module.exports={presets:[['@babel/preset-env',{'modules':'false','useBuiltIns':'usage','targets':'> 0.25%, not dead',}]],env:{test:{presets:[['@babel/preset-env',{targets:{node:'current'}}]],},},};

ポイントは以下の部分

env:{test:{presets:[['@babel/preset-env',{targets:{node:'current'}}]],},},

これは環境変数NODE_ENVtestだった場合に有効になる設定となる。
さらに、その後のpreset-env以下でnode: 'current'としているが、この設定によって現在のnode.jsにあわせてトランスパイルすることを意味している。

つまり、NODE_ENVtestだった場合は、Babelpresett-envが「よしな」に現在のnode.js(CommonJS)にあわせたコード変換をしてくれるということ。先に書いたとおりJestnode.jsで動くのでnode.js用にコード変換してもらえれば無事Jestでテストを動かすことができるようになる。

JestをつかうとNODE_ENVはデフォルトで'test'にセットされる

前述の例でNODE_ENVtestだったときの設定を、babel.config.jsに書いたが、Jestを使う時に実行するときに環境変数を明示的にtestになくてよい。

それはJestが

Jestのソースより
if(process.env.NODE_ENV==null){process.env.NODE_ENV='test'}

のようにしており、NODE_ENVに値がセットされていないときは、自動的にNODE_ENV=testになるため。

preset-envでnodeを指定していれば、追加のプラグイン指定は不要

上のように、

presets:[['@babel/preset-env',{targets:{node:'current'}}]],

を指定してpreset-envが現在のnode.js用のプラグインをよしなに導入してくれるので、
マニュアルで@babel/plugin-transform-modules-commonjsプラグイン2を指定する必要はない。

preset-env勝手に親切にも@babel/plugin-transform-modules-commonjsを取り込んでくれる)

ということで、できあがったbabel.config.jsを再掲する

babel.config.js
module.exports={presets:[['@babel/preset-env',{'modules':'false','useBuiltIns':'usage','targets':'> 0.25%, not dead',}]],env:{test:{presets:[['@babel/preset-env',{targets:{node:'current'}}]],},},};

これでオッケー。

Jestを実行する

npm test

テストが、無事実行された

image.png

まとめ

  • ES6で書かれたフロントエンドアプリを想定して、そこでJestによるテストを書くための準備について説明しました
  • 記事内のソースコードはこちらにおいてあります https://github.com/riversun/es6_babel7_jest

  1. Babel本体にはコード変換の機能は無い。コード変換はBabel用のプラグインが行うもので、本来は変換先のターゲット(たとえばIE11対応とか)に合わせて自前でプラグインを指定しないといけない。しかしそれではあまりに面倒なので、preset-envを指定しておくと、preset-envが気を利かせて変換先ターゲットに向けたコード変換に必要な各種プラグインを導入してくれるというカラクリになっている。「プリセット」という名前の通りある程度のメジャーな想定で作られており万能というわけではないが、たいていは事足りるレベルで変換してくれる。 

  2. 古くはbabel-plugin-transform-es2015-modules-commonjsプラグイン 

Hueを使って照明の色で天気予報を認識する

$
0
0

1. 億劫なこと

毎日、テレビやスマホで天気予報を確認して服装の選択や傘の有無を考えるのがめんどくさい。

2. やりたいこと

当日の天気予報をAPIで取得し、天気・温度に応じて室内照明(Hue)の色を点灯させたい。
想定する手順は以下の通り。

  1. 気象情報APIによって、当日の情報(天候と気温)を取得する
  2. 取得した天気の情報を元に、照明の色を変化させる

3. 環境

  • node version : v8.11.3
  • Philips Hue Go + ブリッジ

4. 実装

4.1 準備

モジュールのインストール。

    $ npm install request

4.2 気象情報APIの利用

今回は無料のAPIを使いたかったため、openweathermapを利用した。
HPから利用登録してAPPIDを入手。

天気の情報は以下のAPIによってGETできる。

    http://api.openweathermap.org/data/2.5/weather?zip=[郵便番号],JP&units=metric&APPID=[APPID]

コードは以下の感じ(郵便番号とAPPIDは任意に設定)。

weather.js
    // ▼▼天気情報を取得(openweathermapのAPI)▼▼
    var request = require('request');

    // API情報(zip_codeとwAPPIDは任意)
    var wbaseurl = "http://api.openweathermap.org/data/2.5/weather";
    var zip_code = "100-0005,JP";   //東京駅の郵便番号
    var wAPPID = [任意のID];
    var openweather_api = wbaseurl + "?zip=" + zip_code + "&units=metric&APPID=" + wAPPID;
    var options_openweather = {uri: openweather_api, method: 'GET'};

    function openweather_get() {
        request(options_openweather, function (error, response, body) { 
            var temp_json = JSON.parse(body).main.temp;
            console.log("本日の気温:" + temp_json + "度");
            var weather_json = JSON.parse(body).weather[0].main;
            console.log("本日の天気:" + weather_json);
        });
        return
    }
    openweather_get()

4.3 Hueの制御

  1. HueのAPIについて
    Hueの登録とAPIは公式ページを参考にして登録を行った。

  2. HueのAPI制御
    次に、HueのAPIを制御するために以下のようなコードを書いた(ipaddressとusernameは任意に設定)。

hue.js
    // ▼▼Hueの制御▼▼
    var request = require('request');

    // HueのAPI情報(ipaddressとusernameは任意)
    var hue_uri = "http://[ipaddress]/api/[username]/lights/1/state";

    // Hueを「白」に光らせる
    var hue_headers = {"Content-type": "application/json"};
    var white = {"on":true, "bri":144, "hue": 22612, "xy":[0.3146,0.3303], "effect": "none", "sat":171};
    var options_W = {uri: hue_uri, method: 'PUT', headers: hue_headers, json: white};
    function white_hue() {
        request(options_W, function (error, response, body) { console.log(body);})
        return
    }
    white_hue()

色は「白」以外にも、条件に応じて様々なパターンを作成した。

4.4 条件の設定

4.4.1 温度情報に応じて色を変化

温度ごとの条件は以下のように設定した。

   30度以上 → 赤色に点灯
   20度以上で30度未満 → 緑色に点灯
   10度以上で20度未満 → 水色に点灯
   10度未満 → 青色に点灯

4.4.2 天気情報に応じて色を変化

APIで取得できる天気の条件は以下。

晴:"Clear", 曇:"Clouds", 雪:"Snow", 雨:Rain, 雷雨:"Thunderstorm", 霧雨:"Drizzle"

これを元に、天気ごとの条件を設定した。

晴れ or 曇り → 白色に点灯
   それ以外(雨や雪) → 紫色に点灯

4.5 実行

天気情報APIの取得コードとHueの制御コードを、条件設定に合わせて一部改修して実装した。

写真は温度が寒く、天候が晴れの時の様子。

clear.png

温度と天候の照明色は、30秒ごとに交互に点滅するようにした。
正常な動作を確認できたのでサーバーに実装し、毎日の外出時刻に合わせて点灯するように設置した。

5. まとめ

照明の色を見るだけで朝の支度ができるようになった。
理想は勝手に服や傘が準備されていることなのだが(笑)
でも、夕方の雨予報などはわからない、、、もっと良い使い方を検討してみたい。


Development on AWS受講までの事前準備 in MacPC

$
0
0

概要

AWSトーニング受講にあたり、事前準備として自前のMac端末に色々導入した時のログを残す

目的

・最低限の開発環境をここで揃えるようにする
・開発の初歩の初歩で詰まる方向け
・アウトプットの練習

何ができればよいのか

まず、事前に用意すべき環境は
①RDPクライアントからWindowsサーバーへの接続
②Linuxサーバーへの接続

その他用意した方が良さそうなもの
③Homebrewのインストール

とりあえず上記3つができればよい事にする

①RDPクライアントからWindowsサーバーへの接続

こちらを参考にダウンロードと手順に従い、MacからWindowsへリモートデスクトップ接続をできるようにする。
https://pc-karuma.net/mac-app-microsoft-remote-desktop/

詰まりポイントは特にないはず。

②Linuxサーバーへの接続

こちらも、Windowsの場合はTeratermなどの専用のターミナルを用意する必要があるが、幸いMacには標準のターミナルが用意されている
そのため、以下を参考にsshログインができれば大丈夫
https://qiita.com/HonwakaDeveloper/items/d31e5c19751644129efc

③Homebrewのインストール

Mac上で様々なパッケージをインストールするには、Homebrewのインストールが必須である。(macのターミナルを使うのであれば、最低限これは入れておきましょう)
これが少しだけ事前準備に時間がかったのだが、まず、以下を参考にHomebrewのインストールを行う。
https://qiita.com/rabbit1013/items/1494cf345ff172c3b9cd

Homebrewのインストール時にパスワードが通らない時の対処法

原因①:Xcodeがインストールされていない

→Xcodeを以下を参考にインストールしましょう(初期状態だとこれは入っていないらしい)
MacのOSのバージョンによっては、最新版が入らない可能性があるので注意
https://qiita.com/rabbit1013/items/edd6544653bb87858cde

原因②:rootユーザが有効になっていない

→rootのパスワードが通らない場合は、そもそもrootユーザが有効になっていない場合があります。その場合は、以下を参考にrootのパスワードを設定します
https://pc-karuma.net/root-user-enable-disable/

終わりに

macとは言え、環境構築は慣れないと大変時間がかかるもので、今回は準備に2時間程かかってしまったが、今後は無駄を無くして構築にかける時間を少しでも短縮できるようにしていきたい。

あなたはまだGitを使いこなせていない

$
0
0

はじめに

私事ですが、最近エンジニアに転職しました
入社後、色々学んできた中でGitについて改めて便利やな〜と感じたので、
そのことについてまとめてみようと思います

まず、入社前の私の状態について軽く説明します。
Gitをバージョン管理というよりは、ソースコードのバックアップのために使っていました
本当にpushとpull以外では使っていませんでした笑
なので、Gitについて基本的な概念を大雑把に理解している感じです
具体的には

  • GitとGitHubって別物なんや!!
  • リポジトリはリモートとローカルがあるんか〜
  • addしたら変更履歴がインデックスに上がるんか〜  などなど

こんな感じです笑

ですが、開発をしているとコンフリクトは起こるし、前のバージョンで確認したいことはあるしで、Gitを個人のバックアップ用に使っていると訳がわからないことになしました
そこでGoogle先生にはだいぶお世話になりました。
今回はそのときにGoogle大先生から教わったGitのことについてまとめようと思います。

基本操作

まず、基本操作について説明します
大きな流れとしてはgit initからgit pushまでです

ディレクトリをGitの監視下に置く

このコマンドでファイルの変更の監視を開始します

ターミナル
git init

リモートリポジトリの追加

リモートリポジトリ(GitHubなど)を追加する
gitのプロトコル(通信方式)はLocal、HTTP、Secure Shell (SSH)、Gitがあるらしいです
今回はgitを使ったコマンドを例に記載しておきます
他のプロトコルについては他の記事をご参考ください。

ターミナル
git remote origin git@github.com:xxxxxx/xxxxx.git

インデックスにファイルを追加する

ステージングと呼ばれる作業です。
インデックスにあるファイルがコミットの対象になります。

ターミナル
git add xxx.php

コミット

インデックスにあるものをローカルリポジトリに反映させる
コミットメッセージが本当に大切だから意識して書くようにするといいと思います。

ターミナル
git commit -m "first commit"

リモートリポジトリにローカルリポジトリを反映させる

リモートリポジトリoriginにローカルリポジトリbranch1を反映させます

ターミナル
git push origin branch1

以上がgit initからgit pushまでの一連の流れになります。

チーム開発

次に、コンフリクトが起こった時の対処法について解説します。
コンフリクトとは同じファイルの同じ箇所を違う人が編集することがよく起こります
Gitがどちらの変更を反映させたらいいかわかりませんという状態です。
普段はGitがいい感じにやってくれるのですが、Gitでは判断出来ないものはコンフリクトとして報告してくれます
では、実際にコンフリクトが発生した時の対処法について解説します。

ソースコードの編集が終了し、pushしようとします。

ターミナル
git add
git commit -m "commit message"
git push

pushしようとするとコンフリクトが発生し、pushできません。
そうした時に変更された内容を吸収しないといけません。変更を吸収するためにpullします。

ターミナル
git pull

pullした後、コンフリクトが発生した箇所でこのような記述があります
この記述を参考に編集して再度pushします。

<<<<<<< HEAD

# 作業ブランチでの変更内容

=======

# hogebranchでの変更内容

>>>>>>>hogebranch
ターミナル
git push

するとリモートリポジトリに他の人の変更と自分の変更がいい感じにくっついて履歴として保存されます。

ある時点のコミットした状態に戻る

Gitを使っているのであれば、あるコミットの時点に戻りたいということも可能です。
開発を進めていると原因がよくわからないバグが発生します。
その時にこのバグがいつからあったのかを調べないと原因の切り分けがしにくい時があります。
是非覚えておきたい手法です。

まず、あるコミットの時点にどういう名前で保存されているかを調べます

ターミナル
git reflog

// 実行結果
7ea6663 (HEAD -> master, origin/master, heroku/master) HEAD@{0}: commit: Update production.rb
16780b4 HEAD@{1}: pull --progress origin: Fast-forward
7843f1c HEAD@{2}: checkout: moving from pg-install to master
7863c5b HEAD@{3}: commit: add pg

上記のような結果が出てくると思います。

次に、戻るコマンドを叩きましょう
ここで注意ですが、戻ってしますとコミットしていない変更点は消えてしまいます
なので、消えて欲しくない変更はaddしてcommitしておきましょう

本題に戻ります。例えば、、、
HEAD@{3}に戻りたいときは以下のコマンドです
resetにはhard,mixed,softの3種類のオプションがあります
これらのオプションについてはまた興味がありましたら調べてみてください。
今回使用する--hardは簡単にいうと全部消えるので注意してください

ターミナル
git reset --hard HEAD@{3}

これでローカルのフォルダも変更されています。
慣れないうちはあまり触りすぎないことをオススメしますめんどくさいことになるので、、、

最後に、最新の状態に戻しましょう
やり方は同じです
reflogでコミットのハッシュを確認しましょう

ターミナル
git reset --hard HEAD@{0}

で元に戻りましょう

以上です!!!
ここまで読んでいただきありがとうございました!!
疑問、気になるところがございましたら、質問、コメントよろしくお願いします!!!

オブジェク指向

$
0
0

オブジェクト

  • 関連する変数(値)と関数(動作)が一つにまとまり、そのまとまりに名前がついたもの。
    • 関連した変数や関数を「一つのオブジェクト内」で宣言することで、管理しやすくなる。
    • オブジェクトには「クラス」「インスタンス」と言う2つの側面がある。
  • クラス
    • 設計図。オブジェクトを作るには、まずクラスを宣言する必要がある。
    • 設計図なので、どんな変数(値)でどんな関数(動作)にするのか考えて、クラス内部で宣言する。
    • 関連した変数や関数はこの時点(クラス)で決定。
  • インスタンス

    • クラス(設計図)から生成された実体。モノ。
    • 設計図だけあっても関数を使うことができないので、クラスから実体を生成する。
  • メモ

<?php
$today = new DateTime();
print($today -> format('G時 i分 s秒'));
?>
  • $today と format は ->で繋がっている
    • これは$todayと言うDateTimeメソッドの、インスタンスのメソッドを使っている
  • formatメソッドの使い方
    • dateとだいたい同じ
    • ()の中のパラメーター(例の場合は時間)をそれぞれ求めてフォーマット化してくれるメソッド

変数で計算結果を保管

$
0
0

変数

  • PHPの場合、変数名を$から始める必要がある
    • 変数は$から初めて、英語や英語_数字などで作成する
    • 例:$abc$abc_123
      • $合計などの日本語も一応使えるけど基本的に使わない
  • 記号や空白が含まれていたり、先頭が数字の場合は使えない
  • 大文字小文字の設定は自由だけど、基本的にPHPの変数は小文字で書いたほうがいい
    • 変数名は小文字と大文字を完全区別するので、一部でも異なると「別の変数」と見なされてしまうので注意
    • 例えば全て小文字の場合、一部を大文字にすると別の変数となってしまう
  • 変数は、最初に『代入』と言う操作を行う
<?php $sum = 100+1050+200; ?>
  • 変数名(上記の場合は$sum)の次に=を書き、その後に記憶したい内容や、保管したい内容を記述する
  • ルールはprintのパラメーターと同じで'(クォーテーション記号)を入れてあげるとそのまま文字列として記憶される
    • クォーテーション記号がなければ計算式として「計算結果」を代入してくれる
  • 格納した変数を使いたい場合は=を使わず変数名だけを記述する
  • 変数を使うメリット
    • 何度も同じ計算式を使う場合にわかりやすくなる
    • 計算式が何を意味しているのわかりやすくなる

[AtCoder Beginner Contest 152-D問題]を解く!

$
0
0

記事の概要

今回解くのはABC152-D問題。最初問題を読んでも全く意味がわからず、解説を読んでも理解することに時間がかかった。今は理解しているが少し経てばどうせ忘れるので自分の考えをまとめておこうという魂胆である。

問題

正の整数 N が与えられます。
N 以下の正の整数の組 (A,B)であって、次の条件を満たすものの個数を求めてください。

[条件]
A,Bを先頭に 0 のつかない 10 進数表記で表したときに、 A の末尾の桁が B の先頭の桁に等しく、 A の先頭の桁が B の末尾の桁に等しい

[制約]
- 1≤N≤2×105
- 入力はすべて整数である。

[入力]
N

考え方

まず条件を見てみよう。数字の最初の一桁と最後の一桁を入れ替えたやつがペアになる(間は何だろうと関係ない)ということなので例えば(12,21)や(102,221)になる。少し特殊な例だと(1,1)や(1,11)もペアである。要するには最初の一桁(1~9)と最後の一桁(0~9)を管理して、同じものをひとまとめにすれば良い。例を挙げると(12,102,112,122,132)はどれも最初が1で最後が2なので区別する必要がないのである。なら二次元配列[最初の数字][最後の数字]で管理できると考えられる。

for(inti=1;i<=n;i++){intv=static_cast<int>(log10(i));intmax=i/pow(10,v);//最初の一桁intmin=i%10;//最後の一桁number[max][min]++;}

最後の一桁は10で割ればあまりで出てくるから簡単。最初の一桁は少しめんどくさくて、まずlogで桁数-1を求めて、10の桁数-1乗で割れば商で出てくる。二次元配列には最初の一桁と最後の一桁が同じ数字の個数がカウントされていく。
しかしこれではまだ答えになっていない。number[1][2]とnumber[2][1]をペアにしないといけない。Nを150と考えるとnumber[1][2]には(12,102,112,122,132,142)の6が格納されている。一方number[2][1]には(21,201,211,221,231,241)の6が格納されている。ペアの総数は組み合わせで出るので6*6=36ということになる。要するにnumber[max][min] * number[min][max]の総和である。

解答例

handstand2.cpp
#include <bits/stdc++.h>
usingnamespacestd;intmain(){intn,ans;cin>>n;intnumber[10][10];for(inti=0;i<10;i++){for(intj=0;j<10;j++){number[i][j]=0;}}//最初の一桁と最後の一桁が同じ数字をひとまとめにして個数を格納for(inti=1;i<=n;i++){intv=static_cast<int>(log10(i));//最初の一桁intmax=i/pow(10,v);//桁数計算intmin=i%10;//最後の一桁number[min][max]++;}//ペアの総数計算for(inti=0;i<10;i++){for(intj=0;j<10;j++){ans+=number[i][j]*number[j][i];//組み合わせ}}cout<<ans;return0;}

最後に

書いている時はすごく考えがまとまっているけど、時間が経って読み直す時は何言ってんだこいつってなりそう。ちょっとしたら読み直して修正します。読んでくれたみなさんありがとう。

Viewing all 21239 articles
Browse latest View live