ただただ `import ’hoge’;` とか `require('hoge')`とかした場合について

ただただ import ’hoge’; とか require('hoge')とかした場合について確認した

会社で闇のコードを弄っているときにrequire('hoge')みたいなのが無限に出てきた。
こいつってどんな形でimportされるんだ?ときになったので試してみた。
結論から言うと、クロージャの中にいて中のファイルたちはどこからも参照されない。 windowになんかぶら下げるとかする場合は意味があるけど、それ以外はまるで無視される。

経典MDNでは?

MDN曰く

付随効果のためだけにモジュールをインポートする

付随効果だけのためにモジュール全体をインポートしたときは、何もインポートされません。 モジュールのグローバルコードが実行されるだけで、実際の値はインポートされないのです。

引用: 付随効果のためだけにモジュールをインポートする

まぁ、試すか、と言うわけで試した。

コード

■ test.js

const TEST = 'test';

■ index.js

require('./test.js')
const peace = 'peace'

/***/ "./src/index.js":
/*!**********************!*\
  !*** ./src/index.js ***!
  \**********************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

__webpack_require__(/*! ./test.js */ "./src/test.js");

const peace = 'peace';

/***/ }),

/***/ "./src/test.js":
/*!*********************!*\
  !*** ./src/test.js ***!
  \*********************/
/*! no static exports found */
/***/ (function(module, exports) {

const TEST = 'test';

/***/ })

TESTを参照することはできなさそう🤔

exportを追加

■ test.js

const TEST = 'test';
export const Dog = 'DOG' // 追加

■ index.js(一緒)

require('./test.js')
const peace = 'peace'

/***/ "./src/index.js":
/*!**********************!*\
  !*** ./src/index.js ***!
  \**********************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

__webpack_require__(/*! ./test.js */ "./src/test.js");

const peace = 'peace';

/***/ }),

/***/ "./src/test.js":
/*!*********************!*\
  !*** ./src/test.js ***!
  \*********************/
/*! exports provided: Dog */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Dog", function() { return Dog; });
const TEST = 'test';
const Dog = 'DOG';

/***/ })

exportされてるものに関しては__webpack_require__でなんかされそうな雰囲気があるので試した。

■ test.js

export const TEST = 'test';

■ index.js(一緒)

require('./test.js');
console.log(TEST); // Uncaught ReferenceError: TEST is not defined

というわけで、MDNとおりでした。

以上です。

CSSのサイズ指定時の単位について、というか%について詳しく述べる

CSSのサイズ指定時の単位について、というか%について詳しく述べる

モチベーション

今、仕事でフロントエンドエンジニアをやっているけど、案外CSSが苦手な人が多い。CSSスタイルシート言語なので他のプログラミング言語パラダイムがまるで当てはまらないことが大きな理由の一つなのかなと思う。
特に細かい仕様を頭に入れていないと何やねんみたいな挙動することも多い。
僕はCSSの肝は以下の3点だと考えていて、それさえマスターすればあとはプロパティを死ぬ程覚えるだけでなんとでもなるんでは?と思っている。

  • ボックスモデル
  • レイヤー
  • 単位

というわけでこの内の単位について、忘れないうちに記述しておこうと思う。

単位の種類

単位の種類は他にもあるだろうけど、主に以下の種類がある

  • px
  • em
  • rem
  • vw
  • vh
  • vmin
  • vmax
  • %

それ以外にも様々あるので、上記以外のものも含むざっくりとした説明は以下の記事を見たらわかる。
[CSS]長さの単位

というか、ちゃんと調べたいのであれば仕様書はこれです。
Distance Units: the type

そういうわけで具体的に見ていく

px

言わずもがな。
pxはwebの世界では絶対値としての地位を確立していると思う。絶対値といえばこれ。最も多くのシーンで使われているわかりやすい単位。
そういうわけで特に説明はないです🥰

em

pxは絶対値だったけど、これ以降に出てくるものはすべて相対値になる。
相対値とは、何かの値をもとに決まる値のこと。emの場合はそのコンテキストのフォントサイズで値が決まる。

<div class="target"></div>
.target {
  font-size: 20px
  height: 2em; /* 40px */
}

使い所

コンテキストに完全に依存するので割と使いにくいイメージがあるけど、逆にいえばコンテキストに依存させたいようなときはいいかもしれない。
例えば、ブログなんかの文字は1行あたりざっくり40文字未満が読みやすいらしいので、そういうときは

.entry {
  width: 40em;
}

のようにしておくと、勝手に(font-size * 40)pxを計算してくれる。それ以外にも最大で3行だけ表示したいときの高さなんかも以下のような感じで指定できる。

.block {
  overflow: hidden;
  line-height: 1.6;
  height: calc(3em * 1.6) /* line-heightを掛けてやる */
}
  • box-sizing: border-boxの場合でpaddingを上下にとっている場合はそれも勘案してやる必要がある。

rem

root要素のfont-sizeを基準にした相対値。
root要素ってのはなにかというとhtmlのことです。

html {
  font-size: 62.5%; /* フォントサイズはデフォで16pxなので16 *  0.625 = 10px */
}

body {
  font-size: 1.4rem; /* 14px */
}

こんな感じでメインで使う場合はhtmlにfont-size: 62.5%;として、10px基準で扱い、pxの代わりに扱うことが多い。

pxかremか

戦争がおきそうなテーマでもあるし、僕も一度この件でtwitterで争いがおきたことがあったけど、やっぱ用途としてはpxの代わりという感じ。 ブラウザの機能ではフォントのサイズを変更することができる。これを変更した時にブラウザはhtml要素のfont-sizeを変更するので、remで指定しておくことでその変更を各要素のサイズに反映することが可能になる(そのために上記の指定ではhtmlのfont-sizeは%指定がされている)。
または今後2000pxを大きく超える閲覧環境が出てくるような場合、そのサイズに応じてhtmlのfont-sizeを変更してやれば閲覧環境に合わせたサイズで対応することも可能になる。
ただ、フォントサイズの変更も今どき単純にzoom機能を使うのでは?という気もするので、どこまで考えるかは要件次第って気もするけども。

rem を指定する場合の注意点

上記の通り、remだとサイズが可変することがある。
つまりここはpx、ここはremみたいに混ざってると上記のようなときに可変する場所としない場所が出てわけわからんことになるので、基本的にはpxかremかは統一したほうがいい。(多くの場合emと%はどれとも共存できるとおもう)。
逆にpxだとサイズが可変しないことから、remを使用している場合でも可変してほしくないborder-widthなんかはpxを指定するとかはありだと思う。

