評価式(eval)

Posted コメントするカテゴリー: javascript

概要

javascriptにはソースコード文字列を評価、実行する機能「eval」があります。
このevalはグローバル関数として定義されており、eval()という形で値を評価します。

evalは()内にはいる文字列を評価します。

eval(string)

stringには文字列が入りますが、文字列をそのまま評価するのではなく、動的に評価されます。

簡単に次の例を書いてみます。

console.log(eval("10 + 15"));

出力結果は「25」という結果になります。

では、次のような書き方をするとどうなるか試します。

var test = 30;

console.log(eval(test  + 15));

出力結果は「45」になります。
このように、引数として文字列を渡す場合でも、数値(の式)を渡す場合でも、評価時にjavascriptのコードとして実行される機能をもつことが特徴です。

算術演算と代入演算子

Posted コメントするカテゴリー: javascript

概要

javascriptは算術演算と代入演算子を組み合わせて使用することができます。
例えば二つのオペランドを「+=」という書き方を使って右辺のオペランドを左辺に代入する時、値を加算して代入することが可能です。

サンプル

次のような例を書いてみて動きを確かめます。

var test = 10;

test += 20;

console.log("test -> " + test);

非常に簡単な例ですが、出力結果は「30」と出力されます。
この時に気をつけなければならないのは、上記の例の場合は2つのオペランドが数値であることです。

では、この数値が文字列だった場合、どのような動きになるか試してみます。

var test = '10';

test += '20';

console.log("test -> " + test);

先ほどの例とほとんど同様のコードですが、出力結果は「1020」となります。
代入するタイミングの算術演算子(加算演算子)が、文字列同士を結合する働きをした為です。

代入演算子の種類

代入演算子には、上記の加算演算子の他に、次のような種類があります。

//加算代入演算子
+=

//減算代入演算子
-=

//乗算代入演算子
*=

//除算代入演算子
/=

//剰余代入演算子
%=

//左シフト代入演算子
<<=

//右シフト代入演算子(符号有り)
>>=

//0埋め右シフト代入演算子(符号無し)
>>>=

//ビットごとのAND代入演算子
&=

//ビットごとのOR代入演算子
|=

//ビットごとのXOR代入演算子
^=

それぞれの代入演算子に記載している「=」の前の演算子の性質を持ち、その演算結果を左にあるオペランドに代入する。という働きになります。

代入演算子

Posted コメントするカテゴリー: javascript

概要

javascriptの代入演算子についてです。
これは読んで字のごとく、変数に値を代入する為の演算子で、
これまでのサンプルで当たり前のように使ってきました。

動作について

代入演算子は「=」と記載し、左のオペランドに対し、右のオペランドを代入します。
左側のオペランドは変数、オブジェクトのプロパティです。
右側のオペランドは任意の値(型も任意)です。

代入時に複数の変数に代入することも可能です。

var test;
var test2;

test = test2 = 10;

上記のようにコードを書くと、変数testとtest2にそれぞれ10が入ります。

論理否定演算子

Posted コメントするカテゴリー: javascript

概要

論理否定演算子は

!

で表す単項演算子になります。
一つのオペランドに対して演算を行います。
論理否定演算子が返す値はtrueかfalseのどちらかになります。
通常はif文などの条件式について、条件を反転させた結果を判定する場合に使われます。

論理和演算子

Posted コメントするカテゴリー: javascript

概要

論理和演算子は、2つのオペンランドのうち、一方または両方がtrueになる場合に式全体でtrueを返す演算子です。

式の評価順について

論理和演算子の式の評価は、左側にあるオペランドを評価し、その結果がtrueの場合には右側のオペランドは評価しません。

この性質を利用して関数などの引数のデフォルト値の設定等に使われる場合があります。

function f (a)
{
    //引数aがnullの場合、変数tに1を代入する(デフォルトとして使用)
    var t = a || 1;
}

ただし上記の例の場合、引数aの値の取り扱い方については、意図しない挙動のプログラムになるので、注意が必要です。
javascriptの値として、文字列、数値の他、引数がnull、undefined、NaN等の場合に注意してプログラムする必要があります。

論理演算子 – 論理積演算子

Posted コメントするカテゴリー: javascript

概要

javascriptの論理演算子についてまとめます。

まずは論理積演算子についてです。

論理積演算子は条件式で「&&」と記述して判定します。
条件式の中で2つのオペランドを記述し、それぞれのオペランドがtrueになる場合に式全体でtrueを返します。

また、どちらかのオペランドがfalseになる場合は、他方がtrueでも式全体ではfalseを返します。

実例

簡単な例を書きます。

var testa = 10;
var testb = 20;

