配列ではないオブジェクトに対しての配列メソッドの扱い

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

概要

javascriptの配列は、以下の特徴があります。

・配列に要素が追加されると、lengthプロパティが自動的に更新される
・lengthプロパティに現在の長さより小さな値を設定することで、配列を縮められる
・Array.prototypeからメソッドを継承している
・Arrayというクラス属性を持っている

上記は配列の特徴ですが、必ずこの特徴を持たなければならないことはないようです。(まだ推測の段階なので、検証は必要)
javascriptの配列ではないオブジェクトに対し、配列として扱っても、配列同様に振舞うことができます。

また、文字列を配列にように扱うことも可能です。

文字列に対し、インデックス指定でアクセスし、内容を取得したりすることが可能です。

ES2015(ES6)の配列メソッド

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

概要

ES6の配列に使えるメソッドを簡単に試してみます。

forEach

forEachは前のブログ投稿にも出てきました。
配列test1に対して、全ての要素を加算し、最終的な合計値を出力しています。
次のようなコードを書きます。

let test1 = [1, 10, 20, 30, 60];
let sum = 0;
test1.forEach(function(value) { sum += value; });
console.log(sum);

出力結果

Array(5) [ 2, 11, 21, 31, 61 ]

map

このメソッドは配列の要素を1つづつ、関数に引数として渡します。
関数から返された値は最終的に配列として返されます。
次のようなコードを書いて試してみます。

let test2 = [1, 10, 20, 30, 60];
test3 = test2.map(function(x) { return x * x; });
console.log(test2);
console.log(test3);

出力結果

Array(5) [ 1, 10, 20, 30, 60 ]
Array(5) [ 1, 100, 400, 900, 3600 ]

filter

配列要素の部分集合となる配列を返します。
次のようなコードを書いて試します。

let test4 = [1, 10, 20, 30, 60];
test5 = test4.filter(function(x) { return x > 15; });
console.log(test4);
console.log(test5);

出力結果

Array(5) [ 1, 10, 20, 30, 60 ]
Array(3) [ 20, 30, 60 ]

every

配列の各要素に対して、指定した関数内の演算結果をみます。演算結果が配列の全ての要素が真だった場合にはtrueを返します。(演算結果が偽の場合はfalseを返します)
次のコードを書いて試してみます。

//every
let test6 = [1, 10, 20, 30, 60];
test7 = test6.every(function(x) { return x < 20; });
console.log(test6);
console.log(test7);

//some
let test8 = [1, 10, 20, 30, 60];
test9 = test8.some(function(x) { return x < 20; });
console.log(test8);
console.log(test9);

出力結果

Array(5) [ 1, 10, 20, 30, 60 ]
false
Array(5) [ 1, 10, 20, 30, 60 ]
true

indexOf

要素の中から指定した値を持つ要素を検索して、見つかった場合は最初のインデックスを返す。

//indexOf
let test12 = [1, 10, 20, 30, 60];
test13 = test12.indexOf(20);
console.log(test12);
console.log(test13);

出力結果

2

indexOfの例

const testArray = [1, 2, 3, 4, 5];
const elementToCheck = 3;

if (testArray.indexOf(elementToCheck) !== -1) {
    console.log('配列内に存在する');
} else {
    console.log('配列内に存在しない');
}

javascriptの配列に対してのメソッド

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

概要

配列のメソッドについて試してみます。

メソッドはprototypeオブジェクトのメソッドとしてjavascriptの標準機能として実装されています。

近年ではECMAScriptのバージョンも上がってきており、最新の言語仕様に対応する必要性があります。

現在普及している言語標準化規格は「ECMAScript2015」(ES6)と「ECMAScript2016」(ES7)が大半になりますが、言語仕様が新しくなる前から実装されている基本的なメソッドについても試してみます。

join

配列の全ての要素を文字列に変換して連結するメソッドです。
実際に次のようコードを書いて動かしてみます。

let test1 = [1, 10, 20, 30, 60];
console.log(test1.join());

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

1,10,20,30,60

少しわかりづらいですが、出力結果はひとつづきの文字列になっています(カンマも含む)

sort

配列の全ての要素をソートするメソッドです。
実際に次のようコードを書いて動かしてみます。

let test2 = [10, 30, 1, 20, 60];
console.log(test2.sort());

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

Array(5) [ 1, 10, 20, 30, 60 ]

配列内の各要素を数値として比較し、小さい→大きい順にソートされています。

では、配列内の要素が数値と文字列があった場合に、どのような挙動になるか試してみます。
具体的に次のコードを書いて動作させてみます。

let test3 = ["xyz", 30, "abc", "5", 60];
console.log(test3.sort());

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

Array(5) [ 30, "5", 60, "abc", "xyz" ]

上記の出力結果はとても「ソートした結果」とは言えず、不完全なものです。
言語仕様にもよりますが、文字列と数値が混在した配列は、sort関数ではソート不能という結果になりました。

では、配列内の要素が全て数値である(負の数、0、正の数)場合のソート結果はどうなるでしょうか。
次のようなコードを書いて実行してみます。

let test4 = [-50, 30, -100, 0, 5, 60];
console.log(test4.sort());

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

Array(6) [ -100, -50, 0, 30, 5, 60 ]

これも、よく見るとソートが不完全です。
結果の後半で「30, 5, 60」のように、桁が考慮されておらず、単純に文字列の出現順(アルファベット順)として出力されています。

上記の配列test4を厳密に数値してソートするには、次のように書きます。

let test4 = [-50, 30, -100, 0, 5, 60];
//数値順としてソートする場合
console.log(test4.sort(function(a, b) { let ans = b - a; if(isNaN(ans)) { return -1; } else { return a - b; }}));

このように書くと、次のような出力結果になります。

Array(6) [ -100, -50, 0, 5, 30, 60 ]

これで正しくソートされています。
sort関数内で、無名関数を定義し、その無名関数の中で引数同士を比較して、比較結果により、引数をソートする判定を行っています。

より詳しく書くと、2つの引数「a」と「b」を比較し、

「b – a」の演算結果が
「正」になる場合は、aをbの後ろへ
「負」になる場合は、aをbの前へ

という無名関数を作り、その演算を繰り返すことで、正しいソート結果を得ています。

concat

concatメソッドは、配列に対して、要素を追加して新しい配列要素を返します。
具体的には次のように書きます。

let test5 = ["xyz", 30, "abc", "5", 60];
console.log(test5.concat(10, 20));

出力結果は

Array(7) [ "xyz", 30, "abc", "5", 60, 10, 20 ]

のようになります。
contactの引数「10, 20」の要素を、元の配列「test5」の最後に付け加えています。

slice

sliceメソッドは配列に対して、指定番目の要素をスライスして別な配列を返します。
引数が2つあり、1つ目の引数で、スライス開始の要素(○番目)を指定し、2つ目の配列で配列の末尾を指定します。
引数が1つのみの場合は、その引数で指定した要素から配列の最後までを取得します。
引数が負の数の場合は、配列の最後から数えた要素数からスライスされます。

次のようなコードを書いて試してみます。

let test6 = ["xyz", 30, "abc", "5", 60];
console.log(test6.slice(0, 2));
console.log(test6.slice(4));
console.log(test6.slice(-2));

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

Array [ "xyz", 30 ]
Array [ 60 ]
Array [ "5", 60 ]

splice

配列に要素を挿入したり、削除する場合に使います。
このメソッドの特徴として、メソッドを実行する配列に対し、直接要素を操作する点があります。

例えば、次のようなコードを書いて実行してみます。

let test7 = ["xyz", 30, "abc", "5", 60, 70, "80", 90];