vw, vh

viewportのwidth、またはheightをもとにした相対値。
100vw = 画面の横幅という感じ。1vwなら画面の横幅の1%の値。

使いどころ

これはちょいちょい使う。例えばファーストビューにheight: 80vhみたいにしたりとか。
あとはスマホ時にすべてのサイズをvwで指定することによって、デバイスのサイズが変わっても全く同じ見た目にするみたいなこともできる。代理店案件とかだと、デバイスが変わることによって、文字の入り方が変わるの嫌がられるみたいな闇があるらしく、そういう時に使ってたみたいな地獄みたいな話も聴いたことある。(その場合はぶっちゃけviewportを固定値にしてやれば済む話だけど)

body {
  font-size: 3.73333333vw /* 14 / 375 */
}

iframe内のvw, vhの値

iframe内の要素にvw, vhがあたっている場合は、iframeのサイズが基準になる。
そりゃそうかという感じだけど、stack overflowにそういう質問が上がっていた。

CSS vh units inside an iframe

vhの問題点

vhは便利だけど、スマホのブラウザだとアドレスバーの表示非表示によって若干意図しない挙動になる場合がある。
The trick to viewport units on mobile
そういう場合はおとなしくJavaScriptに頼るのが話が早そう。

vmin, vmax

viewportの短い方、長い方の値を基準にした値ということらしい。
全然使ったことない。

%

%は非常にややこしい。というかこの記事は基本的に%を説明したくて書いているので、ようやく本番がきたなと言う気持ち。 それではやっていくぞ💪

そもそも%ってなんやねん

今までのものは明確な基準値のある相対値だった。それはたとえば、font-sizeだったりview-portだったり、ある値をもとに数値が決定されていたわけだけど、この%というものに関しては付与するプロパティや状態によって基準値が変わる。
整理した感じ4種類あるので順にみていく。

1. コンテキストの相対値としての%

font-sizeのパターン。当たるはずの値を基準に割合を決定する。

body {
  font-size: 20px;
}

h1 {
  font-size: 200%; /* 40px */
}

逆にfont-size以外思いつかん。

2. 親の表示領域の相対値パターン

  • width
  • height
    • margin
    • padding

width、heightに関してはそうかなという感じがすると思う。親の表示領域の中での割合が値になる。
ただ、marginとpaddingに関しては親の表示領域の中でもwidthのサイズを基準とした値になる。

.parent {
  width: 600px;
}

.child {
  margin-top: 100%; /* 600px */
}

この特性をうまく使うと画像の縦横比を固定することができる。

.fixRatio {
  display: block;
  width: 100%;
}

.fixRatio::before {
  content: '';
  display: block;
  padding-top: 75%; /* 横幅に対して75%の高さ */
}

どっちかにbackground-imageなんかを指定したり、.fixRatioposition: relativeして中でimg要素をposition: absoluteしたりして使う。
結構よく使うイディオム。

親レイヤーを基準にするパターン

position: absoluteのときの%のパターン。
このときは祖先で1番近縁のposition: relativeを持つ要素のボックスを基準に相対値が決まる。 (position: fixedのときはhtml?なのかな?)

  • top, left, right, bottom
  • width
  • height

自分のサイズに依存するパターン

transfromプロパティのtranslateがこれ。
自分のサイズに依存する。

.block {
  width: 600px;
  height: 200px;
  transform: translate(50%, 50%); /* x方向に300px, y方向に100px移動する */
}

この特徴を活かして、中央表示なんかによく使われる。
全然どうでもいいことだけど、例えば以下のようにしてblock要素を左右中央表示することも出来る。

.block {
  margin-left: 50%;
  transform: translate(50%, 50%);
}

まぁ、margin: autoでいいんだけど。

%が使えないプロパティ

以下のやつは使うことができない。

  • border-width
  • box-shadowのカラー以外の値
  • opacity

多分他にもありそう。

そういうわけで

単位と仲良くなりましたか?
これでCSSと戦っていきまっしょう💪

今更だけどまぁまぁ便利なのでgulp4を使う

今更だけどまぁまぁ便利なのでgulp4を使う

はい。
今更gulpって、、、って感じもあるし、webpackだのparcelだの、いやいや、そもそも最近はcliが充実してるので、設定ファイル自体書かないんだよってことがあるのは知ってるけど、gulp4結構便利だったので書いておく。

ちなみに今普通にgulp落としてきたら4以降が落ちてくるけど、3.9.1との明確な差別化のためにこの記事ではgulp4と呼びます。

モチベーション

gulpが便利なときがある

業務でプラグインみたいなやつ書いてて、webpackだけだと結構だるかった。
要件的には以下。

  • htmlとかcssとか扱いたいファイルが複数ある
  • ただコピーしたいのがちょいちょいある
  • 上書きしたいファイルが有る
  • develop用に生成されたファイルをちょくちょく確認したい

特に【上書きしたいファイルが有る】はwebpackだと面倒そうな気配が結構あったので、それが決め手だった。
個人的には未だにウェブサイト作るなら、正直gulpは必須だと思う。
npm scriptsで頑張ってもいいけど、gulpの手軽さには代え難いし、特にウェブサイトの制作だと最終的にWordPressのテーマにしちゃうことも多いと思うし、そういう場合だとNuxtとかは向かなそうな印象ある。

◾️ gulp@3.9.1に引きずられた記事が多い

gulpは@3.9.1の時代が長かったので、巷にはその時代の書き方は死ぬ程転がってる。
もちろんgulp4の書き方も山のように転がってるけど、案外3.9.1を引きずった書き方ばっかだったので、そうじゃない書き方の紹介があってもいいだろうと思った。
個人的には4系の書き方のほうが断然好き。gulp書いてる感でなくjs書いてるなーって感じがするから。

gulpfile.js

公式ドキュメント

まぁ、公式を読めって話だけど、往々にして人間は公式でなく日本語で書かれた記事を先にあたるので、こっちでも書いていく。
大雑把に何が違うかというと、大きいところではseriesparallelが入った。
今まで直列処理するのにrun-sequenceが必要だったけど、seriesが代替できるようになった。 並列処理の場合はその名の通りparallelを使う。 あとはmodule.exportsにタスクをぶら下げる事になったところも大きな変更点だと思う。

