cdnjsjsDeliverunpkgSelf hosted

カメリアの記事

意味があることやないことを綴ります

JavaScriptでイベントが取得できない

イベントが取得できない、発火しない、と困っていました。下のようなコードです。

let element = null
new Promise(resolve => {
  // 処理
})
.then(rly => {
  element.innerHTML = rly
})
element.onclick = () => {
  // 処理
}

これだと onclick が取得できません。タイミングの問題で element.innerHTML = rly する前に element.onclick が発行されます。これでは null にイベントリスナーが紐付いてしまいます。なので下のようにしました。

let element = null
new Promise(resolve => {
  // 処理
})
.then(rly => {
  element.innerHTML = rly
  element.onclick = () => {
    // 処理
  }
})

処理とロードの終了をトリガーにする

ある処理の終了と、諸要素のロードの両方が終了したタイミングで次の処理に移る書き方です。

let promise0 = new Promise(resolve => {
  // 処理
})
let promise1 = new Promise(resolve => {
  window.onload = () => {
    resolve()
  }
})
Promise.all([
  promise0,
  promise1
])
.then(rly => {
  // 処理
})

Unicode Property EscapesのHanは記号を含む

Unicode Property Escapesの「Han」は次の記号を含みます(僕とChatGPT調べ)。

〜、。〈〉《》「」『』【】〔〕〖〗〘〙〃〆・〓

なので本当に感じだけにマッチさせるには次のように書くといいと思います。

/(?![〜、。〈〉《》「」『』【】〔〕〖〗〘〙〃〆・〓])\p{scx=Han}/u

Notionの文字数を数えるJavaScript

Notionの開いているページの文字数を数えて表示する JavaScript です。Chromeの拡張機能「User JavaScript and CSS」を使用して導入してください。

JavaScript

/*

  count word

*/
(() => {
  document.querySelector(`body`).innerHTML += `<div class="count-word">Count</button>`
  let countWordButton = document.querySelector(`.count-word`)
  countWordButton.onclick = () => {
    let contentsWrapper = document
    .querySelector(`.notion-peek-renderer .notion-page-content`)
    if (contentsWrapper) {
      alert(countWord(contentsWrapper))
    }
    else {
      alert(countWord(document.querySelector(`.layout .notion-page-content`)))
    }
  }
  function countWord(elem) {
    let count = 0
    elem
    .querySelectorAll(`.notranslate`)
    .forEach(e => {
      count += e.textContent.replace(/\\r?\\n/g, ``).length
    })
    return count
  }
})()
/*

  count word

*/
.count-word {
  position: fixed;
  z-index: 10000;
  bottom: 110px;
  right: 25px;
  padding: 3px 7px 5px 7px;
  line-height: 1;
  color: #fff;
  background-color: rgba(128, 128, 128, 0.5);
  border-radius: 10px;
  cursor: pointer;
}
.count-word:hover {
  background-color: rgba(98, 98, 98, 0.5);
}

GitHub

github.com

JavaScript 自由研究 - 最頻値を求めるコード

javascript 配列の最頻値を求める | mebee」にあった以下のコードについて研究しました。

'use strict'
  
  const arr = ["a", "a", "a", "b", "c", "d", "d", "e", "e", "e", "e"];
  
  const c = (x, i, v) => (x[i] ? x[i].add(v) : x[i] = new Set(v), i);
  
  const result = arr.reduce(function (x, v) { return (this.set(v, c(x, (this.get(v) + 1 || 1), v)), x); }.bind(new Map), []).pop();
  
  console.log([...result]); // ['e']

概要

概要は下のとおりです。なかなかややこしいので 3 ステップに分けて解説します。 ‘use strict’ はなくても動くようなので省略しています。画像は拡大して表示することができます。

ステップ 1

  1. arr を参照します。
  2. 二つある this のうち前の this が arr を参照します。
  3. this は bind(new Map) によって初期化され Map オブジェクトになります。この時点で this からは重複が取り除かれます。
  4. この this を後ろの this が参照します。
 
POINT: this を「これ」だと思うと理解が阻害されます。「親を参照する」と考えると僕としては分かりやすいです。 前の this では親筋にあたる function(x, v) は関数ですので参照すべき親がありません。レキシカルスコープをたどって遡上するとメソッド reduce() があります。メソッドには親がいますので、この親である arr に行き着きます。 後ろの this も同様に関数 c のレキシカルスコープをたどってメソッド set() の親である、前の this に行き着きます。
 
  1. メソッド reduce() の引数である x と v が各所に配置されます。配置方法がこのコードの妙と言えましょう。後に関数 c の構造を見ていくと何が行われているのか分かるようになります。
  2. メソッド reduce() の引数 x の初期値が設定されます。

ステップ 2

  1. 関数 c の詳細です。関数 c は引数 x について引数 i と v を用いて処理をします。処理をしますが、戻り値はコロン演算子で区切られた最後の値 i となります。
  2. 引数 i と v が配置されます。
  3. 下のようになります。 A. x[i] が存在すれば、 B. Set オプジェクト x[i] に v を add() します。 A. x[i] が存在しなければ、 C. new Set(v) で初期化します。

ステップ 3

  1. 関数 c の戻り値として i が、メソッド Set() の第 2 引数として渡されます。
  2. 関数 function(x, v) の戻り値はコロン演算子の最後の値である x が return されます。それを受け取った reduce() は再び function(x, v) の引数 x としてリサイクルします。
  3. メソッド reduce() が arr について一通りの処理を行った結果を pop() します。 reduce() の返す最終的な配列 x ( x[i] の中身は Set )の最終項目が最頻値となります。
  4. result として結果が返されます。
  5. スプレッド演算子「 … 」によって Set である result を解体します。解体したものを [ ] を使って配列にして返します。