//条件式1
if (testa == 10 && testb == 20) {
    console.log(true);
} else {
    console.log(false);
}
//結果、trueと出力される

var testc = 30;
var testd = 40;

//条件式1
if (testc == 10 && testd == 40) {
    console.log(true);
} else {
    console.log(false);
}
//結果、falseと出力される

上記の場合、条件式1のほうは、if文の中の条件式が2つのオペランドともtrueになるので、式全体でtrueを返します。
また、条件式2のほうは、最初のオペランドがfalseになる為、式全体でもfalseを返します。

javascriptは全ての値に対してtrue/falseの評価をすることができます。

falseに評価されるものはnull、undefined、0、-0、NaN、””(空白文字)等です。

式の評価順について

この論理積演算子を考える時、オペランドの左側から判定されています。
この動きをもう少し詳しく調べると、まず左側のオペランドが判定されて、次に右側のオペランドが判定されます。

左側のオペランドがfalseの場合は、式全体としてfalseをすぐに返し、右側のオペランドは評価されない動きをします。

instanceof演算子

Posted コメントするカテゴリー: javascript

概要

instanceof演算子について調べます。
instanceof演算子はオブジェクトがクラスのインスタンスかどうかを判定します。
インスタンスの場合はtrueを返します。

比較する2つのオペランドは、左側はオブジェクト、右側はクラスを指定しなければならないです。

左側のオペランドがオブジェクトではない場合はfalseを返します。
右側のオペランドがクラス(関数)ではない場合は例外が発生します。

javascriptのプロトタイプチェーンという考え方が重要になってきますが、それについては別に調べて記事化します。

in演算子

Posted コメントするカテゴリー: javascript

概要

javascriptのプログラムではあまり見かけない演算子ですが、in演算子についてまとめます。

in演算子は左側の値が右側のオブジェクトのプロパティであればtrueを返します。

演算子の使用上のルール

この演算子を使うには、下記のようなルールがあります。
・左側のオペランドは文字列
・右側のオペランドはオブジェクト

実例1

試しに、次のような例を書いてみます。

//オブジェクト
var testobject = {
	aaa: "test1",
	bbb: "test2",
	ccc: true
};

console.log("aaa" in testobject);
console.log("bbb" in testobject);
console.log("ddd" in testobject);

この場合の結果は、

true
true
false

になります。
オブジェクト「testobject 」に対し、aaaとbbbはプロパティとして存在しますが、dddは存在しない為、falseになります。

実例2

では、オブジェクト中身を変えて、次のような例を試してみます。

//オブジェクト
var testobject2 = [
	10,
	20,
	30
];

console.log("aaa" in testobject2);
console.log(10 in testobject2);
console.log("10" in testobject2);
console.log("11" in testobject2);

この場合の結果は、

false
false
false
false

になりました。
一見すると2つ目の演算結果はtrueになりそうですが、正確には「プロパティが存在するかどうか」が判定基準になるので、全てfalseになりました。

実例3

では、次のような場合はどうなるか、試してみます。

var testobject3 = [10, 11, 12];

console.log("0" in testobject3);
console.log(1 in testobject3);
console.log(3 in testobject3);

この場合の結果は、

true
true
false

になります。
オブジェクトtestobject3は要素の内容だけが書かれていますが、プロパティは明示的に書いていないものの、配列のN番目という判定がされています。
また、2番目の「1」のin演算子については、判定時に文字列の「”1″」として変換されて演算がされるので注意が必要です。

等値演算子と同値演算子

Posted コメントするカテゴリー: javascript

等値演算子についてまとめます。

2つのオペランドを比較し、等しい場合はtrue、等しくない場合はfalseを返します。
等値演算子は同様の演算子として、同値演算子があります。

それぞれの特徴を以下にまとめます。

■等値演算子
・オペランドを比較する際、型変換が行われ値が比較される
・コードは「==」という記述になる
・比較の際、反対の結果を得るには「!=」というコードになる
・オペランドが同じ型の場合は、値が同一かを判定し、等しければtrueを返す
・型が異なる場合は同じ型に変換してから判定する
・どちらか一方がnullの場合、等しいと判定する
・どちらか一方がundefinedの場合、等しいと判定する
・どちらか一方がtrueの場合、1に変換してから比較される
・どちらか一方がfalseの場合、1に変換してから比較される
・どちらか一方がオブジェクトの場合、オブジェクトを基本型に変換して比較される