console.log(test7.splice(3)); //出力結果 ["5", 60, 70, "80", 90]

//一旦、元の配列の要素を出力して確かめる
console.log(test7);  //出力結果 ["xyz", 30, "abc"]

//さらにspliceメソッドを使う
console.log(test7.splice(1, 2));  //出力結果 [30, "abc"]

//元の配列の要素を出力して確かめる
console.log(test7);  //出力結果 ["xyz"]

実行した際の2つめの出力を確認すると、spliceメソッドを使った後の配列は、要素が先頭の3つのみになっています。
つまり元の配列の要素数が変更され、要素が減っている状態と言えます。

さらに2回目のspliceの実行で、要素は元の配列の1番目から2つ削除されます。

最終的には元の配列の要素は1つだけになり、「”xyz”」の文字列が出力されました。

push pop

pushメソッドは配列に対して、最後に1つの要素を追加するメソッドです。
その反対にpopメソッドは、配列の最後の要素を削除します。

配列の長さは動的に変化し、pushした場合は1つ増加し、popした場合は1つ減少します。
この2つのメソッドを使うと、配列に対してのスタック操作が可能になります。

上記を踏まえて次のようなコードを試してみます。

let test8 = [];

test8.push(3)
console.log(test8);

test8.pop();
console.log(test8);

test8.push(5, 2);
console.log(test8);

test8.pop();
console.log(test8);

test8.push(4);
console.log(test8);

test8.push(6);
console.log(test8);

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

Array [ 3 ]
Array []
Array [ 5, 2 ]
Array [ 5 ]
Array [ 5, 4 ]
Array(3) [ 5, 4, 6 ]

pushとpopのメソッドを実行した後、それぞれ配列の最後の値が増加、減少していることがわかります。

unshift shift

unshiftメソッドとshiftメソッドは、配列の先頭の要素を操作します。

unshiftは配列の先頭に要素を追加します。
shiftは配列の先頭の要素を削除します。

先ほどpushで書いたコードに似た次のようなコードを書いて試してみます。

let test9 = [];

test9.unshift(3)
console.log(test9);

test9.shift();
console.log(test9);

test9.unshift(5, 2);
console.log(test9);

test9.shift();
console.log(test9);

test9.unshift(4);
console.log(test9);

test9.unshift(6);
console.log(test9);

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

Array [ 3 ]

Array []

Array [ 5, 2 ]

Array [ 2 ]

Array [ 4, 2 ]

Array(3) [ 6, 4, 2 ]

pushやpopと違い、配列の先頭に要素を追加していることがわかります。

toString

配列に対してのtoStringメソッドを試してみます。
このメソッドは配列要素の一つ一つを文字列に変換してカンマ区切りのリストを出力します。

実際に次のようなコードを書いて試してみます。

let test10 = ["xyz", 30, "abc", "5", 60, 70, "80", 90];
console.log(test10.toString());

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

xyz,30,abc,5,60,70,80,90

配列要素が全てカンマ区切りで連結され、全体でひとつの文字列として出力されています。

また、類似するメソッドとして、toLocaleStringメソッドがあります。
メソッドの動きはtoStringと同様の動きになりますが、区切り文字がロケール固有区切り文字で区切られます。
区切り文字はプログラム実行時の、ブラウザ環境に依存します。

javascriptの多次元配列

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

概要

javascriptで多次元配列を扱う場合を試してみます。

厳密に言うと、javascriptは言語仕様としての多次元配列はありません。
言語仕様としては存在しませんが、擬似的に配列と配列を組み合わせて多次元配列となるような配列を生成できます。

実際にコードを書いて多次元配列を試してみる

javascriptでコードを書いて、多次元配列のような配列を試してみます。

次のようなコードを書いて、実行してみます。

//通常の配列を定義する
let test1 = [1, 10, 20, 30, 60];

//要素の全てを回して処理
for (let i = 0; i < test1.length; i++) {
	//ループ内で、要素ごとに、さらに新規配列を定義して代入する
	test1[i] = [2, 20, 40, 60, 80];
}

//ループ後の結果を出力1(わかりやすいように、1次元目の要素を一つづつ出力する)
console.log(test1[0]);
console.log(test1[1]);
console.log(test1[2]);
console.log(test1[3]);
console.log(test1[4]);

//ループ後の結果を出力2(わかりやすいように、1次元目の要素内の2次元目の要素を出力する)
console.log(test1[0][0]);
console.log(test1[0][1]);
console.log(test1[0][2]);
console.log(test1[0][3]);
console.log(test1[0][4]);

実際に動作させた結果は、次のようになります。

Array(5) [ 2, 20, 40, 60, 80 ]
Array(5) [ 2, 20, 40, 60, 80 ]
Array(5) [ 2, 20, 40, 60, 80 ]
Array(5) [ 2, 20, 40, 60, 80 ]
Array(5) [ 2, 20, 40, 60, 80 ]
2
20
40
60
80

出力結果を確認すると、1次元目の要素には「Array(5) [ 2, 20, 40, 60, 80 ]」というように、1つの要素内にさらに配列が格納されていることがわかります。

次に、2次元目の要素を一つづつ出力しているのですが、順に、2, 20, 40, 60, 80 という形で2次元目の要素を一つづつ出力することができています。

では次に、上記のコードを少し改造して、次のようなコードを書いて実行してみます。

//通常の配列を定義する
let test2 = [1, 10, 20, 30, 60];

//要素の全てを回して処理
for (var i = 0; i < test2.length; i++) {
	//ループ内で、要素ごとに、さらに新規配列を定義して代入する
	//要素内の値に対して i を加算
	test2[i] = [2 + i, 20 + i, 40 + i, 60 + i, 80 + i];
}

//ループ後の結果を出力1(わかりやすいように、1次元目の要素の一つづつ出力する)
console.log(test2[0]);
console.log(test2[1]);
console.log(test2[2]);
console.log(test2[3]);
console.log(test2[4]);

//ループ後の結果を出力2(わかりやすいように、1次元目の要素内の2次元目の要素を出力する)
//2次元目の1つ目の要素を出力してみる
console.log(test2[0][0]);
console.log(test2[0][1]);
console.log(test2[0][2]);
console.log(test2[0][3]);
console.log(test2[0][4]);

//2次元目の2つ目の要素を出力してみる
console.log(test2[1][0]);
console.log(test2[1][1]);
console.log(test2[1][2]);
console.log(test2[1][3]);
console.log(test2[1][4]);

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

Array(5) [ 2, 20, 40, 60, 80 ]
Array(5) [ 3, 21, 41, 61, 81 ]
Array(5) [ 4, 22, 42, 62, 82 ]
Array(5) [ 5, 23, 43, 63, 83 ]
Array(5) [ 6, 24, 44, 64, 84 ]
2
20
40
60
80
3
21
41
61
81

最初の1次元目の出力結果を見てみると、forでループする際のカウンタ「i」の変数が、2次元目の各要素に対して加算されていることがわかります。

2次元目の2つ目の要素を出力してみると、加算された結果として「3, 21, 41, 61, 81」が出力されていることがわかります。

このようにしてjavascriptでも、多次元配列として配列を使うことができ、行列の計算や、座標の計算等に応用すること可能になると言えます。

2次元以上の配列も応用次第で活用することができます。

配列の全ての要素にアクセスする方法

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

概要

配列に対して、全ての要素に順にアクセスする方法を試してみます。
別な言い方をすればイテレータ(反復子とも言います)についての挙動を実際に試します。

forループによるアクセス

実際に次のようなコードを書いて、配列の全ての要素に対して出力を行ってみます。

let test1 = [1, 10, 20, 30, 60, 90];
for (var i = 0; i < test1.length; i++) {
	console.log(test1[i]);
}