今までgulp.task()で文字列と処理を渡してたけど、その書き方は非推奨になった。今でもそのAPIは使用可能なこともあって、この書き方を紹介した記事が多い。ここでは紹介しないですが。

そういうわけで以下、具体的な書き方。

■ 基本形

const { src, dest } = requore('gulp');

const default = () => src(`path/to/src/files`).pipe(dest(`path/to/dest`));

module.exports = { default };

ばりシンプル🥰

ちなみにdefaultで外出ししたやつが gulp 実行時に呼ばれる。
以下のようにやるとgulp hogeで呼べるようになる。

const hoge = () => src(...).pipe(dest(...));

module.exports = { hoge };

各タスクの基本的な流れは3.9.1時代と変わらない。srcでファイルを指定してやって、pipeで様々な処理を行って最終的にdestの中で吐き出し先を指定してやるという感じ。
srcに複数渡したいときは今まで通り配列で渡せばオッケー👌globで渡せます。 3.9.1時代もそうだったけど、srcからの処理をきちんとreturnしてやる必要がある。

例)sassの場合

const { src, dest } = requore('gulp');
const sass = require('gulp-sass');
const sassGlob = require('gulp-sass-glob');
const sourcemaps = require('gulp-sourcemaps');
const please = require('gulp-pleeease');

// 僕は基本めんどいのでpleeeaseでsassの処理やってる
const styles = () =>
  src(`${DIR.SRC_ASSETS}sass/**/*.{sass,scss}`)
    .pipe(sourcemaps.init())
    .pipe(plumber())
    .pipe(sassGlob())
    .pipe(
      sass({
        outputStyle: ':expanded'
      }).on('error', sass.logError)
    )
    .pipe(
      please({
        sass: false,
        minifier: false,
        rem: false,
        pseudoElements: false,
        mqpacker: true
      })
    )
    .pipe(sourcemaps.write('./'))
    .pipe(dest(`${DIR.DEST_ASSETS}css`));

例にするには長々した記述のタスクだった。

parallelseries

並列処理と直列処理。
上記の感じで設定したタスクを渡すだけなのでスーパー簡単。

const { src, dest, series, parallel } = require('gulp');
const del = require('del');

// ejsなどの処理を書いておく

// parallelに書いたやつは並列で走る
const devTask = parallel(ejs, styles, scripts, imageMin);

const clean = dir =>  del([dir]);

// seriesで書いたやつは直列で走るので、これだと、clean.bind(null, DIR.DEST) => devTaskの順で走る。
const build = series(clean.bind(null, DIR.DEST), devTask);

watch

watchだけ結構癖があるというか、watchの場合は何も返さない。
ただ発火させるだけでいい。

watchもおんなじ感じで行ける。

const watchEjs = () => watch(`${DIR.SRC}**/*.ejs`, series(ejs, reload));
const watchSass = () =>
  watch(`${DIR.SRC_ASSETS}sass/**/*.{sass,scss}`, series(styles, reload));
const watchJs = () =>
  watch(`${DIR.SRC_ASSETS}js/**/*.js`, series(scripts, reload));

const watches = parallel(watchEjs, watchSass, watchJs);

const dev = series(build, devServer, watches);

module.exports = {
  default: dev
}

■ browserSync

こいつは最近公式に乗った気がするけど、gulp4で使う場合は引数でdoneを受け取って、処理後にそれを発火させる必要がある。

公式

const browserSync = require('browser-sync');
const devServer = done => {
  browserSync.init({
    server: {
      baseDir: DIR.DEST
    },
    ghostMode: {
      clicks: true,
      forms: true,
      scroll: false
    }
  });
  done();
};

const reload = done => {
  browserSync.reload();
  done();
};

これでwatchなんかの文脈で使ってもうまいことreloadしてくれる。

■ その他

gulp-ejs

こいつはgulp4から自分で拡張子の名前を変えることができなくなってやがる。
ので、gulp-renameを入れて別途拡張子の変更をしてやる必要がある。

www.npmjs.com

const { src, dest } = require('gulp');
const plumber = require('gulp-plumber');
const gulpEjs = require('gulp-ejs');
const gulpRename = require('gulp-rename');

const ejs = () =>
  src([`${DIR.SRC}**/*.ejs`, `!${DIR.SRC}_inc/**/*.ejs`])
    .pipe(plumber())
    .pipe(gulpEjs({ INC: Path.resolve(__dirname, `${DIR.SRC}_inc`) + '/' }))
    .pipe(gulpRename({ extname: '.html' }))
    .pipe(dest(DIR.DEST));

そんなとこですかね。

だいたいそんな感じでいけます。
関数ベースで組み立てられるので僕としては書いてて割と楽しい。
あと、結構スッキリ書けるようになったと思う。

今回の記述とってきたレポジトリはぼくのgithubに上がってるのでわかんないところあれば、参考にどうぞ

github.com

JavaScriptで素数を求めるなどやった

以前、と言っても相当前のことだけれど、会社をやっている友達と飲んでいて、そこの強いエンジニアの人も来ていた。その人はプログラミングを教えるということも行なっており、生徒に出した問題についての話になった。
それが、ある数までの素数を求める、というようなものだった。
調べることは許可されており、確か100までの全ての素数を吐き出すようなプログラムを書け、というような話だったと思う。
僕は素数ってどうやって求めるんやろ、と思いながらも相槌を打っていた。
簡単そうでもあるけど、難しそうでもある。

それからしばらく全く忘却していたが、昨日、全く退屈で終わらないような作業をしている時に、ふとその事を思い出してしまった。

全く脳の使わない仕事をしばらくしている反動か知らないけれど、どうにもやりたくなってしまったのでやってみた。

素数

素数とは、その数と1以外では割り切ることのできない数のことで、それは学校で習った気がする。というか、こいつ公式ないのか?という気持ちになって調べてみたらなかった。

というわけで力技で考えるのならば、与えられた数までの全ての数をその数までの全ての数字で割ってみて、1つも割り切れなければ素数だという事を繰り返せば求めることができそうだ。

その場合だけど、5までの素数を求めるとして

5 / 4, 5 / 3, 5 / 2, 4 / 3, 4 / 2, 3 / 2

という形になる。
まぁ、5位なら求められそうなもんだけど、10000とかだと計算量が増えて、たちまちブラウザがフリーズしそうな気持ちがしてくる。

そういうわけでこんな非効率なことはやっとれんな、と思ったところで、良さそうなものを発見した。

エラトステネスの篩(ふるい)

