JSのbind、及び`this`について理解を少し深める

2021/01/05 20:24


<h4>bindそのものについて</h4> <p>JSのbindの用法を知り、「どういう時に使われるのか」が漠然とイメージできるようになりたかったため、概要と使われ方を調べた。</p> <p>とりあえず以下のサイトのデモコードを自分なりにいじってどういう挙動なのかは調べた。</p> <p><a href="https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Function/bind">Function.prototype.bind() - JavaScript | MDN</a></p> <pre class="code lang-javascript" data-lang="javascript" data-unlink><span class="synStatement">const</span> module = <span class="synIdentifier">{</span> a: 50, b: 30, text: <span class="synConstant">'this is test'</span>, showText: <span class="synIdentifier">function</span>()<span class="synIdentifier">{</span> <span class="synStatement">return</span> <span class="synIdentifier">this</span>.text; <span class="synIdentifier">}</span>, <span class="synIdentifier">}</span>; <span class="synStatement">const</span> moduleShow = module.showText; console.log(moduleShow); <span class="synComment">// moduleから抜き出した関数にmodule自体をbindする</span> <span class="synComment">// moduleShow内のthis = bindされたmoduleとなる</span> <span class="synComment">// そのため、this.text = module.text、になる</span> <span class="synStatement">const</span> boundGetX = moduleShow.bind(module); console.log(boundGetX()); </pre> <p><br></p> <p>その他、bindの概要、callとの違いについては下記の記事を見てイメージは出来た。 <a href="https://itsakura.com/js-bind">JavaScript this&#x306E;&#x5185;&#x5BB9;&#x3092;&#x6307;&#x5B9A;&#x3059;&#x308B;(bind&#x30E1;&#x30BD;&#x30C3;&#x30C9;) | ITSakura</a></p> <p>ただ、こいつがどういう目的で使われるかは分からなかった。<a href="#f-81413229" name="fn-81413229" title="こういったサンプルを見て、「じゃあこういうものにも応用できるな」と考えつく能力もプログラマに必要不可欠な能力だよな、と最近感じている">*1</a></p> <p>単純に、関数内のthis(thisがない場合はbind内の第一引数にnullを指定する)を特定のものに設定する(=undefinedにしない)場合にbindを使う、という使い方でいいのだろうか。</p> <h4>アロー関数内でのthisの扱われ方とbindの比較</h4> <p>ここまで調べて、そういえばJSの通常関数とアロー関数ではthisの指すものが異なる、という話しを思い出した。</p> <p><a href="https://qiita.com/mejileben/items/69e5facdb60781927929">&#x3010;JavaScript&#x3011;&#x30A2;&#x30ED;&#x30FC;&#x95A2;&#x6570;&#x5F0F;&#x3092;&#x5B66;&#x3076;&#x3064;&#x3044;&#x3067;&#x306B;this&#x3082;&#x5FA9;&#x7FD2;&#x3059;&#x308B;&#x8A71; - Qiita</a></p> <p><a href="https://qiita.com/suin/items/a44825d253d023e31e4d">JavaScript: &#x901A;&#x5E38;&#x306E;&#x95A2;&#x6570;&#x3068;&#x30A2;&#x30ED;&#x30FC;&#x95A2;&#x6570;&#x306E;&#x9055;&#x3044;&#x306F;&#x300C;&#x66F8;&#x304D;&#x65B9;&#x3060;&#x3051;&#x300D;&#x3067;&#x306F;&#x306A;&#x3044;&#x3002;&#x7570;&#x306A;&#x308B;&#x6027;&#x8CEA;&#x304C;10&#x500B;&#x307B;&#x3069;&#x3042;&#x308B;&#x3002; - Qiita</a></p> <p><br></p> <p>両者の<code>this</code>に関する違いとしては、アロー関数は<code>this</code>を束縛し、通常関数は<code>this</code>を束縛しない(=関数呼び出し元(レシーバ)をthisとする)という点である。</p> <p>下記のコードを例に比較する。</p> <ul> <li>通常関数</li> </ul> <pre class="code lang-javascript" data-lang="javascript" data-unlink> <span class="synIdentifier">this</span>.name = <span class="synConstant">&quot;globalName&quot;</span>; <span class="synComment">// 通常関数</span> <span class="synIdentifier">function</span> showName() <span class="synIdentifier">{</span> console.log(<span class="synIdentifier">this</span>.name); <span class="synIdentifier">}</span> <span class="synIdentifier">let</span> arrowFunc = <span class="synIdentifier">{</span> name: <span class="synConstant">&quot;john&quot;</span>, func: showName, <span class="synIdentifier">}</span>; arrowFunc.func(); =&gt; john <span class="synComment">// bindを使った場合</span> showName.bind(arrowFunc)(); =&gt; john </pre> <p><code>arrowFunc.func()</code>の返り値が<code>john</code>となっており、これはarrowFunc.nameの値であることが分かる。 このことから、<code>arrowFunc.func()</code>、つまりは<code>arrowFunc.showName()</code>のshowName内部のthisはarrowFunc(レシーバ)を指していたことが分かる。 <br></p> <ul> <li>アロー関数</li> </ul> <pre class="code lang-javascript" data-lang="javascript" data-unlink> <span class="synIdentifier">this</span>.name = <span class="synConstant">&quot;globalName&quot;</span>; <span class="synComment">// アロー関数</span> <span class="synStatement">const</span> showName = () =&gt; <span class="synIdentifier">{</span> console.log(<span class="synIdentifier">this</span>.name); <span class="synIdentifier">}</span>; <span class="synIdentifier">let</span> arrowFunc = <span class="synIdentifier">{</span> name: <span class="synConstant">&quot;john&quot;</span>, func: showName, <span class="synIdentifier">}</span>; arrowFunc.func(); =&gt; globalName </pre> <p><code>arrowFunc.func()</code>の返り値が「globalName」となっている。これは最初に定義した<code>this.name = "globalName"</code>のnameの値が表示されていることが分かる。 ここで、アロー関数内のthisについてのリファレンスを見てみる。</p> <blockquote><p>アロー関数自身は this を持ちません。レキシカルスコープの this 値を使います。つまり、アロー関数内の this 値は通常の変数検索ルールに従います。このためスコープに this 値がない場合、その一つ外側のスコープで this 値を探します。</p></blockquote> <p><a href="https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions#No_separate_this">&#x30A2;&#x30ED;&#x30FC;&#x95A2;&#x6570; - JavaScript | MDN</a></p> <p><br></p> <p>アロー関数である<code>showName</code>が定義された際、関数内のthisは更に外側のthisを見ていたことになる。 今回Node上で上記コードを実行したため、thisとして定義されていたのは<code>{name: "globalName"}</code>だったため、<code>showName</code>関数内のconsole.logで表示されたthis.nameは、コードの最初に定義したthis.nameだった、ということになる。</p> <p><br></p> <p>ちなみにトッ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D7%A5%EC%A5%D9">プレベ</a>ル、グロー<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D0%A5%EB%A5%B9">バルス</a>コープあたりはここを参考にした。</p> <p><a href="https://qiita.com/qeema/items/0b7e2ff4e33703a42a40">JavaScript&#x306E;&#x30C8;&#x30C3;&#x30D7;&#x30EC;&#x30D9;&#x30EB;&#x30B9;&#x30B3;&#x30FC;&#x30D7;&#x306F;&#x5E38;&#x306B;&#x30B0;&#x30ED;&#x30FC;&#x30D0;&#x30EB;&#x30B9;&#x30B3;&#x30FC;&#x30D7;&#x3067;&#x306F;&#x306A;&#x304B;&#x3063;&#x305F; - Qiita</a></p> <h4>まとめ</h4> <p>改めて<code>bind</code>、通常関数とアロー関数それぞれでのthisの使い方を確認した。 通常関数とアロー関数の違いについては他にも色々あるが、一旦知りたいと思っていたことを確認することができた。</p> <div class="footnote"> <p class="footnote"><a href="#fn-81413229" name="f-81413229" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text">こういったサンプルを見て、「じゃあこういうものにも応用できるな」と考えつく能力も<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D7%A5%ED%A5%B0%A5%E9%A5%DE">プログラマ</a>に必要不可欠な能力だよな、と最近感じている</span></p> </div>