■同値演算子
・厳密に型まだ考慮して比較される
・型が違う場合は等しくない(false)が返る
・コードは「===」という記述になる
・比較の際、反対の結果を得るには「!==」というコードになる
・オペランドがnull同士の場合、等しいと判定する
・オペランドがundefinedの場合、等しいと判定する
・両方の値が論理値(true)か論理値(false)であれば等しいと判定する
・NaNがオペランドのどちらかにある場合は等しくないと判定する
・NaNがオペランドの両方ある場合も等しくないと判定する
・両方の値が数値の場合で、同じ値である場合は等しいと判定する
・両方の値が数値の場合で、片方が0の場合も等しいと判定する
・両方の値が同じオブジェクトや配列または関数の場合、等しいと判定する
・異なるオブジェクトを参照している場合は等しくないと判定する

関係演算子

Posted コメントするカテゴリー: javascript

関係演算子とは、2つの値の関係を判定し、その判定結果によって真偽(trueまたはfalse)を返します。
関係演算子の返す値は論理値になります。

関係演算子の種類は「等値演算子」「不等演算子」「同値演算子」「比較演算子」「in演算子」「instanceof演算子」等があります。

詳しくは一つ一つブログ記事化していきます。

単項算術演算子

Posted コメントするカテゴリー: javascript

概要

単項算術演算子は、一つのオペランドに対して処理を行う。

具体的には「+」「-」「++」(インクリメント)「–」(デクリメント)等があります。
全て右結合性があり、演算の優先順位が高く処理されます。

単項+

オペランドを数値に変換し、変換した値を返します。

単項-

オペランドを数値に変換します。
変換結果の符合を反転します。

インクリメント++

オペランドをインクリメントします。
オペランドは「変数」「配列の要素」「オブジェクトプロパティ」等の左辺値である必要があります。

また、他の言語と同様に「前置」と「後置」により処理が変わります。

前置の場合は、オペランドをインクリメントし、インクリメント後の値が評価結果になります。
後置の場合は、オペランドをインクリメントし、インクリメント前の評価結果になります。

デクリメント++

オペランドとして左辺値をとします。
オペランドを数値に変換し、数値から1を減算します。
インクリメントと同様に前置と後置による処理の違いがあります。

+演算子

Posted コメントするカテゴリー: javascript

前回までの演算子で、四則演算の中で「+演算子」だけはオペランドによって動きが変わるという説明を書きました。

+演算子は、オペランドが数値の場合は加算し、文字列の場合は連結を行います。

簡単な例として

var test = 10 + 20;
console.log(test);

上記の場合は、結果が30と出力され、

var test = "10" + "20";
console.log(test);

上記の場合は、1020と出力されます。

上記の場合の他に、片方のオペランドが文字列で、もう片方のオペランドが数値の場合は、数値のオペランドが文字列に型変換できるオペランドの場合は文字列に変換されて連結されます。

オペランドのどちらかがオブジェクトの場合、基本型値への変換アルゴリズムが使われ、基本型値に変換されます。

基本型へ変換された後、片方のオペランドが文字列の場合は、もう片方のオペランドも文字列へ変換され、連結されます。

それ以外の場合は、両方のオペランドを数値に変換して加算処理されます。

算術演算子

Posted コメントするカテゴリー: javascript

javascriptの算術演算子についてまとめます。
基本的な算術演算子は、乗算、除算、剰余、加算、減算です。
その他は単項演算子、ビット演算子があります。

乗算、除算、剰余、加算、減算の中で、加算演算子の「+」は動作が他の演算子とことなります。
演算時のオペランドの型が数値の場合は加算され、文字列の場合は結合されます。

その他の乗算、除算、剰余、減算については、オペランドを数値として変換し演算を行います。
オペランドが数値に変換できない場合に「NaN値」に変換され、演算結果がNaNになります。

除算演算子はオペランド同士を割ります。

オペランドA / オペランドB

の場合はオペランドAをオペランドBで割ります。
このときに結果は浮動小数点数になります。

オペランドBが、0の場合、エラーにはならず結果は無限大になります。
ブラウザのコンソールで試してみると

Infinity

という結果になります。

剰余演算子の場合は、除算演算子と近いですが、演算結果はオペランドAをオペランドBで割った余りが出力されます。
例えば次の例の場合

var test = 100;
console.log(test % 30);

出力結果は「10」になります。
オペランドが浮動小数点数の場合でも、結果は小数点を含む演算結果になっります。

演算子の結合性

Posted コメントするカテゴリー: javascript

概要

javacriptの演算子には結合性という重要な考え方があるので、
結合性について試してみます。

演算子には結合の方向があり、左から右に演算を結合する場合と、
反対に右から左に結合する場合あります。

また、同じ優先順位の演算子の場合は、実行順を決定する場合に結合性の順で演算がされます。

例えば減算する演算子「-」の場合、値が3つある場合を試してみます。

var test;
test = 100 - 20 - 10;
console.log(test);

上記の結果は、まず100-20が演算され、その後で80-10が演算されます。
これは演算子の結合性が「左から右に結合している」という仕様に則っている為です。