上記のコードは単純に配列の全ての要素にアクセスしています。
出力結果は次のようになります。

1
10
20
30
60
90

では、この配列が、途中で値が存在しない場合の配列の場合を試してみます。
配列の3つめ5つめをnullにしてあります。

let test2 = [1, 10, , 30, , 90];
for (var i = 0; i < test2.length; i++) {
	console.log(test2[i]);
}

上記の場合の出力結果は次のようになります。

1
10
undefined
30
undefined
90

ループ処理の3番目と5番目の要素にアクセスする際、配列の要素がないので「undefined」として結果が出力されます。

上記のことから、ループ処理でイテレータの実行する時は、配列の要素が全て存在する場合か、または存在することをチェックするプログラムを書く必要があります。

例えば次のように書くことで配列の要素が存在しない場合はループをスキップすることが可能です。

let test3 = [1, 10, , 30, , 90];
for (var i = 0; i < test3.length; i++) {
	if (test3[i]) {
		console.log(test3[i]);
	}
}

上記のコードの場合は、配列の要素が存在する場合のみtrueと判定されるので、次のような出力結果になります。

1
10
30
90

if文での判定を行う際に、要件仕様によってcontinue等を使って処理をスキップする場合も有用です。

for in によるアクセス

上記のような配列に対して、for文と同じようにアクセスする構文として「for in」という構文があります。
これも同様に動きを試してみます。

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

let test4 = [1, 10, , 30, , 90];
for (var index in test4) {
	console.log(test4[index]);
}

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

1
10
30
90

for in構文の場合、値が空白やnull、undefinedの要素にはアクセスせず、次の要素にアクセスします。

for in構文で注意が必要なのは、動作するブラウザ環境により、処理される順番が担保されないという点です。(降順/昇順などがバラバラになる)

順番を重視する要件の場合にはfor 文を使ったほうが無難と言えます。

forEach()メソッド によるアクセス

では次にforEach()メソッドを使った場合について動作を確認してみます。

次のようなコードを書いて実行してみます。

let test5 = [1, 10, , 30, , 90];
test5.forEach(function(x) {
	console.log(x);
});

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

1
10
30
90

このメソッドを使った場合も、存在しない要素については処理されず、値が存在する要素を処理しています。

また、for inメソッドとの大きな違いは、処理される順番がインデックス順になる。という点です。

上記のような書き方はjavascriptの関数型プログラムに発展することができ、それはまた別な投稿で取り上げたいと思います。

要素の追加と削除

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

概要

配列の要素を追加する場合と、削除する場合について、調べてみます。

要素の追加

配列の要素を追加する動きを確かめるため、次のようなサンプルコードを実行してみます。

let test1 = [];

test1[0] = "abc";
test1[1] = "def";

console.log(test1[0]);
console.log(test1[1]);

配列test1を生成し、要素の1番目と2番目に対して値を入れています。
出力結果は「abc」「def」になります。

さらに次のようなコードを実行してみます。

let test2 = [];

test2.push("abc");
test2.push("def", "ghi");

console.log(test2[0]);
console.log(test2[1]);
console.log(test2[2]);
console.log(test2.length);

test2[test2.length] = "jkl";

console.log(test2[3]);

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

abc
def
ghi
3
jkl

配列に対してのpushは要素を一つ追加して、値を代入する動きをします。
pushは引数が複数ある場合は、配列の一つづつの要素として代入する動きをします。

途中で配列のインデックス「test2.length」に対して値を代入していますが、
「test2.length」とすることで配列の最後の要素を示すことができます。
上記の場合は3つ目の要素に対して値を代入しています。

要素の削除

配列の要素を削除するには、delete演算子を使います。(その他の方法もあります)
次のようなコードを書いて実行してみます。

//要素の削除

let test3 = [];

test3[0] = "z";
test3[1] = "y";
test3[2] = "x";
test3[3] = "w";

console.log(test3[0]);
console.log(test3[1]);
console.log(test3[2]);
console.log(test3[3]);

console.log(test3.length); //出力結果は4

//要素のインデックス1を削除
delete test3[1];

console.log(test3[0]);
console.log(test3[1]); //出力結果はundefined
console.log(test3[2]);
console.log(test3[3]);

console.log(test3.length); //出力結果は4

上記のコードを実行すると、配列test3の1つめの要素をdelete演算子を使って削除しています。
この時、lengthの結果をみても削除前と削除後は結果は変わらないという特徴があります。

その他の配列要素の削除について

上記の例の他、要素を削除するには、popメソッドやshiftメソッドがあります。
delete演算子とは異なり、popやshiftの場合は要素の数が変動します。
この削除のされ方の違いは、プログラムを実装する際に非常に重要になるので、注意して実装します。

pop、shiftについては、また別途、ブログ記事でとりあげる予定です。

配列に対してのlengthプロパティについて

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

概要

配列の長さについて試してみます。
配列の長さはlengthプロパティで調べます。
ここでいう長さとは、要素数と同じことを意味します。

前回のブログ投稿で、疎な配列について書きましたが、その場合は要素数とlengthの長さの関係は、必ずしも一致はしません。

簡単なサンプル

次のような簡単なサンプルコードを書いて動かしてみます。

let test1 = new Array(10);

let test2 = [];

let test3 = [1, 10, 20, 30, 60, 90];

console.log(test1.length);
console.log(test2.length);
console.log(test3.length);

上記の出力結果は「10」「0」「6」になります。

lengthプロパティは通常、配列の要素数を出力する場面で使うことが多いですが、
反対に配列の要素に対してlengthプロパティを使って設定することもできます。

次のコードを書いて実行してみます。

let test4 = [1, 10, 20, 30, 60, 90, 100];

console.log(test4.length);

test4.length = 4;

console.log(test4.length);

最初の出力では「7」と出力されますが、次の出力では「4」と出力されます。
配列test4に対して、lengthプロパティに対して「4」を設定したので、4つ目以降の要素が削除される動きになります。

配列の要素が0から埋まっていない配列

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

概要

これまでのサンプルコードの中でも出てきましたが、
配列の要素が0から埋まっていない配列についてまとめます。
上記のような配列を疎な配列と呼びます。

特徴

この疎な配列の特徴は次のようになります。
この場合のlengthで取得した要素数は、実際の要素数よりは大きくなります。
疎な配列は実行速度は遅くなる代わりに、メモリ効率は上がります。

配列リテラルで値を省略した場合の挙動

配列を生成する再に、配列リテラルで生成し、その値が無い場合(省略した場合)は、疎な配列にはならないです。
この場合は、undefinedの値として配列が生成されます。

配列の要素へのアクセス方法について

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

概要

javascriptの配列について、要素へのアクセス方法について試してみます。

配列への代入

配列の要素にアクセスする方法は[]演算子を使います。
具体的には次のようなコードになります。

//要素が空の配列を作成
let test1 = [];

//要素の1に値を代入
//(この時、配列の0番目はemptyで空なので全体の要素数は1つ)
test1[1] = 10;

//要素の0に文字列「abc」を代入
test1[0] = "abc";

//要素へのアクセスに変数を使う(その1)
let arr_str = 4
test1[arr_str] = "efg";

//要素へのアクセスに式を使う(その2)
let arr_cal = 5;
test1[arr_cal + 10] = "hij";

便宜上、開発ツールのログ出力命令は省略していますが、出力結果は次のようになります。

Array [ <1 empty slot>, 10 ]

Array [ "abc", 10 ]

Array(5) [ "abc", 10, <2 empty slots>, "efg" ]