需要が薄いMaterial-UIのvalidationの一例

2021/01/04 12:54


<p>空文字を許容しない、というバリデーションを一部分だけ書きたい、しかしそのために本格的なバリデーションの機構を組むのはめんどくさくて死にそう、という時にその場しのぎで書いたもの。</p> <pre class="code lang-javascript" data-lang="javascript" data-unlink> &lt;TextField label=<span class="synConstant">&quot;名前&quot;</span> variant=<span class="synConstant">&quot;outlined&quot;</span> margin=<span class="synConstant">&quot;normal&quot;</span> required <span class="synComment">// input.valueに入力された文字が入っているものとして、空文字の場合は input.value はfalseを返す</span> <span class="synComment">// 上記の場合に{ error: true }を返すことで &lt;TextField error /&gt; と書いた時と同じようになる</span> <span class="synComment">// { error: false } の場合はerrorは指定されていない状態になる</span> <span class="synIdentifier">{</span>...(!input.value ? <span class="synIdentifier">{</span> error: <span class="synConstant">true</span> <span class="synIdentifier">}</span> : <span class="synIdentifier">{</span> error: <span class="synConstant">false</span> <span class="synIdentifier">}</span>)<span class="synIdentifier">}</span> /&gt; </pre>

Material-UIのTextFieldをtype=&quot;date&quot;にした際のdefaultValueに指定する日付のフォーマットについて備忘録