これが何かと言うと、Wikipedia先生に聞いてみるとなんとなくわかる。

https://ja.m.wikipedia.org/wiki/%E3%82%A8%E3%83%A9%E3%83%88%E3%82%B9%E3%83%86%E3%83%8D%E3%82%B9%E3%81%AE%E7%AF%A9

わかるとか言ったけど、僕はすぐには分からなかった。なんとなく読んで、へーっとなって、寝て起きるとようやく理解できてきたというのが本当のところだった。

これはつまり、以下の手順で求めることができそうなことがわかった。

  1. ある数(max)の平方根を求める(maxDevide)
  2. maxDevideまでの素数を全て求める(primesForDevide)
  3. maxDevideより大きい、maxまでの全ての整数をprimesForDevideで割り、1度も割り切れなかったものと、primesForDevideを合成する

そういうわけでやってみた。

実装💪

const getPrimes = max => {
  if (max < 2) {
    return [];
  }
  const getMaxDevide = n => Math.floor(Math.sqrt(n));
  const maxDevide = getMaxDevide(max);
  const getPrimesByMaxDevide = (num, primesArray = []) => {
    if (num <= 2) {
      return [2, ...primesArray];
    }

    const isPrime = ![...Array(getMaxDevide(num) + 1).keys()]
      .filter(n => n > 1)
      .some(n => num % n === 0);

    return getPrimesByMaxDevide(
      num - 1,
      isPrime ? [num, ...primesArray] : primesArray
    );
  };

  const devidePrimes = getPrimesByMaxDevide(maxDevide);

  return [
    ...devidePrimes,
    ...[...Array(max + 1).keys()].filter(
      n => n > maxDevide && !devidePrimes.some(d => n % d === 0)
    )
  ];
};

こんな感じでうまいこといけてるみたい。 1,000,000くらいの数与えてもいけるみたいなので、パフォーマンス的にも問題なさそう。

だけどダラッとかかれているので読みにくすぎるのでリファクタする。

const getMaxDevide = n => Math.floor(Math.sqrt(n));

const isPrime = num =>
  ![...Array(getMaxDevide(num) + 1).keys()]
    .filter(n => n > 1)
    .some(n => num % n === 0);

const getPrimesByCheckingAllNumbers = (num, primesArray = []) =>
  num <= 2
    ? [2, ...primesArray]
    : getPrimesByCheckingAllNumbers(
        num - 1,
        isPrime(num) ? [num, ...primesArray] : primesArray
      );

const getPrimes = max => {
  if (max < 2) {
    return [];
  }
  const maxDevide = getMaxDevide(max);
  const devidePrimes = getPrimesByCheckingAllNumbers(maxDevide);

  return [
    ...devidePrimes,
    ...[...Array(max + 1).keys()].filter(
      n => n > maxDevide && !devidePrimes.some(d => n % d === 0)
    )
  ];
};

マシになりましたか?

所感

なんというか、素数を調べるところからやっても2時間くらいかかりそう。
コード書くだけでも割とかかった。
これが入社試験とかで、素数を調べるところからだったら死んでたな。

direnvでプロジェクトごとのnodeのバージョンを切り替える

今更ですが、会社でまとめたのでこっちにも貼っときます。

プロジェクトごとにnodeのバージョンが違って、そのたびに思い出しては切り替えることがあります😇 こっちではv8なのにこっちではv10、、、 そもそも覚えてられないし、切り替えるのが面倒、、、、🤯

そういうわけでdirenvを使いましょう。

direnv

これです。 https://github.com/direnv/direnv

こいつを入れて各プロジェクトに.envrcをおくと、そのプロジェクトに移動したタイミングで、.envrcの中身が実行される、みたいなことになります。

■ install

$ brew install direnv

それからシェルにパスを通します。 公式に書いてますが、

~/.bashrc

eval "$(direnv hook bash)"

~/.zshrc

eval "$(direnv hook zsh)"

.config/fish/config.fish

eval (direnv hook fish)

あるいは

direnv hook fish | source

後は、direnv edit コマンドがかけるように以下も追記します。

export EDITOR=vim

後は $ source 設定したファイル で再読込して$ direnv --version が通ればバッチリです。

.envrcを作成

作りたいディレクトリに移動して、$ direnv edit ..envrcの作成が始まります。 別に.envrcを普通においてもいいです。

そのプロジェクトに移動すると、.envrcの中身が走るわけですが、

direnv: error .envrc is blocked. Run `direnv allow` to approve its content.

とか言われることがあります。その場合は書かれてますが、

$ direnv allow

でOKです。

nodeのバージョン切り替え

それぞれのバージョン管理ツールによりますが、以下のような感じで.envrcを書くと動くはず。

■ nodebrew

nodebrew use 使いたいバージョン

■ nvm

nvm use 使いたいバージョン # これだとだめ。nvm command not found的なこと言われる

あるいは.nvmrcを置いてやることもできます。

上の方法だとだめなので、.nvmrcを作ってやりましょう。

.nvmrc

10.16.0

.envrc

nvmrc=~/.nvm/nvm.sh
source $nvmrc
nvm use

nvmrc=のところはnvmの場所です。

【やっとくと良いぞ】.gitignore_globalに設定

他の人がnodeのパッケージ管理に何使ってるかわからんので、こういうファイルはgitに含めたくないものですが、かといって毎回書くと忘れちゃう。 なので、.gitignore_globalを用意して、そこに記述しておきましょう。

$ touch ~/.gitignore_global

.gitignore_global

.DS_Store
.nvmrc
.envrc
$ git config --global core.excludesfile ~/.gitignore_global

あるいは ~/.gitconfig

[core]
    excludesfile = /Users/<username>/.gitignore_global

はい。

参考 - gitignore_globalを作成する on OSX - nvmとdirenvを使ってディレクトリ毎にnodeのバージョンを指定する方法 - fishでdirenvを設定する

EventTarget.addEventListenerでイベントを登録した時、そのイベントの実体はどこに登録されるのか

モチベーション

要素追加時に、その要素にeventを登録したとする。 その後、その要素が削除され、かつその要素がどこからも参照されていない時、登録されたイベントはどうなるのか気になった。
もし、上記の状態でもイベントが削除されないのであれば、removeEventListenerで明示的に削除する必要がでてくる(ただ、残っていたからといってどの程度影響があるのかという話もあるが未調査)。

そもそもこいつはどこにイベントを登録するのだろう。
そういう訳で仕様書を当たることにした。