(16) […]
0: "abc"
1: 10
4: "efg"
15: "hij"
length: 16
<prototype>: Array []

(<>で表現している箇所は、ブログの構造上、半角文字の「<>」ですが、表示エラーになるので全角にしています)

上記の4つ目の出力結果だけは、配列を展開した形で出力を確かめています。

代入した値の取得

次に配列に代入した値を取り出してみます。

ここで注意が必要なことは、上記の例で配列で値を代入する場合、
配列のインデックスとしての「1」を使っていますが、実際は文字列の1として要素名を確定していることです。
これは[]演算子を使って配列の値を代入する場合の動作になるので注意が必要です。

値を取り出すには次のような書き方をします。

console.log(test1[0]);
console.log(test1[1]);
console.log(test1[13]);

便宜上、console.logで出力していますが、実際には「test1[0]」のように記述します。

上記の実行結果は、値が正常に取得できた場合は、配列内の値を取得、
インデックスが正しくない、存在しない場合は、undefinedが出力されます。

上記の例は次のようになります。

abc
10
undefined

当然、3番目の例は、配列のインデックスの13には要素を代入していないので、値の取得ができずにundefinedになります。
javascriptでは配列の値が取得できない場合はエラーで処理落ちすることなく、undefinedになるので注意が必要です。

配列の要素数について

配列を定義し、値を代入して利用すると、代入した数だけの要素が増えることになります。(要素を削除しない限りは)

要素数を出力するには、lengthプロパティを使います。

console.log(test1.length);

上記の出力結果は「16」となります。
ここで16となる理由を考察してみると、全ての要素に値を格納されている訳ではなく、
一番最初の値の代入の際に

let arr_cal = 5;
test1[arr_cal + 10] = "hij";

という配列の添え字に整数を使って代入した為、配列のインデックスとして解釈され、0から15までの要素が作成された為になります。
この時、途中で要素の代入をしていないインデックスは空(undefined)という形で要素が生成されます。

上記の考えにより「console.log(test1[13]);」という出力は「undefined」という形で出力されると言えます。

配列のインデックスに非整数値を使った場合

ここまでは配列のインデックスに数値を使ってきましたが、
あえて文字列を設定して代入と取得を試してみます。

次のようなコードを書いて実行してみます。

let test2 = [];

test2["z"] = 10;

console.log(test2);

出力結果は

[]
length: 0
z: 10
<prototype>: Array []

のようになります。
配列のN番目に値が格納されているわけではなく、配列のプロパティ名「z」に対して、値「10」が格納されていることになります。

試しに、この配列に対して、0番目や1番目の要素を取得してみます。

console.log(test2[0]);
console.log(test2[1]);

出力結果は、共に「undefined」になります。

また、この状態で配列test2に対してlengthを取得してみます。

console.log(test2.length);

出力結果は、「0」になります。

配列のインデックスに非整数値を使った場合(その2)

では、配列のインデックスにマイナスの値を使うとどうなるか試してみます。

次のようなコードを書いて実行します。

let test3 = [];

test3[-50] = 100;

console.log(test3);

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

[]
"-50": 100
length: 0
<prototype>: Array []

インデックスに「-50」と指定しましたが、この場合の動きは要素の「数」としてのインデックスではなく「-50」というプロパティ名として解釈され、「-50」の要素として「100」が配列に格納されている動きになります。

オブジェクトに対してのメソッド

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

概要

javascriptのオブジェクトに対してのメソッドを調べてみます。

javascriptのオブジェクトは全てObject.prototypeからプロパティとメソッドを継承しています。
代表的なメソッドを具体的に調べてみます。

toString()

toString()メソッドはオブジェクトの値を表す文字列を返します。
オブジェクトを文字列に変換する必要がある場合、このメソッドを呼び出します。
例えば、配列を文字列に変換すれば、文字列に変換された配列要素のリストが取得できます。

toLocaleString()

このメソッドはオブジェクトを表すローカライズされた文字列を返します。

valueOf()

このメソッドは文字列以外の基本型にオブジェクトを変換する必要があるときに使います。

オブジェクトのシリアライズ

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

オブジェクトのシリアライズ

javascriptのオブジェクトのシリアライズについて、試してみます。

オブジェクトのシリアライズは、一度シリアライズしたオブジェクトを元に戻せるような文字列に変換します。
他のプログラム言語にもあるように、シリアライズ操作はプログラミングをするうえで要所で使う場面が出てきます。

ネイティブ関数の使用

まず、オブジェクトをシリアライズするケースからです。
javascriptのネイティブ関数として、JSON.stringify()という関数が用意されています。

逆に一度シリアライズした文字列をアンシリアライズ(元に戻す)場合は、
JSON.parse()という関数が用意されています。

実際にシリアライズを試してみます

まずは、検証用オブジェクトをシリアライズして、ブラウザの開発ツールでログ出力してみます。

//テスト用オブジェクトの用意
let test1 = {
	a: '10',
	b: '20',
	get access_a() {
		return this.a;
	}
}

//オブジェクト「test1」をシリアライズします
let s_obj = JSON.stringify(test1);

console.log(s_obj);

//出力結果は、以下のようになる
{"a":"10","b":"20","access_a":"10"}

以上のような出力結果になりました。

次にアンシリアライズを試してみます

上記の例で使用した変数を、そのままアンシリアライズしてみます。

//(先ほどシリアライズした際の変数を使用)アンシリアライズ
let us_obj = JSON.parse(s_obj);

console.log(us_obj);

//出力結果
Object { a: "10", b: "20", access_a: "10" }

出力結果は上記のようになります。
ブラウザごとに出力結果の表示方法は変わるので、見え方は異なりますが、オブジェクトの内容が列挙されます。

JSON形式について

json形式はjavascrptでプログラムする際に頻繁に使用するデータ形式になります。

正式には「Javascript Object notation」という名称になり、javascriptでオブジェクトリテラルや配列リテラルににたデータ形式でデータ構造を表したり、保持したりします。

シリアライズ可能なものと不可能なもの

シリアライズはjavascriptの値を全てサポートしているわけではないです。

次にサポートしているものと、サポートしていないものを整理してみます。

サポートしているもの

オブジェクト
文字列
配列
数値
true
false
null
NaN
Infinity
Dateオブジェクト

サポートされていないもの

Function
RegExp
Error
undefined

オブジェクトの拡張可属性について

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

オブジェクトの拡張可属性

オブジェクトに対して、新しくプロパティを追加できるかどうかの指定ができます。
この指定のことを拡張可属性と呼びます。

オブジェクトが拡張可かどうかは、ECMAScriptの処理系によって変わってきます。

ES5は組み込みオブジェクトとユーザ定義オブジェクトは拡張可になります。
明示的に拡張不可が設定された場合は拡張不可になります。

拡張可か拡張不可かを調べるには、Object.isExtensible()で調べます。

オブジェクトと拡張不可にするには、Object.preventExtensions()を使います。

オブジェクトの全ての独自プロパティを再定義不可にするには、Object.seal()を使います。
この場合、オブジェクトに新しいプロパティを追加することはできず、
削除することも再定義することもできません。

オブジェクトをロックするには、Object.freeze()を使います。
オブジェクトを拡張不可にしてプロパティの再定義も不可になります。
また、オブジェクトの独自データプロパティを読み出し専用にします。

オブジェクトのクラス属性について

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

概要

クラス属性について調べてみます。

クラス属性はオブジェクトの型情報を表す文字列です。
この属性は文字列として設定されており、取得の方法は限定的です。

オブジェクトからクラス属性を取得するにはtoString()メソッドを使います。

実際に簡単なコードを書いてみて動作させてみます。

