Unknown Region

プログラムでハマったエラーとその解決方法についての備忘録メモ

【JavaScript】ENUMの仕組みを用意する

JavaScriptでは[enum]という単語は予約語だけれど、一般的な[enum]、つまりは列挙型の仕組みは用意されていない。

ja.wikipedia.org

 

[JavaScript enum]Google検索をかけると、連想配列を使って擬似的に実現する方法が出てくるけれども、個人的には[定義時の見難さ][定義された値を後から書き換えることができてしまう]のが良くないと感じていた。

なので、この機会にその2点をカバーできるように仕組みを整えた。

 

コード: ENUM.js

class ENUM {
  structure = this.define();

  define () {
    return Object;
  }

  apply (values) {
    values == null ? values = {} : values;
    let element = {};
    Object.keys(new this.structure).forEach(key => Object.defineProperty(element, key, {
      value: values[key],
      writable: false
    }));
    return Object.freeze(element);
  }

  values () {
    return Object.keys(this).map(key => this[key]);
  }

  static create (clazz) {
    let instance = new clazz();
    Object.defineProperty(instance, "structure", {
      readable: false,
      writable: false,
      enumerable: false
    });
    return Object.freeze(instance);  
  }
};

コード: COLOR.js

let COLOR = ENUM.create(class extends ENUM {
  RED = this.apply({code: "#FF0000"});
  GREEN = this.apply({code: "#00FF00"});
  BLUE = this.apply({code: "#0000FF"});

  define () {
    return class {
      code;
    };
  }
});

[ENUM]というクラスは共通的に使い、新しく用意するenumの分だけ[COLOR.js]のような内容を用意してあげれば良い。

[define()]では、ENUMの値として使用するメンバーの名称定義してあげる感じになる。

 

COLORへlabelというメンバを増やしたCOLOR2を定義してみる。

コード: COLOR2.js

let COLOR = ENUM.create(class extends ENUM {
  RED = this.apply({code: "#FF0000", label: "red"});
  GREEN = this.apply({code: "#00FF00", label: "green"});
  BLUE = this.apply({code: "#0000FF", label: "blue"});

  define () {
    return class {
      code;
      label;
    };
  }
});

メンバを省略した場合はdefine()の記述自体を省略できるようにした。

以下に使用例を載せる

例: sample.js

// 予めCOLORの定義は完了しているものとする
COLOR.ORANGE = "hoge"
COLOR.RED = null
COLOR.BLUE.code = "#FF0000";
COLOR.GREEN.code = "#FF0000";
COLOR.ORANGE = "hoge"

console.log("COLOR.RED == COLOR.RED: " + (COLOR.RED == COLOR.RED));
console.log("COLOR.RED == COLOR.GREEN: " + (COLOR.RED == COLOR.GREEN));
console.log("COLOR.RED == COLOR.BLUE: " + (COLOR.RED == COLOR.BLUE)); 
console.log("COLOR.RED.code: " + COLOR.RED.code); 
console.log("COLOR.GREEN.code: " + COLOR.GREEN.code); 
console.log("COLOR.BLUE.code: " + COLOR.BLUE.code); 
console.log("COLOR.values(): " + COLOR.values()); 

switch(COLOR.RED) {
  case COLOR.RED: 
    console.log("COLOR.RED IS CHOSEN.");
    break;
  case COLOR.GREEN: 
    console.log("COLOR.GREEN IS CHOSEN.");
    break;
  case COLOR.BLUE: 
    console.log("COLOR.BLUE IS CHOSEN.");
    break;
  default:
    console.log("AN OTHER IS CHOSEN.");    
}

結果: sample.js

COLOR.RED == COLOR.RED: true
COLOR.RED == COLOR.GREEN: false
COLOR.RED == COLOR.BLUE: false
COLOR.RED.code: #FF0000
COLOR.GREEN.code: #00FF00
COLOR.BLUE.code: #0000FF
COLOR.values(): [object Object],[object Object],[object Object]
COLOR.RED IS CHOSEN.

COLORへの要素の追加・変更・削除を許さない仕様なので、COLOR自体へ再代入されない限り思わぬところで値を書き換えられてしまう可能性がなくなる。

 

 

おまけでnode.js用

コード: ENUM.js

export default class {
  structure = this.define();

  define () {
    return Object;
  }

  apply (values) {
    values == null ? values = {} : values;
    let element = {};
    Object.keys(new this.structure).forEach(key => Object.defineProperty(element, key, {
      value: values[key],
      writable: false
    }));
    return Object.freeze(element);
  }

  values () {
    return Object.keys(this);
  }

  static create (clazz) {
    let instance = new clazz();
    Object.defineProperty(instance, "structure", {
      readable: false,
      writable: false,
      enumerable: false
    });
    return Object.freeze(instance);  
  }
};

コード: COLOR.js

import ENUM from './ENUM.js'

export default ENUM.create(class extends ENUM {
  RED = this.apply({code: "#FF0000"});
  GREEN = this.apply({code: "#00FF00"});
  BLUE = this.apply({code: "#0000FF"});

  define () {
    return class {
      code;
    };
  }
});

元々こっちで作っていたのに、ブラウザで検証するために上記のコードへ書き換えていたというオチ。

 

【Perl】便利なハッシュスライスを使いこなそう

ハッシュスライスを使うと、ハッシュから複数の値を一気に取得したり、一気に代入したりすることができて便利。

取得の場合の例:

例: demo1.pl

#!/bin/bash

my %data = ('hoge' => 'fuga', 'foo' => 'bar', 'piyo' => 'piyopiyo');
my @values = @data{'hoge', 'foo', 'piyo'};

# 確認用
foreach my $value (@values) {
  print($value."\n");
}

出力: demo1.pl

fuga
bar
piyopiyo

このプログラム[demo1.pl]では、%dataのキーが[hoge, foo, piyo]に対応する要素の値をそれぞれ順番に取り出して@valuesへ代入している

@data{}の部分は以下のように、直接指定ではなくて配列にキーの一覧を用意しておいて利用することも可能。

例: demo2.pl

#!/bin/bash

my %data = ('hoge' => 'fuga', 'foo' => 'bar', 'piyo' => 'piyopiyo');
my @keys = ('hoge', 'foo', 'piyo');
my @values = @data{@keys};

# 確認用
foreach my $value (@values) {
  print($value."\n");
}

出力: demo2.pl

fuga
bar
piyopiyo

 

代入の場合の例:

例: demo3.pl

#!/bin/bash

my @keys = ('hoge', 'foo', 'piyo');
my @values = ('fuga', 'bar', 'piyopiyo');
my %data = ();
@data{@keys} = @values;

# 確認用
foreach my $key (keys(%data)) {
  print($key.' = '.$data{$key}."\n");
}

出力: demo3.pl

foo = bar
piyo = piyopiyo
hoge = fuga

@data{}の部分は取得の場合の例と同様に、以下のように直接指定ではなくて配列にキーの一覧を用意しておいて利用することも可能。

例: demo4.pl

#!/bin/bash

my %data = ('hoge' => 'fuga', 'foo' => 'bar', 'piyo' => 'piyopiyo');
my @keys = ('hoge', 'foo', 'piyo');
my @values = @data{@keys};

# 確認用
foreach my $value (@values) {
  print($value."\n");
}

出力: demo4.pl

foo = bar
piyo = piyopiyo
hoge = fuga

 

連絡先: plugout777★yahoo.co.jp (クローラー対策のため★を@に変更してください)