JavaScript:列挙型(enum)もどきオブジェクト †
最近、enchant.jsにちょっと興味を持ち、10年振りくらいにJavaScriptに触ってみています。
JavaScriptといえばこのサイトができて間もない頃にダイアログ(alert)を表示してドヤ顔してたことくらいしか覚えがないですが、知らない間に随分と進化したものです。
んで、とりあえず列挙型(enum)が欲しいなーってことで、列挙型もどきオブジェクトを生成する関数を作ってみました。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
| -
!
-
!
-
|
|
|
|
-
|
|
|
|
!
-
|
!
|
-
|
|
|
|
|
|
|
|
|
|
|
!
-
-
|
!
-
|
!
|
|
|
-
-
|
-
|
!
!
|
|
-
-
|
|
|
!
!
|
|
!
|
-
|
|
|
|
!
-
|
|
|
!
|
-
|
|
|
|
!
-
|
|
|
!
!
|
var ruche = { };
(function() {
"use strict";
var slice = Array.prototype.slice;
ruche.Enum = function() {
return ruche.Enum.make.apply(this, arguments);
};
ruche.Enum.make = function(valueMaker) {
if (arguments.length === 0) {
return ruche.Enum.make(function() { return 0; });
}
if (typeof valueMaker !== 'function') {
return ruche.Enum.numeric.apply(this, arguments);
}
var args = slice.call(arguments, 1);
var names = [ ];
if (args.length !== 0) {
if (args[0] instanceof Array) {
names = args[0];
} else {
names = args;
}
}
var values = { };
for (var i = 0, len = names.length; i < len; ++i) {
values[names[i]] = {
value: valueMaker(i, names[i]),
enumerable: true,
writable: false,
};
}
return Object.create(null, values);
};
ruche.Enum.numeric = function() {
var args = slice.call(arguments);
args.unshift(function(i) { return i; });
return ruche.Enum.make.apply(this, args);
};
ruche.Enum.named = function() {
var args = slice.call(arguments);
args.unshift(function(i, name) { return name.toString(); });
return ruche.Enum.make.apply(this, args);
};
})();
|
ちゃんと列挙値プロパティが定義されているか確認してみます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
| -
-
-
|
|
|
-
|
|
|
!
|
!
|
-
|
!
|
|
-
|
!
|
|
-
!
|
|
-
|
|
!
|
|
|
|
!
| window.onload = function() {
var printPropList = function(value) {
console.log(value);
var ul = document.createElement('ul');
for (var v in value) {
var li = document.createElement('li');
li.innerHTML = v + " = " + value[v];
ul.appendChild(li);
}
document.body.appendChild(ul);
};
var Color = ruche.Enum('Red', 'Green', 'Blue');
printPropList(Color);
var Num = ruche.Enum.numeric([ 'One', 'Two', 'Three' ]);
printPropList(Num);
var Score = ruche.Enum.named('Bad', 'Good', 'Best');
printPropList(Score);
var animalValues = [ 'Dog', 'Cat', 'Lion' ];
var Animal = ruche.Enum.make(
function(i, name) { return i + "_" + name; },
animalValues);
printPropList(Animal);
};
|
上記のコードを埋め込んだHTML js_test/enum_test.html を確認してみてください。
それなりに新しいブラウザでないと動きません。
まぁ、言ってしまえば次のように書くのとほとんど同じです。
| var Color = {
Red: 0,
Green: 1,
Blue: 2,
};
var Score = {
Bad: 'Bad',
Good: 'Good',
Best: 'Best',
};
|
ただ、今回の関数で作成した列挙値は書き換え不可の値になるので、誤って列挙値を上書きしてしまうようなことは防げます。
| var Color = ruche.Enum('Red', 'Green', 'Blue');
Animal.Red = 100;
|
この列挙値もどきオブジェクトは例えば次のような感じで使えます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
-
!
-
|
-
|
|
|
!
|
!
-
|
|
|
|
!
| var Animal = ruche.Enum('Dog', 'Cat', 'Lion');
Animal.Dog = 'Tiger';
var printVoice = function(animal) {
var voice = '………';
switch (animal) {
case Animal.Dog: voice = 'わんわん'; break;
case Animal.Cat: voice = 'にゃーん'; break;
case Animal.Lion: voice = 'がおー!'; break;
}
document.body.innerHTML += '<p>「' + voice + '」</p>';
};
window.onload = function() {
printVoice(Animal.Dog);
printVoice(Animal.Cat);
printVoice(2);
printVoice('Tiger');
};
|
上記のコードを埋め込んだHTML js_test/enum_animal.html を確認してみてください。
var ANIMAL_DOG = 0;
みたいな定数もどきを使うよりはコードが見やすくなるのではないでしょうか。