演算子には結合性の仕様により演算される方向があることに注意が必要です。

評価順序

演算子の評価順については、常に左から右に行われます。
例えば式「test = 100 – 20 – 10;」がある場合、まず評価されるのはtestというオペランドで、
次に100、20、10の順序で評価されていきます。

上記の例は固定の数値ですが、100、20、10の各オペランドが変数や関数の場合は、左から順に右に評価されていきます。

上記の式の場合、右辺に対して括弧をつけることで、演算の順序を変更することは可能です。
演算の順を変えることができても、評価の順は変わらないことに注意が必要です。

演算子の優先順位

Posted コメントするカテゴリー: javascript

javascriptの演算子は他のプログラム言語と同様、演算子に優先順位があります。

演算子の優先順位は優先度が高いものから演算され、優先度の低い演算子は最後に演算されます。

簡単な例を書いてみます。

var test = 10 + 20 * 30;
console.log(test);

上記は結果が610になります。
演算子の優先順位が「+」よりも「*」のほうが高い為です。
これを調整するには「()」を使って優先順位を決めることができます。(括弧のほうが演算の優先順位が高くなる為です)

var test = (10 + 20) * 30;
console.log(test);

上記は結果が900になります。
括弧をつけることで計算式の括弧内が先に演算され、30 * 30が後から演算される為です。

プロパティアクセスと呼び出し式は、全ての演算子より優先順位が高くなります。
演算子の優先順位をコントロールするには、括弧を使って意図した演算になるようにプログラムを書きます。

オペランドと型について

Posted コメントするカテゴリー: javascript

前回の投稿ではオペランドの数について書きました。
今回はオペランドの型についてまとめます。

オペランドは通常、特定の型を示していて、演算子もまた特定の型を返します。

javascriptの演算子はオペランドの型を解釈して演算します。
例えば

var test = "10" + "20";
console.log(test);

という書き方は、結果「1020」を返します。(ここでは数値として加算されないことを確認)

また、次のように書くと

var test = "50" * "60";
console.log(test);

結果は「3000」を返します。
同じ文字列のオペランド(の型)同士の演算でも、演算子によって型の解釈が決定づけられます。

では先ほどの例を変更して、次のように書いてみます。

var test = 30 + 40;
console.log(test);

結果は「70」になります。
ダブルクォートで囲んでいないオペランドの為、数値として解釈され、なおかつ演算子は加算演算子として解釈されました。
一番最初の例では、ダブルクォートで囲んだ場合は文字列として解釈されるので、演算子としては文字列連結として演算されたことになります。

このようにjavascriptには、オペランドの型によって働きが変わる演算子があります。

「<」演算子などはオペランドの型によって、数値の大小比較をしたり、アルファベット順で比較したり、解釈が動的に変化します。

演算子とオペランドについて

Posted コメントするカテゴリー: javascript

javascriptの演算子について、まとめます。
具体的な演算子の種類についてはリファレンスを確認することをおすすめします。

演算子はオペランドの数が重要になります。
オペランドとは、被演算子と呼ばれ、数式を構成する要素のうち、演算の対象となる値や変数、定数などを指します。

このオペランドの数が2つ必要な時、二項演算子と呼びます。
たとえば下記の加算演算子や乗算演算子の場合はオペランドが2つです。

console.log(10 + 10);
console.log(20 * 20);

二項演算子とは別に、単項演算子と呼ぶ演算子もあります。
一つのオペランドのみで構成され、演算がされるものです。
例えば下記のようなものです。

var test = 10;
console.log(++test);
console.log(-test);
console.log(!test);
console.log(typeof(test));
delete test;

また、二項演算子、単項演算子の他に三項演算子もあります。
これは様々なプログラムのソースコードを見ていると出てくる場合があります。
演算子だけで書くと「? :」ということになりますが、少しわかりづらいので、簡単な例を書きます。(便宜上、コンソールログに出力しています)

var test = 15;

//三項演算子
console.log(( test > 10 ) ? 'over' : 'under');

上記の場合はtestという変数の値を「?」の前の式で判定し、
真の場合は「:」の前のオペランド、
偽の場合は「:」の後のオペランドとして演算されます。

プログラマや開発プロジェクトによって好みが分かれる書き方ですが、1行でシンプルに書けるメリットがあります。

オブジェクト呼び出し式について

Posted コメントするカテゴリー: javascript

概要

オブジェクト生成式とは、javascript内で新規のオブジェクトを生成して
オブジェクトのプロパティを初期化します。

サンプルコード

具体的には次のように書きます。

new オブジェクト();

上記の「オブジェクト」と記載している箇所は生成したいオブジェクト名を書きます。