var test1 = {
	a: '10',
	b: '20',
	get access_a() {
		return this.a;
	}
}
console.log(Object.prototype.toString.call(test1));

var test2 = new Object();
console.log(Object.prototype.toString.call(test2));

var test3 = new Array();
console.log(Object.prototype.toString.call(test3));

var test4 = new Date();
console.log(Object.prototype.toString.call(test4));

上記のコードの実行結果をブラウザの開発ツール(コンソール出力)で確認すると、次のようになります。

[object Object]
[object Object]
[object Array]
[object Date]

出力のルールとしては、先頭部分に「[object]」という文字列が必ず出力されており、その後にオブジェクトのクラス属性が出力されます。

オブジェクト属性の種類について

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

概要

javascriptのオブジェクトの属性には、3種類の属性があり、
オブジェクトの属性ごとに、使用方法や取得方法、設定方法が変わってきます。

いままではオブジェクトの属性を意識せずにサンプルのコードを書いていましたが、属性ごと詳しく違いを調べてみます。

プロトタイプ属性

オブジェクトが生成されるときにプロトタイプ属性が設定され、オブジェクトの生成方法によってプロトタイプの設定のされかたが変わります。オブジェクトリテラルを使って生成する場合
object.prototype
がプロトタイプ属性使われます。

newを使って生成する場合
コンストラクタ関数のprototypeプロパティの値が使われます。

Object.create()を使って生成する場合
Object.create()に渡された最初の引数が使われます。

オブジェクトのプロパティ属性について

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

概要

オブジェクトのプロパティには属性があります。

属性は大きく分けて「書き込み可能」「列挙可能」「再定義可能」などがあります。

また、アクセサプロパティのゲッターメソッドとセッターメソッドをプロパティ属性として考えるとすると、アクセサプロパティには書き込み可能属性がないと言えます。

データプロパティの属性は、値も属性のひとつとみなし、書き込み可能、列挙可能、再定義可能、の合計4つの属性があると言えます。
(アクセサプロパティには値の属性はないものと考えます)

まとめるとアクセサプロパティは、ゲッター、セッター、列挙可能、再定義可能、の4つの属性があると言えます。

プロパティのメタ属性の取得と設定


上記の概要で書いた4つの属性について、プロパティディスクリプタと呼ばれるオブジェクトを使います。

プロパティディスクリプタはプロパティのメタ属性と言え、データアクセスに対しての取り決めを決定しています。

データプロパティについては、次のようなメタ属性の名前を持ちます。
value
writable
enumerable
configurable
また、アクセサプロパティについては、次のようなメタ属性を持ちます。
get
set
enumerable
configurable
アクセサプロパティは、valueとwritableのメタ属性はありません。

試しに、前回の投稿で書いたサンプルコードに対して、プロパティディスクリプタオブジェクトを取得して試してみます。
var test = {
	a: '10',
	b: '20',
	get access_a() {
		return this.a;
	}
}

//プロパティディスクリプタオブジェクトを使用してtestオブジェクトのプロパティを出力
console.log(Object.getOwnPropertyDescriptor(test, 'a'));
上記のサンプルコードを実行した結果は次のようになります。

{…}

configurable: true

enumerable: true

value: "10"

writable: true

&lt;prototype&gt;: {…}

__defineGetter__: function __defineGetter__()

__defineSetter__: function __defineSetter__()

__lookupGetter__: function __lookupGetter__()

__lookupSetter__: function __lookupSetter__()

constructor: function Object()

hasOwnProperty: function hasOwnProperty()

isPrototypeOf: function isPrototypeOf()

propertyIsEnumerable: function propertyIsEnumerable()

toLocaleString: function toLocaleString()

toSource: function toSource()

toString: function toString()

valueOf: valueOf()

ブラウザの開発ツールの出力なので、出力結果がまとめられている箇所があり、出力結果のオープン/クローズで表示されるので一部抜粋しています。

上記の出力結果では
configurable: true

enumerable: true

value: "10"

writable: true
という先ほどあげたメタ属性についての記述があります。
また、上記の結果から、testオブジェクトのaプロパティは、データプロパティであることがわかります。(get、setが無く、valueやwritable属性が表示されています)

また、getOwnPropertyDescriptor()の処理対象はオブジェクトに対して独自プロパティのみが対象となります。
継承されたプロパティ等は対象ではない為に、継承オブジェクトには明示的にgetOwnPropertyDescriptor()を書く必要があります。

definePropertyについて

ここまでは、getOwnPropertyDescriptorを使ってオブジェクトのプロパティを調べる形でしたが、
オブジェクトのプロパティに対して、属性を設定(変更)するメソッドについても調べてみます。

オブジェクトに対してプロパティの属性を変更するには、
defineProperty
を使います。

書き方は
Object.defineProperty()
という形になり、()内で設定したいオブジェクトと、プロパティ名、それと属性(上記でいうメタ属性)を設定します。

具体的には、次のようになります。
var test = {
	a: '10',
	b: '20',
	get access_a() {
		return this.a;
	}
}

//definePropertyを使用して属性の変更
Object.defineProperty(test, 'a', {
	value: '30',
	writable: false,
});

//testオブジェクトのプロパティaに対し、文字列40を代入する
test.a = '40';

//内容を確認
console.log(test.a); //出力結果「30」
上記の例はtestオブジェクトのプロパティaに対して、メタ属性を変更しています。また、値の設定についても同時に行っています。

出力結果については、「30」と出力され、writableでfalseにしている為、値の代入を行っても書き変わらない挙動になります。

以上のように、オブジェクトのプロパティに対しての属性の設定を簡単に試してみました。

上記以外の命令や書き方があるので、ブログに追記する形で更新いたします。

ゲッターメソッドとセッターメソッド

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

概要

javascriptのオブジェクトについては、前回の投稿で簡単なオブジェクトの書き方、使い方を例にあげました。

オブジェクトについて、もう少し入り組んだ概念について詰めます。

オブジェクトに対してゲッターとセッターと呼ぶメソッドを指定でき、それぞれプロパティという位置づけで解釈することができます。

また、ゲッターとセッターについては、それぞれアクセサプロパティと、データプロパティという名前で区別して考えることができます。

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

アクセサプロパティは書き込み不可の属性です。

プロパティがゲッターとセッターの両方のメソッドを持つ場合、 読み書き可のプロパティになります。

ゲッターしかない場合は、読み出し専用のプロパティになり、
セッターしかない場合は、書き込み専用のプロパティになります。

また、データプロパティは単純に値のみを持ちます。

簡単な例

具体的なゲッターメソッドは次のように定義します。

//ゲッター
var test = {
	a: '10',
	b: '20',
	get access_a() {
		return this.a;
	}
}

//呼び出す時の書き方
console.log(test.access_a);
この場合は、変数testに対して、ゲッターメソッド「access_a」を定義しています。

access_aを呼び出すと、メソッド内でプロパティaの値が、返されます。

文字通り「get」キーワードを下記、その後にメソッド名と処理を書きます。

次にセッターメソッドの場合は次のように定義します。

//セッター
var test = {
	c: '30',
	d: '40',
	get access_c() {
		return this.c;
	},
	set access_c(value) {

		//わかりやすいように10倍に計算する
		var sub_c = value * 10;

		this.c = sub_c;
	},
}

//呼び出す時の書き方
console.log(test.access_c); //出力結果「30」

//testオブジェクトのセッタプロパティに対して値を代入
test.access_c = 50;

console.log(test.access_c); //出力結果「500」

上記のようにセッターメソッドを使う時は、オブジェクトのプロパティに対して値を代入するように書きます。

例ではわかりやすいように、セッターメソッド内で値を10倍にして返しています。

