thisのブラウザ挙動/実装演習
メソッドの受渡しは、処理そのものと受け手の情報を切り離すことがあります。配列コールバック、bindの引数、newを含むコードを実行順に追い、安全に意図した対象を操作する方法を学びます。
この単元で学ぶこと
- メソッド移動と共有状態を追跡する
- コールバックへ受け手を渡す方法を選ぶ
- 束縛とnew・アローの優先関係を判定する
本文解説
同じ関数を別の対象へ置く const a={n:1,inc(){return ++this.n;}};const b={n:10,inc:a.inc};とします。b.inc()は11で、a.nは1です。関数本体が共有されても、nを保存するオブジェクトは別です。メソッド名や定義位置より、各呼出しでどの参照が受け手になるかを表にします。
引数の一部を先に固定する function sum(a,b){return this.n+a+b;}にsum.bind({n:10},2)を適用すると、thisと最初の引数を保持します。得られたfにf(4)を実行したときはa=2,b=4で16です。bindの先頭はthis用の枠なので、通常引数を一つずつずらして読む必要があります。
束縛後も対象は変化する const a={n:2};const f=read.bind(a);の後a.n=9にすると、readがthis.nを返す場合f()は9です。bindはオブジェクトのスナップショットを作りません。f.bind({n:8})を作っても元のthis=aは上書きされないため、対象を切り替えたいなら元のreadから新しくbindします。
内側の関数を比較する obj.run()の中でfunction f(){return this;}と書いてf()を呼ぶと、strictではundefinedです。通常関数は外側のthisを自動継承しません。一方const f=()=>this;なら外側runのthisを読みます。ネストしていること自体ではなく、どちらの関数記法を使ったかが分岐点になります。
mapへ渡す二つの方法 const a={n:5,read(){return this.n;}};に対し[1,2].map(a.read.bind(a))は[5,5]です。[1,2].map(a.read,a)も、mapの第2引数thisArgを通常コールバックへ渡すので同じ結果になります。ただしコールバックがアローならthisArgで外側thisは変えられません。APIの引数仕様と関数の種類を両方確認します。
取り出した関数を明示して呼ぶ const {read}=a;は分割代入で関数値を得る操作です。read()では受け手を失いますが、read.call({n:12})なら12を返せます。aが書かれていた構文から関数を得たことと、その後の関数にaが束縛されていることは別です。取り出した時点と呼んだ時点を二行に分けて追います。
束縛したコンストラクタ function Item(n){this.n=n;}、holder={n:1}、Bound=Item.bind(holder,7)を考えます。new Bound()はholderへ代入するのでなく、新しい実体のnを7にします。newでは束縛済みthisを使わず、束縛済み引数は適用します。アローは元々構築可能でないため、bindしてもnewで使えるようにはなりません。
関数の返却だけではthisは固定されない a.make()がfunction(){return this.n;}を返す場合、その通常関数をb.fへ保存してb.f()を呼べばthisはbです。返した関数が()=>this.nならa.make()の外側thisを参照します。通常関数・アロー・束縛済み関数の三種類を区別すると、返却関数を使う設計でも結果を説明できます。
図解
重要ポイント
- bindは対象の現在のプロパティを読み続ける。
- mapのthisArgは通常関数へ渡せる。
- newでは束縛済みthisより生成した実体が使われる。
- 返却した通常関数は新しい呼出し先でthisが決まる。
間違えやすい点
- bindの生成と関数の実行を混同しない。
- メソッド共有を状態の共有と決めつけない。
- オブジェクトを返すアローをコンストラクタと思わない。
用語解説
- thisArg
- callや配列メソッドなどが、呼ぶ通常関数のthisとして指定する引数。
- 部分適用
- いくつかの引数を先に固定し、残りを後から与えること。
- 構築可能
- newによるオブジェクト生成の呼出しを受け付ける性質。
関連教材
参考資料
教材データに登録された参考リンクです。リンク先の内容や更新日は提供元でご確認ください。
- https://html5exam.jp/outline/objectives_lv2.html
- https://tc39.es/ecma262/2024/multipage/ordinary-and-exotic-objects-behaviours.html#sec-ordinarycallbindthis
- https://tc39.es/ecma262/2024/multipage/ecmascript-language-functions-and-classes.html#sec-class-definitions
- https://tc39.es/ecma262/2024/multipage/ecmascript-language-statements-and-declarations.html#sec-try-statement
確認問題の出題・採点や学習履歴の保存にはログインが必要です。