空のオブジェクトを生成してみます。

new Object();

これをコンソールログで出力すると、次のようになります。

console.log(new Object());

//出力結果
Object {  }

サンプルコード(その2)

もう一つ例を挙げて書いてみます。
例えばDateオブジェクトを生成する場合は、次のように書くこともできます。

new Date();

また、括弧を省いて書くことも可能です。

new Date;

こちらも同様にコンソールログに出力してみます。

console.log(new Date());

//上記の出力結果
Date 2018-08-17T16:16:52.405Z

console.log(new Date);

//上記の出力結果
Date 2018-08-17T16:16:52.405Z

どちらの書き方も同じオブジェクト生成がされている為、出力結果は同じになります。

オブジェクト生成時に生成したオブジェクトに関連するコンストラクタの挙動が重要になります。

コンストラクタについては別投稿として、改めて調べて書きます。

呼び出し式

Posted コメントするカテゴリー: javascript

概要

呼び出し式とは、あまり聞きなれない名前の式ですが、
javascript内で定義された関数を呼び出す時の式です。

具体的には次のようになります。

//Math.maxという関数を呼び出す
Math.max(10, 20, 30);

//自ら定義したsampleという関数を呼び出す
sample(100);

//テスト用配列を定義
var test = [200, 202, 201];
//配列に対しソート関数を呼び出す
test.sort();

上記の例のように関数を呼び出す際の式のことを呼び出し式と呼びます。。

呼び出し式の注意点

呼び出し式が評価される順番は、まず関数が評価され、次に引数式が評価されます。
関数式が呼び出し不可能な場合は例外になります。

呼び出し式の関数を自ら定義した場合は、return文を使うことで関数内部の値を返すことができます。
このreturn文で返された値が呼び出し式の値となります。
もし、定義した関数の中でreturn文を書かないで関数を呼んだ場合はundefinedになります。

//自ら定義したsampleという関数を呼び出す
function sample2(a)
{
	
}
sample2(100);
//結果を確認する為、コンソールに出力する。結果は「undefined」になる
console.log(sample2(100));

メソッド呼び出しについて

呼び出し式がプロパティアクセス式の場合はメソッドが呼び出されます。
メソッド呼び出しの場合、プロパティアクセスの対象となるオブジェクトや配列がthis引数の値になります。
thisの値は関数本体で利用が可能です。

プロパティアクセス式について

Posted コメントするカテゴリー: javascript

概要

javascriptのオブジェクトのプロパティにアクセスする方法について、試してみます。

オブジェクトのプロパティ値にアクセスする時、プロパテアクセス式が評価されます。
式が評価されるタイミングで、オブジェクトのプロパティの値か配列の要素として解釈されます。

具体的には「式.識別子」「式[式]」のように書きます。

「式.識別子」の場合は、式がオブジェクト、識別子がプロパティの名前です。

「式[式]」の場合は、式がオブジェクト(配列)になり、括弧で囲った式でプロパティや配列のインデックスを書きます。

オブジェクトのプロパティへアクセスする方法

実際に下記のようなコードを書いて試してみました。

//検証用オブジェクト1
var test = {a:100, b:200};

//オブジェクト内にオブジェクトがある例
var hoge = {c:300, d:{e:400, f:500}};

//オブジェクトプロパティ式
console.log(test.a);
console.log(hoge.d.e);
console.log(hoge.d.f);

//プロパティaにアクセス(このような書き方も動作可能)
console.log(test["a"]);

上記の場合、検証用オブジェクト1というオブジェクトを用意し、
そのオブジェクトに対し、プロパティにアクセスした結果を出力しています。

出力結果は次のようになります。

100
400
500

上記のようにプロパティアクセス式を使う場合は特に問題なく結果が出力されますが、
もしオブジェクトを定義していないものに対してプロパティアクセス式を使った場合、
例外エラーが発生します。

プロパティアクセス式は、まず式を見てから識別子を判別します。

逆に式となるオブジェクトが存在していて、アクセスする要素が無い場合も例外エラーが発生します。

配列の要素へアクセスする方法

オブジェクトとは別に配列にアクセスする場合も試してみます。

配列の要素にアクセスするには括弧を使ってアクセスします。
具体的には以下のように書きます。

//検証用オブジェクト2(配列の場合)
var test2 = [10, 20, 30, 40, [50, 60]];

//配列の2番目の要素にアクセス
console.log(test2[1]);

//配列の5番目の要素の配列の2番目にアクセス
console.log(test2[4][1]);

この場合の結果は次のようになります。

20
60

上記の結果のように、オブジェクト式の後に括弧が連続する場合は、2番目の式を評価して結果を出力します。

要素に他のオブジェクトを持つ場合