仕様書ではEventTargetのEvent Listener List に登録される事になっている。

MDNを見ると、addEventListener の項目は EventTarget 項目内にある。
https://developer.mozilla.org/ja/docs/Web/API/EventTarget/addEventListener
つまり、addEventListenerEventTargetインスタンスのメソッドで、こいつを調べようと思ったら、EventTarget について調べたら良さそう。
ちなみにEventTarget オブジェクトはwindowから生えている。

念の為。

document instanceof EventTarget // true
document.createElement('div') instanceof EventTarget // true

へぇ、そうなんだ🤔という気持ちになった。

以下はwhatwgのEventTargetの仕様書。
原文
日本語

この中にこのような記述がある。

Each EventTarget object has an associated event listener list (a list of zero or more event listeners). It is initially the empty list.

日本語だとこう

各 EventTarget object には、 イベントリスナリスト が結び付けられる — それは、 0 個以上のイベントリスナからなるリストであり,初期時には空とする。

更にFor web developers (non-normative)(このブロックは Web 開発者向けであり、規範的ではない。)という緑色の項目内、 target . addEventListener(type, callback [, options])の欄に以下の記述もある

Appends an event listener for events whose type attribute value is type. The callback argument sets the callback that will be invoked when the event is dispatched.

target のイベントリスナリストに[ type 属性値が type であるイベント用のイベントリスナ ]を付加する。 callback 引数が,イベントが配送されたときに呼び出される callback として設定される。

ということは、EventTargetaddEventListenerで登録されるEvent Listener Listを保持していると言えそうなので、EventTargetが削除されれば、自ずとEvent Listener Listも削除されるのでは?ということがわかる。

ちなみに、Event Listener Listを観測するためのメソッドはEventTargetインスタンスに生えていないため、Event Listener Listを実際に観測することは現状できない様子。
(それを観測するためにどうこうするみたいな記事は出てくるが、実体を確認することは今の所できない様子。)

以上

よろしく💪

祖父との思い出2

「おじいちゃあん、おじいちゃあん、行くよう、早く行くよう、って言って、おじいちゃん、妹にミルク飲ませてるのに、バスのガラガラ引っ張るおもちゃもって、行くよ、行くよって何度もいってさ、その話をおじいさんから何辺も何辺も聞かされたいや。

それで遠ーくまで散歩していってさ、そうしたら、途中でお前が眠たくなって、それで、妹おんぶして、お前のことをおじいさん抱えて、バスのおもちゃ引っ張って帰ってきたんだれ。 ばぁか疲れたいやって、おじいさん言ってさ。」


2019/03/24

到着すると地元はよく晴れていた。
母親が喪主なため、せわしなく連絡をとったりしていた。余裕がなさそうだ。
僕は車に乗り込むと、とりあえず祖父の家に向かうことになった。妹と3年ぶりにあった。
向かう道中で、母は車を運転しながら、決めることが多く、葬儀会社と何度も何度も打ち合わせしなければ行けない状況に苛立っているうようだった。

祖父の家では、布団で祖父が寝かされていた。息を引き取ってから3日目なので、喉元が緑色に変色し、耳が暗い紫色に変わっていた。首から下は、布団がかけられていて分からなかった。

触ると冷たい。ドライアイスのせいだ。
じいちゃん、帰ってきたよ。

線香を折らずに火をつけ、立てる。水を替えてやる。水を替えるのが供養になるそうだ。

祖母は相変わらずマイペースだ。
今の葬儀は割合手が込んだものになっていて、遺影以外にも写真をいくつも集めたコラージュみたいなものも作るらしい。そのために引き出した昔の写真を見ながら、自分を見つけては可愛い可愛いと何度もいっていた。 こんだけ可愛かったんだから、そら言い寄られるわけだ、と言っていた。

**

母の家系は、男の子供に恵まれなかった。
僕の母が長女、そして近いところに嫁に行った叔母(次女)がいる。
僕の家も叔母の家も祖父母の家からはそう遠くはないし、行き来がずっとあるが、叔母の方が訪問頻度も高く、その分関係性も強かったんだろうと思う。

僕は初孫で長男だったこともありすごくかわいがってもらったしその自覚もあるが、逆に叔母の子達は一番下の子で18でまだ地元におり、孫を通した交流も多かったことも、交流頻度の多寡に影響していると思う。

そうはいっても長男がいないため、とりあえず長女である母が喪主ということにしたそうだ。祖母はとにかくそういった面倒事を任せられる状態ではない。

**

今日は僕と父、妹は家に帰って、母親は祖母と祖父と泊まることにするそうだ。宗教的な理由からか、線香を絶やしてはいけないらしく、火事になる危険性もあるので祖母一人には任せることができない。それに死体と夜を二人で過ごすのは、幾ら夫婦だったとはいえ可哀想だ。(遺体の顔に白い布がかけられていることも多いが、祖母はその状態が怖いらしく、常にとっていた。) 明日は昼に納棺、夜に通夜、そのまま祖母と僕の家族が斎場に祖父と泊まる。叔母たちは斎場と家が近いため家に帰り、葬儀前にまた来る形になった。

大まかな予定を確認したあと、父方の叔父(父の兄)が妹に結婚祝いを渡したいことと、僕が妹に髪の毛を切ってほしいと依頼したことで、先に一旦家に帰ることにした。母が父に、僕の髪の毛を切り終わってから叔父に連絡して来てもらえ、コーヒーをだして、茶菓子が今家にないから、このお菓子を持っていけと、お菓子をもたせてくれた。

家について散髪が始まるやいなや、父は叔父に連絡し、髪の毛を切ってる途中に何故か叔父が来た。コーヒーは出すのに茶菓子は出さない。しかも何故か寒いし、叔父の対応を僕と妹に任せ、自分は少し離れた席で相撲を見ていた。それでも談笑して和やかな雰囲気だったが、終わったあと確認すると、車の中にお菓子は置きっぱなしだった。父はこういう人間なんだ。僕はまた祖父の家に向かう途中の車の中で、父を叱った。

祖父の家に叔母家族が来たので、久しぶりに皆でご飯を食べにいった。回転寿司。
僕は叔母の隣りに座った。叔母は普通に振る舞っているようだったが、かなり憔悴しているようだった。


2019/03/25

今日は納棺と通夜。
納棺は15時からなので、それに間に合うように祖父の家に行けば良かった。