セッターに値を入れた後に、改めてゲッターメソッドを使うと、出力結果は計算された結果が返ってきます。

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

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

概要

javascriptのオブジェクトのプロパティにアクセスする方法を試してみます。 簡単な方法として、for in を使ってオブジェクトにアクセスしてみます。 具体的には下記のように書きます。
var test = {a:10, b:20, c:30}

for (hoge in test) {
	console.log("hoge -> " + hoge);
}

//出力結果は次のようになります
hoge -> a
hoge -> b
hoge -> c
上記のようにfor inを使うとオブジェクト内の「プロパティ」にアクセスすることができます。 では、オブジェクト内の「値」にアクセスするにはどうすればよいか、試してみます。
var test = {a:10, b:20, c:30}

for (hoge in test) {
	console.log("hoge -> " + test[hoge]);
}

//出力結果は次のようになります
hoge -> 10
hoge -> 20
hoge -> 30
最初の例と似ていますが、for inで回した値を参照するタイミングで「オブジェクト[プロパティ]」という記述することで内容を取得することが可能になります。 上記の例は必ずしもこう書かないといけないわけではないので、参考例として書いています。 また、オブジェクトが継承されているケースもあるので、プログラムの実装時には挙動に注意が必要です。

オブジェクトの内容を確認する

オブジェクトの内容が、配列、文字列、オブジェクト等、不明な場合は下記のように書いて簡易的に調べることができます。
// 「obj_check」は調べたいオブジェクト
for(let key in obj_check){
    console.log(key + " : " + obj_check[key]);
}

オブジェクトの内容を確認する(よりシンプルな方法①)

以下のように書くと、テーブル形式でobj_checkの内容を確認できます。
console.table(obj_check)

オブジェクトの内容を確認する(よりシンプルな方法② json.stringify)

以下のように書くと、テーブル形式でobj_checkの内容を確認できます。
console.log(JSON.stringify(obj_check, null, 2))
ただし、最近のブラウザの開発ツールはどんどん改善されているので、いちいちコードを書かなくてもオブジェクトの内容を把握できる方法があるかと思います。 簡易的なチェックという認識で使用するとよさそうです。

オブジェクトのプロパティの削除

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

概要

javascriptでの、オブジェクトのプロパティの削除についてです。

これまでにもこのブログで出てきましたが、オブジェクトのプロパティを削除するには、delete演算子を使います。

前回のオブジェクト生成の例をもとにdelete演算子の挙動をみてみます。

//新規でオブジェクトを生成する
var test = {a:1, b:2}
  
//.で読み出す
console.log(test.a);
  
//[]で読み出す
console.log(test["a"]);

//delete演算子を使って、プロパティ「a」を削除する
delete test.a;

//delete演算子を使って、プロパティ「b」を削除する
delete test[b];

上記の場合、前者の削除の方法は.を使ってプロパティを指定しています。
後者の削除の方法は[]を使ってプロパティを指定しています。
どちらも同じ同様の動きになります。

注意する点としては、継承されたオブジェクトの継承プロパティは削除されないことです。

delete演算子はプロパティの削除が成功した場合にtrueを返します。
delete演算子は、再定義可の属性がfalseになっているプロパティは削除しないです。

また、注意しなければならないのは、use strictモードの場合と非use strictモードの場合で、挙動が異なる点です。
use strictモードでは再定義不可のプロパティを削除するとtype error例外が発生します。
非use strictモードでは同様の削除をするとfalseを返します。

オブジェクトのプロパティ呼び出しについて

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

概要

オブジェクトのプロパティの呼び出しについてです。

プロパティを呼び出す時の注意点としては、次のような点があります。

・存在しないプロパティから値を取得する
・独自プロパティから値を取得する
・継承したオブジェクトのプロパティから値を取得する
・存在しないオブジェクトからプロパティの値を取得する

上記の点では、存在しないプロパティから値を取得しようとしてもエラーにはならず、undefinedになります。
また、独自プロパティ、継承したオブジェクトのプロパティから値を取得しようとしても存在しないプロパティの場合はundefinedになります。

ただし、存在しないオブジェクトからプロパティを読み出すとエラーになります。(上記4つめのケース)

オブジェクトの継承とプロトタイプオブジェクト、プロトタイプへの参照と代入の挙動について

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

概要

javascriptのオブジェクトと、オブジェクトの継承、そしてオブジェクトのプロパティへのアクセスについてまとめます。

javascriptのオブジェクトの独自プロパティについては、そのオブジェクトとプロトタイプオブジェクトから継承したプロパティがあります。

オブジェクトのプロパティへのアクセスについて

例としてオブジェクトAの独自プロパティpを参照しようとする場合、
オブジェクトAの独自プロパティpにアクセスします。

この際、独自プロパティpがオブジェクトAに存在しなければ、
オブジェクトAのプロトタイプオブジェクトA'(ここでは便宜上A’とします)のプロパティpがあるかチェックします。

プロトタイプオブジェクトA’が、プロトタイプチェーンにより、さらにプロトタイプオブジェクトが継承されている場合は、その継承しているプロトタイプオブジェクト(オブジェクトA”とします)のプロパティpがあるかチェックします。

上記のような流れで任意のオブジェクトの任意のプロパティへアクセスする挙動になります。

文章にするとわかりにくい面があるので、簡単なイメージ図にしていみました。

オブジェクトのプロパティへ値を代入する場合

上記の例とは反対に、オブジェクトAのプロパティpに対して、値を代入する場合の挙動をまとめます。

参照する場合とは反対に代入する場合は、動きが変わってきます。

まず、オブジェクトAにプロパティpが存在する場合は、
プロパティpの値がそのまま変更されて終了します。
この場合、プロトタイプチェーンで継承されているオブジェクトのプロパティは無関係で影響を受けません。

次に、オブジェクトAにプロパティpが存在しない場合は、
オブジェクトAに対して、プロパティpが新規追加されます。
この場合も、プロトタイプチェーンで継承されているオブジェクトのプロパティは無関係で影響を受けません。


オブジェクトのプロパティを連想配列として解釈する

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

概要

前回の投稿では、生成したオブジェクトのプロパティにアクセスする方法を書きました。

//新規でオブジェクトを生成する
var test = {a:1, b:2}
 
//.で読み出す
console.log(test.a);
 
//[]で読み出す
console.log(test["a"]);

上記の方法で、2つ目に書いた[]で読み出す方法について、詳しくみてみます。
.で呼び出す方法と[]で呼び出す方法は、どちらも同じ結果を得ることができますが、[]で呼び出す方法については、文字列を使って呼び出していることが特徴的です。

文字列で呼び出すことが特徴なので、オブジェクトを配列と見立てると連想配列として考えることができます。

より、簡単な方法でオブジェクトの中身を確認する

コンソール上で [object Object] という表示になった場合、
以下の方法で内容を確認することができます。

console.log(JSON.stringify(確認したいオブジェクト));

連想配列としてのオブジェクト

連想配列としてのオブジェクトとして考えると、javascript特有の柔軟な配列操作が可能になります。

例えば以下のように、オブジェクトのプロパティ名が動的に変わる場合でも処理がされます。

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

//新たなプロパティを指定して値をセット
//例1
test["c"] = 3;

//例2
test["d"] = 4;


//プロパティ名に、動的な変数を使用
var o = 1;
//例3
test["e" + o] = 5;

//例4
test["e" + (o + 1)] = 6;


//プロパティ名に、動的な変数を使用(その2)
var p = 3;
//例5
test["e" + p] = 7;

//例6
test[p] = 8;


//プロパティ名に、動的な変数を使用(その3)
var q = 4;

//例7
test[q] = 9;