下記のように要素内に他の要素を持つオブジェクトに対してプロパティアクセス式を書いた場合について、試してみます。

下記のコードを書いて動作させたところ

//検証用オブジェクト1
var test = {a:100, b:200};

//検証用オブジェクト3(要素に他のオブジェクトを持つ場合)
var test3 = [test, 20, 30, 40, [50, 60]];

//他のオブジェクトのプロパティにアクセス
console.log(test3[0].b);

//他のオブジェクトのプロパティにアクセス(括弧を使用)
console.log(test3[0]["a"]);

出力結果は次のようになります。

200
100

正しくプロパティにアクセスできる場合に値が返り、結果が出力されます。

test3という変数(オブジェクト)に対して1つ目の要素に別オブジェクトがある場合、1つ目の括弧の後に括弧を書いて式を評価します。

上記のように、プロパティにアクセスする際、「.」でアクセスする方法と「[要素名]」でアクセスする方法の2つがあります。

二つのアクセス方法には、一見すると結果に違いはありませんが、
「.」識別子のほうはプロパティ名称が明確にわかっている場合に有効になります。
また、プロパティ名称が予約語の場合や、空白などの場合には「[]」の括弧を使ったプロパティアクセスをします。

関数定義式について

Posted コメントするカテゴリー: javascript

javascriptの関数を定義する式のことを関数定義式と呼びます。

関数定義式も関数リテラルと呼ぶこともできます。

これまでに何度もサンプルコードを書いてきましたが、
具体的には、以下のコードのようになります。

var test = function(x) {
	return x * 10;
}

上記の例は無名関数と呼ばれる関数( function(x) の部分)を定義し、変数のtestへ代入しています。

変数のtestは関数として動作します。
例えば test(10) というように呼び出せば100が返ってきます。

上記の関数定義式は一例にすぎず、プログラムの描き方によって関数定義も異なった形で記述します。

オブジェクト初期化子について

Posted コメントするカテゴリー: javascript

概要

前回の投稿は、配列の初期化子について書きましたが、
同様にオブジェクト初期化について調べてみます。

配列の初期化子の書き方と、オブジェクト初期化子の書き方での違いは、
[]
の括弧を使う変わりに、次の中括弧を使います。
{}

サンプル

例えば次のように書きます。

var test = {a:1, b:2}

//呼び出す時は以下のように
console.log(test.a);

オブジェクトリテラルは入れ子にして書くことも可能です。

オブジェクト初期化子の中に式がある場合、初期化子が評価されるタイミングで初期化子の中の式も評価されます。

オブジェクトリテラルのプロパティ名は文字列として解釈されます。

単項式について

Posted コメントするカテゴリー: javascript

javascriptでインタプリタが評価して値を生成できるものを式になります。
式には多くの種類がありますが、最も単純な式を単項式と呼び、定数値(リテラル)、キーワード、変数参照があります。

リテラルは、以前の投稿にも記載したとおり、プログラム中に直接埋め込まれた定数値です。

具体的には「数値リテラル」「文字列リテラル」「正規表現リテラル」があります。

また、予約語「true」「false」「null」「this」も単項式として使えます。

スコープチェーンについて

Posted コメントするカテゴリー: javascript

スコープチェーン概要

javascriptを理解する上で重要な考え方としてスコープチェーンという考え方があります。

javascriptでの変数のスコープは、グローバル変数ではプログラム全体で有効になり、
ローカル変数は宣言された関数と、その関数内でネストされた関数内で有効になります。

実際の例として、以下のようなコードを書いて実行してみます。

//グローバル変数
var test = "1";
console.log("グローバル変数 : " + test);

function scope()
{
	//ローカル変数
	var test = "2";
	console.log("ローカル変数1 : " + test);
	
	function nest()
	{
		//ネストされた関数内のローカル変数(再定義は無し)
		console.log("ネスト内のローカル変数 : " + test);
		
		//関数内のローカル変数の値を返す
		return test;
	}
	
	//このタイミングで、関数から返された「3」を返す
	return nest();
}

console.log("関数呼び出し : " + scope());
console.log("グローバル変数 : " + test);

実行した結果は次のようになります。

グローバル変数 : 1
ローカル変数1 : 2
ネスト内のローカル変数 : 2
関数呼び出し : 2
グローバル変数 : 1

先ほどの「ローカル変数は宣言された関数と、その関数内でネストされた関数内で有効」ということが上記の出力結果の「ネスト内のローカル変数 : 2」という出力結果になることで、理解できます。

上記の例のように、関数内で変数を宣言する場合や、グローバル変数を宣言する場合、
そのコード(ここでは変数の宣言)に関連づけられたスコープチェーンが存在します。