昼頃、一旦母を家に戻すため、妹が迎えにいった。祖父の家の風呂が機能していないため、家で風呂に入りたいそうだ。
帰ってきた母は、祖父の家では歯も磨けなかった、 誰も歯がないから歯磨き粉がないんだと言った。なるほど、盲点だったなと思った。

支度をしていると刻一刻と納棺の時間が近づいてくる。それにもかかわらず、父はラーメンを食いに行きたいだの、出前を頼もうなど食べる話しかしない。僕は今日の晩、斎場に泊まって翌日の式に出席した後直接大阪に帰るので、忘れ物の無い様、荷物をまとめた。
お昼ご飯は結局スーパーで弁当を買った。

祖父の家に向かう道中、母はいろいろなことを語った。
今回、いろいろなことを決めなければならないが、祖母が決めることができないので、自分が決めなければならないこと。連絡すべき人たちの連絡先などはすべて、祖父が生前残してくれたノートに記載されていたこと。そこには僕の電話番号や、息子が生まれたこと、親戚関係の生死なども記載されていたこと。浅丘雪路、死亡なども書かれていたこと。入院中に何かあった時のために、姉妹にはお金の場所等も事前に教えておいたこと。そういうことが、今回すごく助かったと言っていた。また、家系の本家、分家等のしきたりが分からず、マナーを犯したために少々ややこしくなっていて、ストレスになっていることも語った。

話を聞いていると、本家問題以外にも、お坊さんに対する扱いも特別なものだった。僕はなんとなく、そういったしきたりがひどく疑問だった。
僕は祖父を送りたいがために来ているのであって、本家との顔つなぎに来ているわけでもなければ、入信しに来てるわけでもない。母や叔母も同じはずだ。お坊さんは宗教上の行為を持って祖父を弔ってくれる、いわば協力者の立ち位置であって、そこに気を使いすぎて祖父を送ることに集中できないような構造では、改められてもいいのかもしれないと思った。

早めについたので、祖父の顔を何度も眺めて、触る。右の頬には若干赤い筋がはいってきている。何人か祖父に会いに来た。叔母たちもきた。そしてお坊さんと棺がやってきた。
遺影は淡い緑色の額に入れられている。棺もそれに合わせた色、運び込んで祖父の隣に置く。

旅支度。
布団を剥ぐと、黄色くてむくんだ手や足がみえる。
手が大きい。こんなに手が大きかったんだなーと思った。
アルコールで体の出ている部分を拭いてやる。僕は顔を拭いた。祖母も反対側から顔を拭いた。

おじいさん、旅立つときが来ましたて。しょうがねえんだ。

僕は次に手を念入りに拭いてやった。黄色くて大きい手が、堪らなく愛しかった。
祖母は祖父の手を取り、「冷てえねえ、冷てえて。22日の日に、おじいさんの手を握ってたんだよ。そんときはさ、あんなあったけかったのに、冷てえねえ。ずっと触っててもあったかくならねえね」といった。

旅支度は、足袋を履かせ、すね当て、手の甲あてをつけて、最後に頭巾をつけて、六文銭をもたせてやる。
足や手はすごく冷たくて重たかった。

腹水が溜まっているので、頭の方を下げるとそれがクチから出る可能性があったため、慎重に、棺の中に収めた。
収めたあと、葬儀会社の人が綿で袴を着せてくれた。下から見ると立っているように見えた。
あまり立派だったからか、父が写真を撮っていいか聞いた。僕はその時の父の態度が不真面目に感じて、苛々しながら父を諌めた。葬儀会社の人は、最近はそういう方も増えていますと言ったが、祖父は写真がすきでなかったから、と、その話は流れた。 それから顔にファンデーションを施して、口に綿をつめ、少し紅を塗った。妹も化粧を施してやっていた。本当に生きているみたいで、寝てるだけなんじゃないかと何度も思って、何回も何回も冷たい顔を触った。

入院中、枕元に置いていたという妹が買ってきた健康長寿のお守りも持たせてやった。50円玉など、小銭も集めて持たせてやった。集めた小銭を祖母が、じいさん、お金持ちになりましたね、といって袴の襟のやたら奥に突っ込んだ。

大好きだった酒と、枕と、衣類なんかの遺品も葬儀会社の人に渡した。
そして棺の蓋を締めた。
その時、それがなぜだかすごく悲しかった。

重たい棺を霊柩車に乗せた。
それが出発するのをみながら、もう肉体はここに帰ってこないんだと思った。

僕たちは着替えながら通夜の迎えのマイクロバスを待った。着替え終わったくらいで、母は通夜の終わりの挨拶をするので、そのための原稿を練習した。
父も妹も泣いた。母も泣いた。本番に読めるのだろうかと不安になるほどに。

祖母の準備は致命的に遅い。それは周りを常に苛立たせるほどに。
通夜の支度をして迎えが来たが、祖母はストッキングを履くのに時間がかかっている。うちの親父の気が揉めている。だけどいいじゃないか。ばあちゃんのための葬式でもあるんだから。

僕は叔母の息子とともに車で斎場に向かった。久しぶりの従兄弟。
叔母の子供は三人いる。長女、長男、次男だ。長女が一番年が上だ。

斎場につくと、祖父のスナップ写真や、先程渡した遺品が展示されていた。スナップ写真はぼくが写っているものがやたら多かった。嬉しくて、切なくなった。
会場に入ると、すごく立派な飾りが用意されていて、祖父が寝ていた。顔をずっと見ていたい。
徐々に人が集まって、スナップ写真を見ながら談笑をしたり、控え室でコーヒーを飲んだりしている。僕はそういった人たちに挨拶したり、変にトイレに立ったりしていた。そうして、その間に何度も祖父を覗きに行った。
祖父のそばに、僕以外にもうひとりいて、慈しむように祖父を見ていた。あとから聞くと妹だそうだ。祖父をひどく慕っていたらしい。

親戚たちへの挨拶や、談笑をしているとあっという間に時間が過ぎた。お坊さんがはいってきて母たちは挨拶に向かった。もう直ぐお通夜が始まる。
僕は何度めかのトイレに向かってから煙草を吸った。

地域柄、祖父は法華宗だった。
僕はこのタイプの葬儀関連は初めてだったので、興味深く参加していた。
隣に座る父が、だんだん眠たそうにしてくるのを肘で小突いて起こしながら、お経を聞いていた。
リズミカルな打楽器とお経は、意味はわからなかったがなんとなくぼうっとしてしまった。この時間、僕は祖父について考えていた。いろいろなことを思い出そうとしていた。話の断片や記憶をかき集めて辻褄を合わせるような、物語を作っているようなことを繰り返していた。ふわふわとした浮遊感の中で、満遍なく引き伸ばされた悲しみの上をたゆたっているような、悲しいような、よくわからないような気持ちをずっと感じていた。