//例8
test[q + 4] = 10;


//確認の為、呼び出し
console.log(test["a"]);   //出力結果:1
console.log(test["b"]);   //出力結果:2
console.log(test["c"]);   //出力結果:3
console.log(test["d"]);   //出力結果:4
console.log(test["e1"]);  //出力結果:5
console.log(test["e2"]);  //出力結果:6
console.log(test["e3"]);  //出力結果:7
console.log(test[p]);     //出力結果:8
console.log(test["p"]);   //出力結果:undefined
console.log(test[q]);     //出力結果:9
console.log(test[4]);     //出力結果:9
console.log(test["q"]);   //出力結果:undefined
console.log(test[8]);     //出力結果:10

後半の例6、例7、例8は少し紛らわしく書きました。

例6について

オブジェクトのプロパティを文字列を示すダブルクォートで囲っていないので、
これは単純に配列のn番目に値を代入する動きになります。

その証拠として、例8ではプロパティを単なる数値として直接指定して値を呼び出しても出力結果が「10」という形で取り出せます。

また、例6に対して、

test["p"]

とした場合の出力結果はundefinedになります。

これはtest[p]という(pは数値の3が代入されている)オブジェクトのプロパティへ代入していますが、pは数値の3なので配列の3番目(0はじまりだと4番目)に値を代入している解釈になるので、
文字列としてのtest[“p”]という形で値を取り出そうとしても存在しない為にundefinedになります。

例7について

オブジェクトのプロパティに対して数値を指定している為、
値を参照する際にも、test[“q”]という形で文字列として取り出そうとするとundefinedになります。

例8について

オブジェクトのプロパティが数値の加算になっているので、
配列の添え字として解釈され、問題なく値が取得できます。

オブジェクトのプロパティ読み出しについて

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

オブジェクトのプロパティを読み出す方法

オブジェクトのプロパティを読み出す方法は、
以前の投稿でも取り上げましたが、次のように書きます。

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

//.で読み出す
console.log(test.a);

//[]で読み出す
console.log(test["a"]);

上記はtestオブジェクトを生成し、その中からaというプロパティの値を読み出しています。

オブジェクトのプロパティに値を代入する方法

上記の例とは逆にオブジェクトのプロパティに値を代入する方法は次のように書きます。

//上記で生成したオブジェクトを使用
test.a = 10;

//.で読み出す
console.log(test.a);

test["b"] = 20
//[]で読み出す
console.log(test["b"]);

オブジェクトの生成

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

概要

javascript内でオブジェクトを生成する方法を試してみます。

オブジェクトの生成の方法は、次のとおりです。

①オブジェクトリテラルを使って生成
②newキーワードを使って生成
③Object.create()を使って生成

③の方法はECMAScript5の言語仕様に則ってプログラミングする場合に有効です。

オブジェクトリテラル

オブジェクトリテラルを使った生成を試してみます。
変数を宣言し、その変数に対して、新規のオブジェクトを生成し、代入します。

オブジェクトリテラルは、中括弧を使い、内部には「プロパティ名」と「値」をペアでカンマ区切りで記述します。
プロパティ名と値はコロンで区切ります。

//オブジェクトリテラルによる生成

//空のオブジェクトを生成する
var testobject = {};
console.log(testobject); //出力結果「Object {  }」

//要素を2つ持つオブジェクトを生成する
var testobject2 = {a:10, b:20};
console.log(testobject2); //出力結果「Object { a: 10, b: 20 }」

//オブジェクト内の要素が他のオブジェクトのデータを扱う場合
var testobject3 = {c:testobject2.a, d:testobject2.b};
console.log(testobject3); //出力結果「Object { c: 10, d: 20 }」

リテラルを使ったオブジェクトで、プロパティ名に予約語を使う場合は注意が必要です。
ECMAScriptのバージョンによって挙動が変わるので、
各バージョンにより、挙動を確かめてプログラムする必要があります。
一般的にはプロパティ名には予約語ではない文字列を割り当てたほうがプログラミングしやすいかもしれないです。

newキーワードを使った生成

new演算子を使ってオブジェクトを生成します。
new演算子のあとに関数呼び出しを記述して、オブジェクトを生成します。
オブジェクトが生成されるときに必ず実行される関数をコンストラクタと呼び、内部で初期化等の動作をします(各関数によって動作が違うので、詳しくはリファレンスを調べる必要があります)

実際の動きについて、簡単なコードを書いて出力結果を確認してみます。

//newキーワードで生成

//空のオブジェクト生成
var testobj1 = new Object();
console.log(testobj1); //出力結果「Object {  }」

//空の配列オブジェクトを生成
var testobj2 = new Array();
console.log(testobj2); //出力結果「Array []」

//日時を扱うオブジェクトを生成
var testobj3 = new Date();
console.log(testobj3); //出力結果「Date 2018-11-14T12:30:02.403Z」

オブジェクト

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

概要

javascriptのオブジェクトについての概要です。

・オブジェクトは複合型のデータ型になります。
・複数のデータをまとめて保持し、読み書きが可能です。
・データをプロパティとして呼ぶこともある。
・プロパティは原則、文字列として指定する。
・各プロパティ(文字列)に対し、値をマッピングする。
・マッピングしたものには呼び名がつけられる(ハッシュ、連想配列等)

・オブジェクトは、文字列、数値、真偽値(true/false)、null、undefined以外の値になる。
・オブジェクトは可変の振る舞いをする。(値を参照で操作する)

・オブジェクトの操作は、生成、プロパティへの値の代入、読み出し、削除など。
・同名のプロパティはNG。
・プロパティは「名前と値」の組み合わせ。その他「プロパティ属性」という値を持つ。
・プロパティ属性は「書き込み可」「列挙可」「再定義可」がある。

・オブジェクトはオブジェクト属性を持つ。「プロトタイプ」「クラス」「拡張可フラグ」
・オブジェクトは大きく3種類あり、「ネイティブオブジェクト」「ホストオブジェクト」「ユーザ定義オブジェクト」
・プロパティは大きく2種類あり、「独自プロパティ」「継承プロパティ」

javascriptのオブジェクトの特徴

オブジェクト自身のプロパティの他、ほかのオブジェクトのプロパティも「継承」することができる。
継承の対象となるオブジェクトをプロトタイプと呼びます。

オブジェクトの詳細な挙動について

javascriptのプログラムをより深く正確にする為には、
オブジェクトについての理解を深める必要があります。

オブジェクトの詳細な挙動は、一つ一つこのブログで掘り下げて、できるだけサンプルプログラムを書いて、挙動を確かめながら記事化していきます。

文についてまとめ

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

概要

javascriptの文についてまとめます。

文はまず、式文と宣言文があり、式文は何らかの処理を書くことで作用します。
宣言文は変数や関数を宣言し定義するための文です。

また、実行順序を変更したり制御する為の制御文もあります。
制御文には以下のようなものがあります。
・条件文
if
swich
・ループ文
for
while
・ジャンプ文
break
return
throw

式文

もっとも簡単な文で、変数の代入や、インクリメント、デクリメント、オブジェクトのプロパティ削除のdeleteなども式文として使われます。

複合文

複合文とは文ブロック

{

}

で囲んで記述される文です。
文ブロックは末尾にセミコロンを記述しません。

宣言文

var
function
等の宣言する文が宣言文です。
変数の宣言と関数の宣言を行います。

var

変数を明示的に宣言する文です。

function

関数を明示的に宣言する文です。
javascriptの関数は、次のように宣言する方法

function test() {

}

や、次のように関数を変数に代入する式もあります。

var ftest = function test() {

}

//呼び出す時
ftest();

条件文