2021/01/01 14:50


<p>material-uiの<code>TextFiled</code>という<a class="keyword" href="http://d.hatena.ne.jp/keyword/API">API</a>の中で、<code>type="date"</code>のようにタイプを指定することでDate pickerのように使用することができる。</p> <p><a href="https://material-ui.com/components/pickers/#native-pickers">Date picker, Time picker React components - Material-UI</a></p> <p>その際、デフォルトの日付を<code>defaultValue</code>というオプションで設定できるが、この部分で少し詰まったので備忘録として残す。</p> <h4>ダメだった例</h4> <pre class="code lang-javascript" data-lang="javascript" data-unlink> <span class="synComment">// 年、月、日の区切りがスラッシュになっているとdefaultValueとして認識されない</span> <span class="synStatement">const</span> today = dayjs().format(<span class="synConstant">'YYYY/MM/DD'</span>) &lt;TextField label=<span class="synConstant">&quot;testDay&quot;</span> type=<span class="synConstant">&quot;date&quot;</span> defaultValue=<span class="synIdentifier">{</span>today<span class="synIdentifier">}</span> margin=<span class="synConstant">&quot;normal&quot;</span> /&gt; </pre> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/f/fujjima/20210101/20210101144435.png" alt="f:id:fujjima:20210101144435p:plain" title="" class="hatena-fotolife" itemprop="image"></span></p> <h4>良かった例</h4> <pre class="code lang-javascript" data-lang="javascript" data-unlink> <span class="synComment">// 年、月、日の区切りがハイフンだときちんとdefaultValueとして指定できる</span> <span class="synStatement">const</span> today = dayjs().format(<span class="synConstant">'YYYY-MM-DD'</span>) &lt;TextField label=<span class="synConstant">&quot;testDay&quot;</span> type=<span class="synConstant">&quot;date&quot;</span> defaultValue=<span class="synIdentifier">{</span>today<span class="synIdentifier">}</span> margin=<span class="synConstant">&quot;normal&quot;</span> /&gt; </pre> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/f/fujjima/20210101/20210101144333.png" alt="f:id:fujjima:20210101144333p:plain" title="" class="hatena-fotolife" itemprop="image"></span></p> <p>詳細は調査中だが、同じようにdatapickerとして使用できる<code>KeyboardDatePicker</code>ではformatに<code>format="MM/dd/yyyy"</code>のように指定してもいける感じなので、どうしてこのような仕様にしているかはよく分からない。 しかも表示される時には<code>YYYY/MM/DD</code>形式だし。スラッシュどこに行った。</p> <p><a href="https://material-ui.com/components/pickers/#material-ui-pickers">https://material-ui.com/components/pickers/#material-ui-pickers</a></p>