焼香をして、南妙法蓮華経と唱えさせられた。35日法要もかねているからかもしれない。焼香は最初喪主である母と叔母、祖母の三人が行った。きちんとできるかな、と思った。その後僕と父、妹、叔母の子。僕は中央の焼香台をつかった。真正面から焼香をしたかった。

読経が終わると、喪主の母が挨拶だ。
変にどきどきする。
その前に突然、プロジェクターが降りてきて、祖父の生前のスライドショーが始まった。結婚式みたいだなと思って笑った。

母が泣いてる姿はほとんど記憶にない。
テレビを見て泣いていたことはあった気がする。あるいは定かではないが、子供の頃、父と喧嘩して泣いていたところを見た記憶が朧気にある。
そんな母は、声をつまらせながら挨拶を読み終えた。
隣で妹は号泣していた。

通夜振る舞いでは、父の兄夫婦と、祖父の兄弟の奥さんしかいないテーブルに座っていろんなことを話した。
奥さんはその兄弟は昨年の10月に亡くなったんだと言った。10月22日。祖父は3月22日、偶然ってあるもんですねと話していると、父の兄が、うちの方のおじいちゃんがなくなったのも2月22日だったといった。
不思議だなと思った。

参列者が全部帰ったあと、葬儀場の宿泊部屋に僕の家族と祖母、叔母家族が集った。
母と叔母は明日の流れを確認している。祖母は疲れたのだろう、すぐに横になって目をつぶった。通夜振る舞いでラーメンを3杯も食べていたので満腹だったのもあったかもしれない。
部屋には祖父も運ばれてきていた。
棺桶の小窓を開けて、祖父の顔をまた触った。相変わらず、生きていて寝てるみたいだ。
叔母の一番下の18歳に、今祖父がバッて起き上がってきたらどうする?と聞いた。
嬉しいと答えた。
俺も。と言った。
昼間母がこの質問を祖母にしたら、祖母は逃げると言ったらしい。

その子にビールを注いでやった。
じいちゃんと一緒にずっと飲みたかったんだといった。僕は飲めたのに飲めなかったんだと白状した。だから今日はたくさん飲もう。
小さいグラスにビールを注いで祖父のもとにおいて乾杯した。

思えばこうして皆揃って集まれるなんて、本当に久しぶりだ。
じいちゃんうれしいやろな。
僕もじいちゃんと久しぶりに一緒に泊まれて嬉しいよ。


2019/03/26

葬儀は9時から。
朝の6時頃から目は覚めていたが、ある程度飲んでいたし、なんとなくゴロゴロしていたくて寝たふりをしていた。一緒に飲んでた従兄弟は良い感じに酔っ払っていたが、二日酔いは大丈夫だろうか。なんかすごく懐かれてしまった。
祖母は午前2時頃に風呂に入ったそうだ。湯壷に入ったと言っていた。湯壷という語彙がなんだかツボに入ってしまって無性におかしかった。

布団を揚げて、朝ごはんにコンビニのおにぎりを食べて、支度をした。
じいちゃん、おはよう。今日でお別れだね。と顔をなでた。
少し時間があったので、近くのコンビニまで歩いていった。このあたりを歩くのは初めてだったので、少し道に迷いそうになった。
コンビニで野菜ジュースを買って、煙草を吸った。雨の予報だったが、気持ちよく綺麗に晴れていた。

戻ると参列者たちが既にちらほら来ていた。老人たちは朝が早い。
僕は再び、祖父を覗きに行って、それから親戚たちに挨拶をした。
今回わかったことだが、妹のコミュニケーション能力は異常だ。職業柄、高齢の方を相手にすることが多いこともあると思うが、ほとんどの人と話をして盛り上がっていた。
昨晩の通夜振る舞いでは僕の隣りにいた祖父の兄弟の奥さんと連絡先の交換さえしていたし、母の悩みの種になっていた祖父側の本家のおばあさんに世辞や冗談をいったりして笑い合っていた。
しかも祖父側、祖母側の家系図まで頭の中で掴みかけてきたらしく、妹を通して誰が誰なのかの説明をうけた。無論、僕はほとんど覚えることができなかったわけだが。

葬儀が近づいてきたので、煙草を吸った。
父の兄と一緒になった。
「じいちゃんはでも良かったと思う、ひ孫も見れたんだし。うちの方は一人もひ孫見ないで死んでしまった」といった。

時間になって葬儀が始まった。
流れは通夜とほとんど一緒だったが、お坊さんの服が少し違ったし、お経中に何かしらで棺を叩いたり、なにかバラバラとした紙がついた棒を煙越しに投げて棺の上に乗せるというパフォーマンスがあったりした。
僕はまた昨日と同様に、父を肘で小突いて起こしつつ、お経をきいたり、遺影を眺めたりした。父の向こう側で祖母もコクリコクリとなっている。湯壷というワードを思い出して、僕は少し、笑ってしまった。
焼香したり手を合わせたり、南妙法蓮華経を唱えたりして、葬儀は終わった。
お経をきいている間、祖父の兄弟関係の方たちはお坊さんと一緒にお経を読んでいた。僕はなんとなく、祖父に向かって一緒に弔ってやれるのは少しうらやましい気持ちになった。

お経が終わり、花を手向ける。
花を手向けながら、また、顔を触る。
もう触れなくなるので、何度も何度も頬を撫でる。
余った花も手向け、遺品もいれる。
顔の近くに酒を供える。
誰かがそれじゃあねといったので、僕は顔を背けて棺から少し離れた。
それじゃあね、と僕も言おうと思ったが、うまく発生できなかった。
だけれど言わなければいけないと思って、また顔を触りながら小さい声で、じゃあね、と言った。

棺の蓋を締めて、出入り口まで運んだ。
出棺の挨拶は叔母がおこなった。
叔母も言葉をつまらせながら挨拶をした。
聞きながら祖父の兄弟が声を揚げて泣き崩れた。
棺は運ばれて、霊柩車の荷台に載せられた。