指定された式の値に応じて、他の文を実行したり、処理を分岐したりします。
条件文は「if文」や「if else」、「switch文」などあります。

if文

javascriptが条件を判定して、処理を分岐する文です。

if else文

if文と組み合わせて書きます。
これまで何度もサンプルコードを書いてきましたので、詳しい内容は割愛します。

switch文

ある一つの判定要素に対し、条件分岐が多数ある場合に用いる書き方です。
簡単なサンプルを書きます。

var test = 10;

swicth(test) {
	case 1:
		//処理A
		break;
	case 5:
		//処理B
		break;
	case 10:
		//処理C
		break;
	case 15:
		//処理D
		break;
	default:
		//処理E
		break;
}

上記の場合、変数testの値を判定し、処理Cが実行されます。
処理後のbreakを書かなければ、そのまま次の処理(上記の場合は処理D)が実行されます。

if else文のelseを連続的に書くよりは、この書き方のほうが処理のみとおしが立ちやすくなります。

ループ文 – while

とある条件が真の間、処理を繰り返すループです。

ループ文 – do while

とある条件が真の間、処理を繰り返すループです。
while文との違いは、最初の1回目は条件の真偽に関係なく、必ず実行されます。

ループ文 – for

カウンタ変数を持ち、そのカウンタの条件が真の間は処理を繰り返すループです。

ループ文 – for inf

オブジェクトに対して、オブジェクトのプロパティを巡回する時に書きます。

for (var test in testobject) {
	console.log(testobject[test]);
}

のように書きます。
オブジェクトについて深く理解する必要があるので、オブジェクトとプロパティについては、別途堀さげて書きます。

ジャンプ文

ループの処理中に、条件や状態により、処理をジャンプする場合に書きます。
breakやcontinueを使います。

ラベル文

先頭に識別子を書き、その後にコロンを書き、最後に文を記述します。

testlabel:while(1) {
	//ループ内の処理
	
	//ラベルを利用して、ループ処理を実行
	continue testlabel;
}

上記の例はラベル「testlabel」を宣言し、その後のwhileループを割り当てています。
ループ処理内のtestlabelの文が実行されると、ラベルしたwhileが実行されます。
上記のサンプルは極端な例ですが、ラベルの行でジャンプするイメージになります。

break文

ループ処理中に、処理をとめてループを抜ける時に書きます。

continue文

ループ処理中に、continue文より後の処理は実行せず、またループの最初から処理を開始する時に書きます。
一般的には条件文の後に、指定条件の場合にcontinue文を書くケースが多いです。

return文

関数内の処理が完了し、関数を抜けて結果を返す処理として書きます。

throw文

ある例外的な条件やエラーが発生したことを示すシグナルのことです。
次のようにループの処理中に、例外を強制発動することができます。

for (var i=0; i<10; i++) {
	//例外が発生した場合にスローする
	throw new Error("Err");
}

try catch finally文

java言語とよく似ていますが、プログラム中の処理を試み、
例外が発生した場合は、処理をcatchし、全ての処理後にfinallyを実行する文です。

with文

実用性は低いですが、オブジェクトが入れ子になっている場合や、
多数のオブジェクトのプロパティに何度もアクセスする場合に使います。

use strict文

ECMAScript5で導入された指示子です。
この指示子が書かれたプログラムは、厳密なコードであることが要求され、
プログラムもまた厳密に書きます。(とは言っても常に正確に記述することは基本です)

カンマ演算子

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

概要

一般的にプログラムを書いていると、よく使用するカンマですが、
javascriptではカンマも演算子と解釈するケースがあります。

セパレータとしてのカンマと、演算子としてのカンマがあります。

また、C言語やC++でもカンマ演算子はあります。
言語のできた順からするとCやC++のほうが先になります。
(C言語は1972年頃、C++は1983年頃、javascriptは1995年頃)

カンマ演算子の挙動

カンマ演算子は、左被演算子を評価して、その値を捨て、右被演算子を評価する動きになります。

演算子の実行例

実際にこの演算子について、コーディングして動作を確かめてみます。

//セパレータとしてのカンマ(変数の宣言なので、カンマ演算子では無い)
var x = 10, y = 20, z = 30;

//カンマ演算子としてのカンマ
var ret = (x, y, z);
console.log(ret); //出力結果「30」カンマ区切りの最後の文字列が代入される


//代入処理がされる場合
var ret = x, y, z;
console.log(ret); //出力結果「10」カンマ区切りの最初の文字列が代入される


//加算演算子を含む場合
var ret = (x += 2, y +=3, z += 4);
console.log(ret); //出力結果「34」


//加算演算子を含む場合(括弧をつけない場合)
var ret = x += 2, y +=3, z += 4;
//出力結果は「SyntaxError: unexpected token: '+='」
//javascriptでは、上記の書き方はエラーになる


//インクリメント
var x = 10, y = 20, z = 30;
x++, x++;
console.log(x); //出力結果「12」


//カンマ演算子を二項演算子の左辺に下記、値を代入する
(x, y) = 40;
//出力結果「ReferenceError: invalid assignment left-hand side」
//javascritpの言語仕様としてエラーになる

上記のような結果になります。
「左被演算子を評価して、その値を捨て、右被演算子を評価する」と一言で言っても、括弧の有無で挙動が変わる点に注意が必要です。

void演算子

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

概要

あまり見慣れないvoid演算子についてまとめます。

void演算子は単項演算子で、オペランド値を廃棄し未定義値を返す動作をします。

実際の使用場面

void演算子は特殊な利用用途以外では、あまりプログラムしません。

働きとして、戻り値がundefineにならなけれならない場合に使用することが多いです。

typeof演算子

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

概要

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

オペランドは1つのみで演算します。

オペランドの「データ型」(文字列)を返します。

typeof演算子で判定できる値について

typeof演算子は、以下の値を演算(判定)することができます。

undefined
null
true/false
数値
NaN
文字列
関数
ネイティブオブジェクト
ホストオブジェクト

条件演算子

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

概要

条件演算子は「?:」で記述する演算子です。
一般的にこれは三項演算子と呼ばれ、オペランドを3つ使い演算を行います。
先頭のオペランドの後に「?」を記述し、その後、2つ目のオペランドを記述し、その後「:」に続けて3つ目のオペランドを記述します。

書き方としては、次のようになります。

判定条件 ? 結果1 : 結果2

判定条件がtrueの場合は結果1のオペランドの値を評価し、falseの場合は結果2のオペランドの値を評価します。

三項演算子については、他の言語にもあり、開発時の環境やプログラマによっても意見が分かれるケースがあります。

eval()

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

概要

eval()について、詳しく調べてみます。

eval()は1つの引数を渡します。
引数として文字列を渡し、それ以外の場合はそのままの値を返します。

引数が解釈できない場合はシンタックスエラー例外になります。
解釈できた場合は、引数を評価します。

実行例1

eval()を呼び出すとき、呼び出したコードの環境変数が使われます。

実際にeval()で呼び出されたコードの変数が使われるかどうか、
例えば、次のようなコードを書いてみます。

var x = "123";

console.log(eval("x"));

出力結果は

123

になり、eval()で「x」という変数を呼び出したことになります。

実行例2

eval()の引数内で変数定義や関数定義も可能です。
また、定義した変数に値を代入することもできます。
例えば、次のようなコードを書いてみます。

var y = "abc";

console.log(eval("y='d'"));

出力結果は

d

という結果になります。
出力結果を確認する為に、console.logを行っていますが、便宜上書いているだけです。

実行例3

eval()での関数定義を試してみます。

eval("function abc() { return 'z'; }");

console.log(abc());

出力結果は

z

という結果になります。