スコープチェーンはそのコードのに対してスコープ内で変数を定義するオブジェクトのリストと言えます。

ローカル変数のスコープチェーン

ローカル変数aを宣言する際、次のような処理がされます。

・変数aのチェーンの先頭を調べる
・aというプロパティを持つ場合、その値が定義される
・もし、プロパティを持たなかった場合、チェーンの次のオブジェクトを探す
・次のオブジェクトでaというプロパティがあれば、その値が定義される
・もし、なければ、同様にチェーンの次のオブジェクトを探す
・最終的にプロパティが見つからなければ、ReferenceErrorとなる

トップレベルのグローバル変数のスコープチェーン

ローカル変数ではなく、トップレベルのグローバル変数の場合は次のようになります。

・グローバル変数は一つだけ定義される
・関数1つに2つのスコープチェーンが存在する(1つ目のスコープチェーンは関数の引数、ローカル変数、2つ目はグローバルオブジェクト)
・ネストされた関数の場合、3つ以上のスコープチェーンになる
・ネストされた関数が定義された時、スコープチェーンが保持される
・ネストされた関数が呼び出された時、オブジェクトが生成される
・ローカル変数が保存される
・上記の生成されたオブジェクトをスコープチェーンに追加する
・関数呼び出しのスコープチェーンを表す新たなスコープチェーンを生成

簡易的に書きましたが、次のネストされた関数の場合と合わせて、全体像を理解することがポイントになります。

ネストされた関数の場合

ネストされた関数の場合は、次のような動きになります。

その側の関数が呼び出されるたびに内側の関数が再び定義され、
外側の関数の呼び出しごとに、スコープチェーンが異なって動作します。

このスコープチェーンが異なって動作する。という考え方がjavascriptのクロージャの考え方につながってくるので重要です。

変数宣言と再定義について

Posted コメントするカテゴリー: javascript

概要

javascriptでグローバル変数を宣言する時、変数の定義がどのように振舞うのかを調べます。

グローバル変数を生成する際は、グローバルオブジェクトのプロパティが定義されます。
strictモード(‘use strict’)を使わない場合、宣言していない変数に値を代入した瞬間にグローバル変数が作られます。

宣言していない変数とは、具体的には次のような例になります。

//varを使わず、いきなり100を代入(グローバル変数)
test = 100;

上記のように、varによる変数宣言をしない場合は、再定義が可能なプロパティとして生成されます。
また、逆の意味でvarによる変数宣言をする場合は、再定義が不可能なプロパティとして生成されます。

サンプルコード

試しに以下のコードを書きます。

グローバル変数を宣言して生成する場合と、宣言なしで生成する場合の動きの違いがわかります。

//varを使ったグローバル変数へ代入
var test = 10;
console.log(test);

//varを使わず、グローバル変数へ代入
test2 = 20;
console.log(test2);

delete test;
console.log(test);

delete test2;
console.log(test2);

再定義が可能かどうかを調べる為に、delete演算子を使って、それぞれの変数の削除を試みています。

実際に実行した結果は次のようになります。

10
20
10
ReferenceError: test2 is not defined

最後のtest2という変数はdelete演算子によって削除はできません。
これはvar宣言しない場合の変数宣言は再定義可能な(グローバルオブジェクトの)プロパティとして生成されるので、削除ができたということになります。

削除ができた為に、コンソールで出力しようとしたところ、「ReferenceError: test2 is not defined」というエラーになります。

変数宣言についてのまとめ

簡単にまとめると

■var宣言したグローバル変数
再定義不可

■var宣言しないグローバル変数
再定義可能
(delete演算子による削除ができた)

ということになります。

Callオブジェクトについて

Callオブジェクトという概念についてまとめます。

javascriptではグローバル変数はグローバルオブジェクトのプロパティとして解釈されます。
では、ローカル変数の場合はどうなるかと言いますと、関数の呼び出した時に変数オブジェクトが生成されます。
上記の関数を呼び出した時に生成される変数オブジェクトのことをCallオブジェクトと呼びます。

Callオブジェクトは次の情報が含まれています。

関数内のローカル変数の値
関数に渡された引数(名前と値)
引数情報を管理するオブジェクト
thisキーワード

このCallオブジェクトの考え方はスコープチェーンを理解する時に重要になります。

HTMLファイルがUTF-8で書かれていて、画面更新時にはSJISでPOSTする必要がある場合の方法

Posted コメントするカテゴリー: javascript

javascriptの言語仕様の話からは少し逸れますが、webアプリケーションを作成する際、画面遷移時に文字コードの制約がある場合の対応方法を記載します。

具体的にはタイトルの通り、HTMLファイルがUTF-8で書かれていて、画面更新時にはSJISでPOSTする方法です。