霊柩車は長いクラクションを三回ならして、火葬場へとむかった。僕たちもバスに乗ってそれを追いかけた。僕はまた、叔父と隣りに座った。なんとなく話したかったので、霊柩車の話をしていた。
ひどく悲しい瞬間と普通の瞬間が短い感覚で交互にやってきて、それについてうまく対処することが難しいなと思った。

火葬場は真新しく、綺麗で広い建物だった。
新しいせいか、あの独特の匂いが全然ない。
どの火葬場でもそうだが、物事が粛々と淡々と行われ、非常に事務的な対応がされる印象があったが、ここはそうではなかったので安心した。

火葬場の奥まで進むと、焼くための装置が蓋を開けて待っていた。
再度お経が読まれ、焼香し、顔を見て、手を合わせた。
じいちゃんがこれからあそこに入るのが凄く怖く感じた。
棺をいよいよ、装置に入れるとき、これから人間の形をした肉体を焼くという行為がありありと感じられて、悲鳴のようなものが漏れたのが聞こえた。
蓋を閉める時、手を振って何人かがバイバイといった。ぼくもそれに習ってばいばいといって、装置の扉は閉められるのを見送った。

あの世とこの世というものを分け隔てるものがあるとすれば、僕はこの、火葬の装置の扉なのではないかと思った。

葬儀場にかえって、お斎の時間。
1時間半ほど皆でご飯を食べて、お骨拾いに行く。
バスから降りて、お斎の場に向かう途中、妹はスナップ写真のコラージュなんかを写真に収めたし、じいちゃんのことも今朝、写真に撮ったと言ったので、写真を送ってもらった。普通にほしいと思った。

お斎は和食のコース料理のような形式だった。席は決まっていて、孫5人は同じテーブルに集められていた。叔母が挨拶をして、お坊さんが献杯の音頭をとった。叔母はもう、泣いていなかった。
お坊さんの献杯に合わせて、孫の僕たちは普通に乾杯をしてグラスを鳴らした。
葬儀場のスタッフが笑ってた。やってしまった、と思ったが、孫は往々にして許されるもんだろうと思って笑った。
これから気をつけます。

18歳の従兄弟は胃の調子が悪そうだった。二日酔いらしい。
若い人間しかいないテーブルには、老人たちのテーブルから無尽蔵にご飯が送られてきて、胃がはちきれそうになった。一番若い人間は胃がだめになっているので、僕と叔母の長女が大活躍していた。なんだか凄く楽しかった。
妹は久しぶりに孫が集まったのだし、と孫と祖母とで集合写真を撮ることを提案した。椅子を並べて真中に祖母を座らせて、それを囲んだ。いい写真が取れた。

あっと言う間に時間は過ぎて、お骨拾いの時間。
希望者だけがいく形だったが、祖父の親戚まわりも、祖母の親戚周りも殆ど来なかった。祖父の兄弟で生前飲み仲間だったおじさんが来た。祖父にそっくりだ。
バスに乗って出発をまった。この日9件も火葬が入っていたので、時間厳守だそうだったが、祖母はトイレに入ってなかなか出てこなくて、皆待たされた。
父はまた苛々している。僕はばあちゃんぽいなと思って可怪しかった。

結局10分近く遅れて出発した。
綺麗に焼き上がっていて、骨の形がしっかり残っていた。ここまで残るのは珍しいそうだ。大腿骨や頭蓋骨も形がありありと分かるほど綺麗に残っていた。
時間がないので橋渡しは最初の一回だけ。僕と、叔母の長男が行った。
それからみんなで骨を集めた。途中から飲み仲間の祖父の兄弟は手で集め始めた。お兄ちゃんの骨だもんなと思った。
すべて骨壷に収めて、それを僕が受け取った。決して落とさないように大事に大事に抱えた。

葬儀場に戻ると、場は解散になった。
参列者を見送って、荷物をまとめた。バスに乗って、祖父の家に帰った。
最後に、お寺にいって、またお経を読んでもらわねばならない。

ただいま。じいちゃん、帰ってきたよ。

祭壇に祖父を置いて、お寺に向かった。
お寺につくと、骨はどうした?ときかれた。
家だとこたえると、必要なんだが、、、と言われた。
取りに帰るのも、ということでそのまま読経が行われた。
読経を聞きながら祖母はたぶん寝ていた。父も眠たそうにしていた。

すべて終わって、祖父の家についたが、葬式の引き出物を渡すところがある、と母と父と妹はまた出ていった。叔母たちも着替えに帰った。僕は荷物をまとめたり、着替えたりしなければならなかったので、祖父の家にいた。祖母と二人になった。
二人きりになった祖母は、じいちゃんにむかって手を合わせた。しばらく手を合わせて何かを話していた。僕はその横でそそくさと着替えを済ませた。
祖母はそれから、何かが食べたいと言い始めた。そばを食べに行こうと言い始めた。冗談じゃない。僕はまだまだ満腹なんだ。祖母は今食べるわけではない、一時間後とかに食べるんだといった。それからそばが良いか、チャーハンがいいか、焼そばがいいか、もしたべるとしたらスープがあるものと無いものどっちがいいか、やっぱり焼そばが良いかもしれないというようなことをしきりに言い始めた。
僕は5時には電車に乗らないといけないから食べられないよ、といったが、聞いてるのか聞いてないのかわからない。
母がもうすぐ帰ってくるはずだから、それから決めたら良いんじゃないかといった。だが、人数が多いから早く予約しないと行けなくなると答えた。火曜日の昼間だから大丈夫、まだ埋まったりはしない。
納得したようだったが、おもむろに立ち上がって、突然受話器を持ち始めた。ちょっと待て、どこに電話するの?ときいたら蕎麦屋だという。
こういう時だけ何故か行動が早い。
なんとか説得して、先に着替えてもらうことにした。

部屋には僕とじいちゃんの二人。
遺影を見ながらたくさん話した。
後悔をいくらしても時間が巻き戻るわけではないし、祖父が今、そこにいるわけでもない。それに、もしかしたら尽くせる限りの最善だったのかもしれない。
それでも、それでも、という気持ちが湧いてきて、同じことを何度も繰り返し頭の中で反芻していた。

母が帰って来て、少し時間があったので近所を散歩した。
久しぶりにあるいてみると、どんどん記憶が戻ってくるのを感じた。
その記憶も全部、ぼくの思いこみかもしれないけれど、僕はここで確かに祖父と遊んだし、可愛がってもらってたんだと思った。
同様に祖母にも、両親にも。
僕が老いて死ぬときには孫にも同じように思ってもらえたら良いなと思った。