27. You Don’t Know JS: Up & Going Chapter 1: Into Programming
【所要時間】
8時間24分(2018年7月23,24日)
【概要】
プログラミングについて
プログラムの基本的な原則を学ぶ。
【要約・学んだこと】
Code
JSはブラウザのdeveloper consoleに直接タイプすることもできるが、通常コードはテキストファイルに保存される。
有効なフォーマットや指示の組み合わせルールは、コンピューター言語、またはシンタックスと呼ばれる。
Statements
コンピューター言語では、特定のタスクを実行する単語、数字、演算子のグループのことをstatement(ステートメント)という。
a = b * 2;
このstatementでは、
a, b: variables(変数)
2: value(値)
=, *: operators(演算子)
と呼び、ほとんどのJSのstatementは、さいごに ; を打つ。
このstatementではvariable bに格納されている値を取得し、value 2をかけ、variable aに結果を格納するような感じ。
Expressions
statementは1つ以上のexpressionsで作られる。expressionはvariableかvalueの参照、またはvariableとvalueを組み合わせた変数のセットである。
a = b * 2;
このstatementには4つのexpressionがある。
- 2 は文字通りvalue expression
- b は現在のvalueを取得するvariable expression
- b * 2 は掛け算をするarithmetic expression
- a = b * 2 はb * 2 の結果を、variable a に割り当てる、assignment expression
単独で存在するgeneral expressionはexpression statementと呼ばれる。
b * 2;
これはプログラムを動かすのに影響を与えないので、一般的ではなく、あまり使われない。b に2をかけるという意味だが、結果として何も起こらない。
より一般的なexpression statementは、
alert( a );
statement全体でexpression自体を呼ぶ機能があるもののことである。
Executing a Program
どうやってprogramming statementsをコンピュータに何をするか伝えるのか。プログラムはexecute(実行)される必要がある。
a = b * 2 のようなstatementsは、実際にコンピュータが理解できるフォームではない。コンピュータはコードをコマンドに翻訳することで理解できる。
いくつかのコンピュータ言語では、コマンド翻訳が上から下へ、行ごとにプログラムを実行する。これはコードをinterpreting(解釈)するという。
他のコンピュータ言語では、翻訳は事前に行われ、プログラムは後で実行する。これはコードをcompiling(編集)するという。
JavaScriptは通常ソースコードが実行されるたびに処理されるため、interpretingされると言われている。しかし、JavaScriptエンジンは即座にプログラムをcomplingし、complingされたコードを実行している。
Try It Yourself
Output
console.log(..)
: これはdeveloper consoleにテキストをプリントする方法。- log( b ): function call という。b variableをfunctionに渡し、b valueをとり、コンソールに出力するように求めている。
- console. : log(..) functionがどこにあるか探すオブジェクト参照。
outputの他の作り方は、 alert(..) statementがある。
このstatementでは、consoleではなくpopup “OK” boxとb variableが表示される。
一度にたくさんのvalueをoutputするとブラウザの邪魔になるので、通常はconsole.log(..) を使う。
Input
HTMLページではJSを使ったフォームelementsをよく見かけるが、ここではよりシンプルなprompt(..) functionを学ぶ。
age = prompt( "Please tell me your age:" );
console.log( age );
prompt(..) : この場合、Please tell me your age: をポップアップに表示させる。
console.log(..) : インプットテキストに入力し、OKをクリックすると、入力内容がageに保存され、console.log(..)に出力される。
Operators
operatorsはvariableやvalueがどのような動きをするかを決める。
* : 掛け算せよ
= : =の右側を計算し、左側にvariable(target variable)を置く。
JavaScriptでは a = 42のように、variableを = の左側に置く必要がある。42 = a とはできない。最近の他のプログラミング言語でも同様であることがほとんど。
全てのプログラムに var が必要。これはvariableをdeclareする主な方法。
それぞれのscopeで1回宣言すれば良い。
var a = 20;
a = a + 1;
a = a * 2;
console.log( a ); // 42
- Assignment: =
- Math: +,− ,* , /
- Compound Assignment: +=, −=, /= はmath operationとassignmentのcompound operators a +=2 は a = a +2という意味。
- Increment/Decrement: ++(increment), — (decrement) a++ は a = a+1と似たような意味。
- Object Property Access: console.log() の .
Objectsはpropertyと呼ばれる特定の名前の場所にある他のvaluesをもつvalue。
obj.a はobj と呼ばれるvalueと、a というプロパティを意味する。
propertyはobj[“a”]としてもアクセスすることができる。 - Equality: a == b のようにに使われる ==(loose-equals), ===(strict-equals), !==(strict not-equals)
- Comparison: a≤b のように使われる。 < (less than), > (greater than), ≤ (less than or loose-equals), ≥ (greater than or loose-equals)
- Logical: a || b で使われる。(これはa or b という意味。)&& (and), || (or)
詳しくはsee the Mozilla Developer Network (MDN)’s “Expressions and Operators” (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators).
Values & Types
異なるvaluesの表現は、プログラミング用語でtypeと呼ばれる。JSはprimitive valueと呼ばれるbilt-in typeがある。
- 計算 : number
- valueを画面に表示: string (一文字以上の文字、単語、文)
- 何かを決める時: boolean (true or false)
ソースコードに直接含まれるvalueはliteralと呼ぶ。 string literalsは “…” または (‘…’)と記述する。
Converting Between Types
number を持っていて画面に表示する場合、valueを string に変換する必要がある。JSではこの変換を coercion と呼ぶ。
JSはtypeを矯正するために、いくつかの異なる機能を提供する。
var a = "42";
var b = Number( a );
console.log( a ); // "42"
console.log( b ); // 42
JSはときにマッチしたtypeにimplicit concern(暗に強制)する。
“99.99” == 99.99 の場合、JSは左側の”99.99”をnumber 99.99と同義とする。よって、99.99 == 99.99 となる。
一方で、ルールをしっかり学ばなければこれは混乱を招く。多くのJSディベロッパーはimplict concernは予期せぬバグを呼び起こすものだと感じている。
しかし、これを学べば混乱をさけるだけでなく、いいプログラムを書けるようになる手助けとなる。
Code Comments
正しく動作するプログラムを書くだけでなく、検査した時に意味のあるプログラムをつくるべきだ。そのため、variable や function にはわかりやすい名前をつけるようにする。
そして、コンピュータではなく人間に説明するためのテキストとなる、code commentsも重要になる。interpreter も compilerもいつもこれらのコメントを無視する。
- コメントなしのコードは最適ではない
- コメントが多すぎるのはよくないコードという証とも言える
- コメントはwhatではなくwhyを説明する。特別必要な場合のみhowを書いても良い。
JSのコメントは下記のように // (1行のみ), /* から始めて */ で閉じる。後者は複数行や、行の途中からでも記述可能。
// This is a single-line comment
/* But this is
a multiline
comment.
*/
Variables
多くの有用なプログラムは、意図されたタスクに要求される異なる操作をうけ、プログラムの過程で変わったvalueを追う必要がある。
最も簡単な方法は、variableと呼ばれるsymbolic containerにvalueを割り当てることだ。なぜならcontainerのvalueは必要に応じて時間とともに変化するかもしれないからだ。
プログラミング言語によっては、特定のvalueタイプをもつために、number や stringのようにvariable(container)を宣言する。static typing(type enforcement)は意図しないvalueの変換を防ぐことで、プログラムの正確さの長所として引用される。
別の言語では、variableの代わりにvalueのタイプを強調する。weak typing(dynamic typing)はvariableがいつでもvalueのタイプを持つことを許可する。プログラムのロジックフローの任意のタイミングで、valueがどのタイプであっても、1つのvariableがvalueを表現できるようにすることが、プログラムの柔軟性をメリットにする。
JSは後者のdynamic typingを使う。variablesはtype enforcementなしで、どんなtypeのvalueも保持できる。
var amount = 99.99;amount = amount * 2;console.log( amount ); // 199.98// convert `amount` to a string, and
// add “$” on the beginning
amount = “$” + String( amount );console.log( amount ); // “$199.98”VM113:5 199.98
VM113:11 $199.98
undefined
amount variableは、number 99.99として始まり、 amount * 2 の結果をnumberとして持つ。
最初の console.log()コマンドは、number valueをstringとして出力するimplicitly coerceを持つ。
amount = “$” + string( amount) は、199.98 value を string にし、$ という文字を最初に加えるexplicitly coercesだ。
JSディベロッパーは amount variableの柔軟性を使い、99.99と199.98、さらに$199.98 value それぞれのvariableとして記述する。
static-typingを使う人は、amountStrといった、個別のvariableを使うことを好む。なぜならtypeが違うからだ。
いずれにせよ、 amountはプログラムの過程で変化したvalueを実行し、variableの最初の目的を表現する。これプログラムのstateを意味する。言い換えると、stateはプログラムの実行のために、valueの変化を追っている。
他に一般的なvariableの使い方は、valueの設定を集中化することだ。これはよくconstantsと呼ばれ、variableとvalueを宣言し、プログラム中でvalueを変化させたくない時に使う。
プログラムの最初でconstants(定数)を宣言することが多い。valueを変える時に、一箇所に行くほうが便利だからだ。通常、JS variableではconstantsは大文字で、アンダースコアが単語の間につく。
これはよくない例です。
var TAX_RATE = 0.08; // 8% sales taxvar amount = 99.99;amount = amount * 2;amount = amount + (amount * TAX_RATE);console.log( amount ); // 215.9784
console.log( amount.toFixed( 2 ) );
VM115:9 215.9784
VM115:10 215.98
undefined
console.log()がconsole valueのオブジェクトプロパティとしてアクセスされるfunction log()と同じように、toFixed()はnumber valuesでアクセスできるfunctionである。
JSの numberは自動でドルにフォーマットされてはいない。エンジンは何を意図しているのかわからないし、通貨としてのタイプはない。 toFixed()はまとめたい小数点以下の桁数を指定し、必要に応じてstringを作る。
TAX_RATE variableは、慣例によりconstant(定数)にすぎない。ただ、もしtax rateが9%になった場合、一箇所のvalueを0.09と指定するだけで、プログラムがアップデートできる。プログラムに出現した回数だけ0.08を見つけ、全て更新する必要がなくなる。
JSバージョンES6以降は、var の代わりに const でconstantを宣言することができる。
// as of ES6:
const TAX_RATE = 0.08;
var amount = 99.99;
// ..
constantは初期設定後に別の場所で謝ってvalueを変えてしまうことを避けることができる。もしTAX_RATEに最初の宣言以降でvalueを変えようとすると、プログラムは変更を拒否する。
ミスを避けるためのprotectionは、static-typingのtype enforcementに似ているため、魅力的である。
さらに詳しくはこのシリーズのTypes & Grammar title 参照。
Blocks
コードでは一連のstatementをグループ化する必要があり、これをblockと呼ぶ。JSではblock1つ以上のstatementを{ } で囲うことで定義される。
var amount = 99.99;
// a general block
{
amount = amount * 2;
console.log( amount ); // 199.98
}
孤立したblockは有効だが、JSでは一般的ではない。blockはif statement やloop statement といった他のcontrol statementにつけられることが多い。
var amount = 99.99;
// is amount big enough?
if (amount > 10) { // <-- block attached to `if`
amount = amount * 2;
console.log( amount ); // 199.98
}
2つのstatementを持つ{}blockは、block内のstatementは、条件が成立する場合のみ処理される。
Conditionals
if statementはよく使われるconditionの1つ。if条件がtrueなら、どうするかを記述する。
var bank_balance = 302.13;
var amount = 99.99;
if (amount < bank_balance) {
console.log( "I want to buy this phone!" );
}
if statementは()で囲うことで、true か false として扱われる。
conditionがtrueでない場合に何かを返したい場合は、 else clause(節)という代わりの方法を提供することも可能。
clearしてもconstはもう一回記述できなかったが、新たなページでやればできた。
const ACCESSORY_PRICE = 9.99;var bank_balance = 302.13;
var amount = 99.99;amount = amount * 2;// can we afford the extra purchase?
if ( amount < bank_balance ) {
console.log( “I’ll take the accessory!” );
amount = amount + ACCESSORY_PRICE;
}
// otherwise:
else {
console.log( “No, thanks.” );
}VM164:10 I’ll take the accessory!
209.97
if以外にも、 switch や loops がconditionにはある。
さらに詳しくはChapter 4 of the Types & Grammar参照。
Loops
あるconditionが失敗するまで繰り返しアクションするように設定すること(conditionが保持できる間のみ繰り返すこと)を, loopsと呼ぶ。
loopはテストconditionとblockを含む。ループブロックが実行される毎、これをiteration(反復)と呼ぶ。
while loop と do..while loopのフォームは、conditionがtrueでなくなるまで、statementのblockを繰り返すというコンセプトを示している。
numOfCustomers = 1;
while (numOfCustomers > 0) {
console.log( “How may I help you?” );//help the customer…numOfCustomers = numOfCustomers — 1;}//versus:do {
console.log( “How may I help you?” );
// help the customer…numOfCustomers = numOfCustomers = numOfCustomers -1;
} while (numOfCustomers > 0);
VM269:3 How may I help you?
VM269:14 How may I help you?
-1
これは numOfCustomers が1の場合。
最初のiterationは while , 2回目以降は do..while を実行する。falseになった時に、その次の動作は行われない。
conditionがfalseなら、while は動作しないが、 do..whileは最初の1回のみ実行する。
numOfCustomers = 0;
while (numOfCustomers > 0) {
console.log( “How may I help you?” );//help the customer…numOfCustomers = numOfCustomers — 1;}//versus:do {
console.log( “How may?” );
// help the customer…numOfCustomers = numOfCustomers = numOfCustomers -1;
} while (numOfCustomers > 0);
VM272:14 How may?
-1
この場合How may?としか返ってこないので、 do..whileが1度だけ実行されているのがわかる。
0~9のような特定の数の集まりを数えるのを目的にloopすることがある。loopのiteration variable(反復変数)をi のように value 0 に設定し、iteration毎に1増やすようにすれば可能。
Warning:
プログラム言語は大抵1からではなく、0から数え始める。
JSの break statementはloopを止めるために使える。break がなければ無限ループするのが観察できる。
var i = 0;while(true) {
if ((i <= 3) === false) {
break;
}console.log( i );
i = i + 1;
}
VM298:9 0
VM298:9 1
VM298:9 2
VM298:9 3
undefined
i が 3を超える時、falseとなる。
whileは手動でタスクを実行できるが、 for loopというsyntactic form(構文形式)もある。
for (var i = 0; i <= 3; i = i + 1) {
console.log( i );
}
VM301:2 0
VM301:2 1
VM301:2 2
VM301:2 3
undefined
for loop は3つのclauseがある。
- var i=0
- i ≤ 3
- i = i+1
for は while do..while より簡単に書ける。
Functions
同じことを何度も繰り返すより、コードのタスクを分割し、再利用したい。それを function と定義する。
functionは名前によって呼び出すことができるコードセクションで、その中のコードは毎回実行される。
function printAmount() {
console.log( amount.toFixed( 2 ) );
}var amount = 99.99;printAmount();amount = amount * 2;printAmount();
VM322:2 99.99
VM322:2 199.98
console.log ( amount.toFixed( 2 ) ) をprintAmount()で呼びだしている。
functionはオプションでarguments(因数、parameter)を渡すこともできる。また、valueを返すことも可能。
function pirntAmount(amt) {
console.log( amt.toFixed( 2 ) );
}function formatAmount() {
return "$" + amount.toFixed( 2 );
}var amount = 99.99;printAmount( amount * 2 );amount = formatAmount();
console.log( amount );VM359:2 199.98
VM363:14 $99.99
function printAmount(..) は amt と呼ぶパラメーターを渡す。 function formatAmount() はvalue を返す。 この2つを同じfunctionにしてもよい。
functionは何度も喚び返すつもりのコードによく使われる。しかし、たとえ一度しか呼ぶことがなくても、名付けられたcollectionに関係するビットコードを編成するだけでもよく使われる。
const TAX_RATE = 0.08;function calculateFinalPurchaseAmount(amt) {
amt = amt + (amt * TAX_RATE);
return amt;
}var amount = 99.99;amount = calculateFinalPurchaseAmount( amount );console.log( amount.toFixed( 2 ) );VM169:8 107.99
calculateFinalPurchaseAmount(..)は一度しか呼ばれないが、2つのfunctionに分けることで、コードが綺麗になる。functionがよりたくさんのstatementを持っていると、より利点があるといえる。
Scope
JSでは、それぞれのfunctionは自身のscopeを得る。scopeは基本的にvariablesのcollectionであり、どうやってvariablesが名前によってアクセスされるかのルールである。コード内のfunctionがfunctionのscoped variablesにアクセスできる。
variableの名前は同じscope内では独自のものにしなければならない。2つのa variablesは隣り合ってはならないが、違うscopeでは同じvariableネームは現れても良い。
function one() {
var a = 1;
console.log( a );
}function two() {
var a = 2;
console.log( a );
}one();
two();
VM403:3 1
VM403:8 2
また、scopeは他のscope内に囲まれても良い。scopeが別のscope内にネストされている場合、最も内側のscope内のコードいずれかのvallueにもアクセスできる。
function outer() {
var a = 1;
function inner() {
var b = 2;console.log( a + b );
}inner();console.log( a );}outer();
VM421:6 3
VM421:10 1
Lexical scopeルールは1つのscopeの中のコードは、そのscopeか外側にあるいずれかのscopeにアクセスすることができるvariablesである。
inner() functionはa と b 両方にアクセスしているが、outer() functionはa にのみアクセスでき、bにはできない。なぜならvariableはinner()の中にあるからだ。
さらに詳しくはこのシリーズのthe first three chapters of the Scope & Closures titleを参照。
Practice
- Write a program to calculate the total price of your phone purchase. You will keep purchasing phones (hint: loop!) until you run out of money in your bank account. You’ll also buy accessories for each phone as long as your purchase amount is below your mental spending threshold.
- After you’ve calculated your purchase amount, add in the tax, then print out the calculated purchase amount, properly formatted.
- Finally, check the amount against your bank account balance to see if you can afford it or not.
- You should set up some constants for the “tax rate,” “phone price,” “accessory price,” and “spending threshold,” as well as a variable for your “bank account balance.””
- You should define functions for calculating the tax and for formatting the price with a “$” and rounding to two decimal places.
- Bonus Challenge: Try to incorporate input into this program, perhaps with the
prompt(..)
covered in "Input" earlier. You may prompt the user for their bank account balance, for example. Have fun and be creative!
という問題。コードを各順に書かれていなくてわかりにくいので整理すると、この手順で書いていけばできるはず。
- constにtax rate, phone price, accessory price, spending thresholdの値段を設定
- bank account balanceをvariableに設定
- functionでtaxとformattingの値段($をつけ、小数点第2位まで)をそれぞれ定義
- bank accountのお金がなくなるまで電話を購入(ループを使う)
またmental spending thresholdを下回る限り電話の数だけaccessoryを購入 - 合計額を計算後、taxを足し、購入金額を正しいフォーマットで表示する。
最後に合計金額がbank account balanceを上回っていないか確認。
const TAX_RATE = 0.08;
const PHONE_PRICE = 979.99;
const ACCESSORY_PRICE = 35.55;
const SPENDING_THRESHOLD = 8000.00;var bank_account_balance = 10000.00;
var amount = 0;function tax(amount) {
return amount = amount * TAX_RATE;
}function formatting(amount) {
return amount = “$” + amount.toFixed( 2 );
}while (amount < bank_account_balance) {
amount = amount + PHONE_PRICE;if (amount < SPENDING_THRESHOLD) {
amount = amount + ACCESSORY_PRICE;
}
}amount = amount + tax(amount);console.log( “Amount” + formatting(amount) );if (amount > bank_account_balance) {
console.log ( “Insufficient balance!” );
}
VM344:27 Amount$10852.65
VM344:30 Insufficient balance!
【わからなかったこと】
最後のpracticeで、
while (amount < bank_account_balance) {
amount = amount + PHONE_PRICE;if (amount < SPENDING_THRESHOLD) {
amount = amount + ACCESSORY_PRICE;
}
}
ここの意味が
- amount(PHONE_PRICE)がbank_account_balanceを下回る限り、購入する。
- amount (PHONE_PRICE + ACCESSORY_PRICE)がSPENCING_THRESHOLDを下回る場合に限り、ACCESSORYも購入する。
という意味で、 このプログラムの答えが
(979.99+35.55)*7+979.99*2
=7108.78+1959.98
=9068.769068.76+(9068.76*TAX_RATE)
=9794.26
になると思っていたが、どこが間違っているのか。
これは
・amount(PHONE_PRICE)がbank_account_balance(10000)を下回る限り、購入する。
ではなく、
・amount(PHONE_PRICE)がbank_account_balance(10000)を上回るまで購入する。
という式である。(問題もそのように言っている。)
もし、
・amount(PHONE_PRICE)がbank_account_balance(10000)を下回る限り、購入する。
としたい場合は、
while ((amount + PHONE_PRICE) < bank_account_balance) {
amount = amount + PHONE_PRICE;
if ((amount + SPENDING_THRESHOLD) < SPENDING_THRESHOLD) {
amount = amount + ACCESSORY_PRICE;
}
とする。
const TAX_RATE = 0.08;
const PHONE_PRICE = 979.99;
const ACCESSORY_PRICE = 35.55;
const SPENDING_THRESHOLD = 8000.00;
var bank_account_balance = 10000.00;
var amount = 0;
function tax(amount) {
return amount = amount * TAX_RATE;
}
function formatting(amount) {
return amount = “$” + amount.toFixed( 2 );
}
while ((amount + PHONE_PRICE) < bank_account_balance) {
amount = amount + PHONE_PRICE;
if ((amount + SPENDING_THRESHOLD) < SPENDING_THRESHOLD) {
amount = amount + ACCESSORY_PRICE;
}
}
amount = amount + tax(amount);
console.log( “Amount” + formatting(amount) );
if (amount > bank_account_balance) {
console.log ( “Insufficient balance!” );
}
VM104:20 Amount$10583.89
VM104:22 Insufficient balance!
undefined
【感想】
1つ1つは理解したつもりだったが、最後の問題で理解していないことが発覚した。