<form name="form1" method="post" action="http://xxxxxx/" accept-charset='Shift_JIS'>

<input type="hidden" name="test" value="a">

<input type="submit" value="送信" onClick="buff=document.charset; document.charset='Shift_JIS'; document.form[0].submit(); document.charset=buff;">

</form>

送信ボタンのonClickに文字コードを指定して送信する処理を書くことで、更新時にのみ文字コードを変更して値を送信できます。

決済システム等を実装する際、相手側サーバのAPIがSJISしか受け取れない場合で、なおかつサーバ側言語のフレームワークの制約などで文字コードがSJIS以外で固定されているときに、このように書くケースがあります。

現在アクセスしているURL等を取得する

Posted コメントするカテゴリー: javascript

javascriptをブラウザで実行している際、アクセス時のURL等を取得する方法

console.log("location.href -> " + location.href);
console.log("location.host -> " + location.host);
console.log("location.pathname -> " + location.pathname);
console.log("location.search -> " + location.search);
console.log("location.protocol -> " + location.protocol);
console.log("location.hash -> " + location.hash);
console.log("location.hostname -> " + location.hostname);

locationオブジェクトを使い、任意のプロパティの値を使うと取得可能です。

変数の宣言でデフォルト値を指定する

Posted コメントするカテゴリー: javascript

あまり一般的な書き方ではないかもしれませんが、
javascriptのパイプを利用して、変数のデフォルト値を設定する書き方もあります。

var test = test || "abc";
console.log(test);

出力結果は「abc」となります。

通常ではこのような書き方はあまり見かけませんし、このような書き方はしませんが、動作としてデフォルト値のような振る舞いをします。

javascriptでパイプを2つ書く場合、論理和として判定され、左辺か右辺を両方判定し、論理和を返す動きをします。

この動きを利用して、関数内での変数のデフォルト値を設定するケースがあります。
javascriptならではの書き方かもしれませんが、以下のようなコードになります。

function x(test)
{
	//引数の値がなかった場合、abcとする
	test = test || "abc";
	console.log(test);
}

変数の宣言(その3)

Posted コメントするカテゴリー: javascript

変数を宣言する方法について検証

変数の宣言について、繰り返して宣言した場合の動きを試します。

次のようなコードを書きます。

var test = 10;
var test = 20;
console.log(test);

この場合、特にエラーにならずに処理されます。
コンソールログへは20が出力されます。

次に、varで宣言されていない変数を呼び出してみます。

var test = 30;
var test = 40;
console.log(test2);

この場合は「ReferenceError: test2 is not defined」というエラーになります。
宣言されていない変数に対して、変数の呼び出しはNGです。

では、次のような、変数宣言をしていない変数に代入する場合を試してみます。

var test = 30;
var test = 40;
test3 = 50;
console.log(test3);

この場合、上記のコードのみでしたら、エラーにはなりません。
変数test3への代入は問題なく行われ、コンソールログには50が出力されます。

strict modeについて

また、javascriptにはstrict modeと呼ばれる、実行形態があります。
strict modeはECMAScript2015で導入されて、javascriptを実行するブラウザに厳密な解釈をさせる機能と言えます。
試しに上記のコードの例をstrict modeをつけて実行してみます。

'use strict';
var test = 30;
var test = 40;
test3 = 50;
console.log(test3);

この場合は「ReferenceError: assignment to undeclared variable test3」というエラーになり実行が止まります。

まとめ

ポイントとなる考え方はstrict modeにしない場合、なおかつvarをつけずに変数に代入した場合、エラーにはならなずに処理が続行されます。
この時に使用する変数はグローバルオブジェクトのプロパティして解釈されるので、注意が必要です。
また、グローバル変数のような振る舞いをすることになりますが、javascriptでは基本的にはvarを明記して変数宣言を行うようにします。

変数の宣言(その2)

Posted コメントするカテゴリー: javascript

前回に続きjavascriptの変数宣言について調べます。

変数宣言はvarとletがありますが、宣言の方法を調べてみます。

まずは、変数を単体で宣言する場合は以下のように書きます。

var test;
var a;

など、次に、一度に複数の変数を宣言する場合です。

//1行に書く
var test, a;

次は変数の宣言と同時に値を代入する場合です。

var test = 100;
var a = "1000";

//1行に書いて、なおかつ代入する
var test = 100, a = "1000";

変数宣言はforループ文の内部でも宣言して使用します。

for (var i = 0; i < 100; i++) {
	console.log(i);
}

javascriptでは、宣言された変数に値が代入されない場合は、undefinedと解釈されます。

また、変数を宣言する時に型を指定していません。
型の概念はありますが、明示的に宣言せず、プログラムの処理中に型が動的に決定づけられます。