◆ window.on*** プロパティへの代入やグローバル変数定義では元から用意されてる setter が使われてリスナ定義される
◆ グローバルで onclick 関数を宣言して window.on*** プロパティに代入すると property descriptor が更新されて setter が使われず value 形式で設定される
◆ 結果として一度関数宣言で on*** プロパティを作るとそれ以降リスナを更新できなくなる

全体に対してリスナを付けるときは window に対して addEventListener メソッドを使います
シンプルなページだと window.onclick のようなプロパティに直接関数を代入することもあるかと思います

JavaScript では window がグローバルオブジェクトなので window.onclick への代入というのはグローバル変数 onclick に代入しているのといっしょです
また グローバルのスコープで関数宣言をするとグローバルに関数名の変数ができます
なので
window.onclick = function(){}

function onclick(){}
はどちらも window.onclick で関数を取得できて同じことのように見えます

window のプロパティに代入形式で onclick 設定

普通にプロパティ代入でリスナを設定するとこのように動きます

window.onclick = function(eve){console.log("defined by assignment of function expression")}
console.log(window.onclick)
// ƒ (eve){console.log("defined by assignment of function expression")}
window.dispatchEvent(new Event("click"))
// defined by assignment of function expression

イベントを起こすと実行されてメッセージが表示されています
このあとに関数構文でグローバルに onclick を定義して上書きします

function onclick(){console.log("defined by function statement")}
console.log(window.onclick)
// ƒ onclick(){console.log("defined by function statement")}
window.dispatchEvent(new Event("click"))
// defined by assignment of function expression

上書きはされているのにリスナは変更されていないようで 表示される文字は古いままです

先に関数構文でグローバルに onclick 定義

次は先に関数宣言した場合です

function onclick(){console.log("defined by function statement")}
console.log(window.onclick)
// ƒ onclick(){console.log("defined by function statement")}
window.dispatchEvent(new Event("click"))

イベントを起こしても何も起きません
この後で window のプロパティに代入形式で onclick 設定します

window.onclick = function(eve){console.log("defined by assignment of function expression")}
console.log(window.onclick)
// ƒ (eve){console.log("defined by assignment of function expression")}
window.dispatchEvent(new Event("click"))

これでも何も起きません

プロパティ代入しないとダメ

関数宣言で window.onclick を作ってもリスナとして実行はされないようです
また 最初にどっちで設定するかも大切で 先に関数宣言で window.onclick を作ってしまうとその後にプロパティ宣言してもダメのようです

何が違うのかが気になるので property descriptor を見てみます

プロパティ代入
window.onclick = function(){}
Object.getOwnPropertyDescriptor(window, "onclick")
// {get: ƒ, set: ƒ, enumerable: true, configurable: true}

関数宣言
function onclick(){}
Object.getOwnPropertyDescriptor(window, "onclick")
// {value: ƒ, writable: true, enumerable: true, configurable: false}

設定が違ってますね

on*** は特殊そうなので その他通常のプロパティで試してみます
window.foo = function(){}
Object.getOwnPropertyDescriptor(window, "foo")
// {value: ƒ, writable: true, enumerable: true, configurable: true}
function bar(){}
Object.getOwnPropertyDescriptor(window, "bar")
// {value: ƒ, writable: true, enumerable: true, configurable: false}

configurable の true/false はこちらも違っていますが 値を getter/setter で取得設定するか 単純に value で入っているかは on*** だけの特徴みたいです

configurable から想像できますが後から上書きしたときどうなるかもみてみます

window.onclick = function(){}
function onclick(){}
Object.getOwnPropertyDescriptor(window, "onclick")
// {value: ƒ, writable: true, enumerable: true, configurable: false}

先にプロパティへの代入であとから関数宣言の場合は configurable が最初は true なので変更されます
しかし 最初から関数宣言した時と同じように value が設定されてリスナとしては機能しません

function onclick(){}
window.onclick = function(){}
Object.getOwnPropertyDescriptor(window, "onclick")
// {value: ƒ, writable: true, enumerable: true, configurable: false}

先に関数宣言をした場合は configurable が false なので変更されず getter/setter 形式にはなりません

setter で設定されるとリスナにも登録される

何もしないページ開いた直後の状態でも onclick プロパティは null として存在します
そのときの property descriptor は
{get: ƒ, set: ƒ, enumerable: true, configurable: true}

プロパティへの代入だと setter による処理が行われます
これによってリスナ登録が行われてるようです

普通のグローバル変数の作成でも setter が定義されていればそれが使われます

Object.defineProperty(window, "foo", {
get(){return 1},
set(value){console.log("setter: ", value)},
})

var foo = 100
// setter: 100

console.log(foo)
// 1
↑はコピペだと var の宣言が先に行われて再定義エラーになります
foo が元から定義済みであるようにみせるため defineProperty を先に実行しておいて あとから foo 定義をするとコメントのような結果になります
(コンソールで 2 回に分けて実行するのがかんたん)


デフォルトでは configurable が true なので property descriptor は変更可能です
関数宣言をすると value 形式に置き換えてプロパティが再定義され setter が使われないのでリスナは設定されません

この後にプロパティに代入しても setter はすでになくなっていて value が置き換えられるだけになり リスナは設定されません
Object.defineProperty で設定しなおそうにも configurable が false に設定されてしまうので再定義しようとするとエラーになります


まとめると window のプロパティに存在する on*** って名前の関数宣言はやめておいたほうがいいでしょう
Firefox でも同じ動作でした


そういえばこの記事でなんで onclick の中で onclick 呼び出そうとしたのか不明でしたがこういうことしたかったのかも
<head>
<script>
function onclick(){
}
</script>
</head>
<body onclick="onclick()">
</body>