### 提案の主題
ゲッター・セッター、DOM和属性、DOM和スタイルを`Object.defineProperty`にやらせよう
__setPropと__getPropを捨てよう
### 概要
「ゲッター・セッター、DOM和属性、DOM和スタイルを`Object.defineProperty`にやらせよう」
jsの`Object.defineProperty`はオブジェクトにプロパティを追加する機能がある
同時に、追加したプロパティにゲッター・セッターをつけることができる
DOM和属性が辞書キー形式(dom@key)で参照できるようになります
やらせたものを貯蔵庫に投稿してあります
DOM和属性革命プラグイン
本体:
https://n3s.nadesi.com/id.php?3147
使用例:
https://n3s.nadesi.com/id.php?3148
コードの追加量はそこそこです。
「オブジェクトの__setPropと__getPropを捨てよう」
こちらは大変な量のコード変更(削除)が発生します
大規模改修のやるきが高まった時に検討してください
__setPropと__getPropを捨てずにDOM和属性革命プラグインだけ採用しても問題はありません
### `Object.defineProperty`について
AIのcopilotくんと語らっていたところ、
jsには`Object.defineProperty`というものがあるのを知りました
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
> 構文
> Object.defineProperty(obj, prop, descriptor)
Object.definePropertyは、オブジェクト(obj)にプロパティ(prop)を追加して、descriptorでセッターゲッターを設定できます。
ふつうにセッター・ゲッターとして使うこともできますし、
domに日本語のプロパティ名を追加して英語のプロパティ名に値を渡すことができます。
なでしこ3のゲッター・セッター、DOM和属性、DOM和スタイルを`Object.defineProperty`にやらせることができそうです。
#### セッターのサンプル
「値セットした時」命令で、hoge["aaa"]に入れた値を100倍にしてhoge["bbb"]に入れるサンプルです。
(以下、サンプルのjs部分はcopilotくん作)
```
//なでしこ3貯蔵庫で実行可能です
//辞書型objのkeyに値を入れた時、funcを実行します
●値セットした時(funcでobjのkeyを|keyに):
『(function 値セット時(func, obj, key) {
const desc = Object.getOwnPropertyDescriptor(obj, key) || {};
Object.defineProperty(obj, key, {
get: desc.get || function () {},
set: function (value) {
sys.__setSysVar('対象', this);
func(value);
},
enumerable: true,
configurable: true
});
}
)』を[func, obj, key]でJS関数実行
objを戻す
変数 hogeは空辞書
hogeの「aaa」に値セットした時には (v):
対象["bbb"] = v * 100 //対象が使える
hoge["aaa"] = 10 //値セット時の関数が呼ばれ、bbbに入る
hoge["bbb"]を表示 //→1000
```
貯蔵庫に投稿したプログラムに「値セットした時」・「値ゲットした時」命令があります。
`objのkeyに値セットした時には (v):`でセッターを付与できます。
#### DOM和属性、DOM和スタイルとして使用する
DOM側に日本語のプロパティを追加し、ゲッターセッターでdomの英語のプロパティに紐づけします。
たとえばdom@"文字"に入れた値をdom["innerText"]へ入れます。サンプルは下記。
```
//なでしこ3貯蔵庫で実行可能です
//日本語名と英語名(domの属性名)を指定してDOMのプロパティに紐づけします
●DOM和属性追加(jpKeyをoriginalKeyに|originalKeyへ|originalKeyとして):
DOM和属性[jpKey] = originalKey //追加
『(function DOM和属性追加(jpKey, originalKey) {
Object.defineProperty(HTMLElement.prototype, jpKey, {
get() { return this[originalKey]; },
set(v) { this[originalKey] = v; },
enumerable: false,
configurable: true
});})』を[jpKey, originalKey]でJS関数実行
「文字」を「innerText」にDOM和属性追加 //dom@「文字」を追加し、セッターでinnerTextに渡す
「あ」のボタン作成
それ@「文字」は「テスト」 //dom$keyやdom.keyではなくdom@keyでアクセスできる
```
貯蔵庫に投稿したプログラムには「DOM和属性追加」「DOM和スタイル追加」命令があります。
この命令で追加されたプロパティは辞書キーの形式でアクセスできます。
dom$だけでなく、dom@やdom[]で参照できるようになります。
### なでしこ本体に組み込むことについて
これをなでしこ本体に組み込んだ時に大きな仕様変更が発生します。
変数`DOM和属性`にキーを追加するプログラムやプラグインは動かなくなります。
そんな時には`DOM和属性`をこの仕様に合わせる「DOM和属性革命」命令を使えばOKなようにしてあります。
```
//すべてのDOMはDOM和属性、DOM和スタイルの辞書キーを得る
●DOM和属性革命:
DOM和属性を反復:
対象キーを対象へDOM和属性追加 //日本語キーを英語キーへ
DOM和スタイルを反復:
対象キーを対象へDOM和スタイル追加
```
#### 「DOM側」へプロパティを追加する、とは
「DOM側」の解釈として2つあります。
・案1. HTMLElement.prototypeに追加する
・案2. なでしこが返すdomのみに追加する
貯蔵庫に投稿したプログラムではHTMLElement.prototypeに追加(案1)をしています。
影響範囲はHTMLElementを継承しているオブジェクト(HTMLタグ)だけなので限定的です。
HTMLElement.prototypeに日本語のキーを追加したところで弊害はないでしょう。("ID"や"HTML"はちょっとアブナイ?)
問題は貯蔵庫のクリアで消えないことくらいです。
AIのcopilotくんはこれはprototype汚染にあたらない、と言っています(日本語キーは他ライブラリとの衝突が少ない、プロトタイプ拡張であるとのこと)
それでもprototypeへの追加に不安があれば案2になるかと思います。
ただし案2の場合は下記が再発します。
https://github.com/kujirahand/nadesiko3/issues/1860
```
テストテーブルをマウス押した時には、:
もし、対象.nodeName=「TD」ならば、:
クリック行=対象.parentNode。
クリック行.背景色=「#CCF」 # できない!?
//クリック行の「背景色」に「#CCF」をDOMスタイル設定。 # できる
```
prototypeに追加する場合は問題が起きません。
下記は動かなくなります。
https://github.com/kujirahand/nadesiko3/issues/1869
```
A=「あああ」のボタン作成
A@「幅」=200px //OK
A@「行揃え」=「右」 //右辺(右)を変換するのはムリ(セッターを頑張れば可能)
```
### __setPropと__getPropを捨てたい
ゲッター・セッター、DOM和属性、DOM和スタイルをdefinePropertyで書き換えると__setPropと__getPropを捨てることができます。
__setPropと__getPropがオブジェクトから消えます。
ハテナ関数で表示されなくなります。
```
hoge = 空辞書
hoge.A=1
??hoge //→main(3): {"__setProp":null,"__getProp":null,"A":1}
```
セレクトボックスの「要素数」が選択肢の数より 2 大きくなるの件が解消されるでしょう。
https://github.com/kujirahand/nadesiko3/issues/2069
コンパイル後の__setProp/__getPropの存在確認がなくなり、jsが短くなります。
//なでしこ3での記述
hoge.A=1
//↓コンパイル後(とても長い)
/*[convLetProp]*/
if (typeof __self.__varslist[2].get("main__hoge").__setProp === 'function') { __self.__varslist[2].get("main__hoge").__setProp('A', 1, __self); } else { __self.__checkPropAccessor('set', __self.__varslist[2].get("main__hoge"));if (typeof __self.__varslist[2].get("main__hoge").__setProp === 'function') { __self.__varslist[2].get("main__hoge").__setProp('A', 1, __self); } else { __self.__varslist[2].get("main__hoge")['A'] = 1 }};
現在の__setPropと__getPropによるセッターゲッターは廃止になります
https://nadesi.com/v3/doc/index.php?%E6%96%87%E6%B3%95%2F%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E6%A7%8B%E6%96%87%E3%80%8C%24%E3%80%8D&show#h418b9cf2
__setPropと__getProp残したままDOM和属性革命をしても動作に問題はないので、廃止予定のまま併用することもできます。
### その他の活用法
DOMのプロパティ構文で、可視や有効などカスタムプロパティを使えるようにする
https://github.com/kujirahand/nadesiko3/issues/1823
についてはセッターゲッターで実装します
```
変数 HTMLElementprototype = 『HTMLElement.prototype』をJS実行
HTMLElementprototypeの"有効"を値セットした時には (v) DOM有効設定(対象,v)。。。
HTMLElementprototypeの"有効"を値ゲットした時には DOM有効取得(対象)。。。
```
HTMLElement.prototypeに追加すればすべての部品に影響しますが、
HTMLSelectElement.prototypeに追加すればセレクトボックスにだけ影響します。
HTMLElement.prototype.値 は valueを指し、
HTMLSelectElement.prototype.値 は selectedIndexを指す、ということができます。
```
//セレクトボックス専用の和属性を設定する
変数 HTMLSelectElement = 『HTMLSelectElement.prototype』をJS実行
{
"値":"selectedIndex",
"行":"size"
}を反復:
defineProperty(HTMLSelectElement,対象キー,対象)
```
「チェックボックス@テキスト」や「セレクトボックス@アイテム」をユーザー側からも追加できます
```
変数 select=[1,2,3]のセレクトボックス作成
selectの「アイテム」に値セットした時には (v):
vを対象へセレクトボックスアイテム設定
select@「アイテム」は[4,5,6,7]
```
### 過去ログ
歴史とか兼ね合いとかかちあいがありそうなissuesの抜粋
https://github.com/kujirahand/nadesiko3/issues/1793
https://github.com/kujirahand/nadesiko3/issues/1823
https://github.com/kujirahand/nadesiko3/issues/1860
https://github.com/kujirahand/nadesiko3/pull/1863