JS.next

JavaScriptの最新実装情報を追うブログ

@@unscopablesが実装された

概要

with文に与えたオブジェクトの特定のプロパティがスコープに含まれることを防ぐための、
ビルトイン"unscopables"シンボルが実装された。


@@unscopablesプロパティのオブジェクトが有する名前のプロパティは、値がTruthyならスコープから外される。

var a = 'unscopable',
    b = 'unscopable',
    c = 'unscopable'

var obj = {
  a: 'scopable',
  b: 'scopable',
  c: 'scopable',
}

obj[Symbol.unscopables] = {
  b: true,
  c: false
}

with (obj) {
  console.log(a, b, c)
}

/* log
  "scopable" "unscopable" "scopable"
*/


何故必要なのか

ES2015で増えたメソッドとの兼ね合いで、with文が使われた古いコードを壊し得るため。(実際に問題が出た)

var ary = [] 
var keys = [1, 2, 3]
with (ary) {
  keys.push(4)
}

このwith文中の『keys』は、ES2015では『Array.prototype.keys』を参照してしまうので『.push(4)』でエラーになってしまう。
そのため『Array.prototype[@@unscopables]』には、新しく追加されたメソッドが登録されており、この問題を回避している。

console.log( Array.prototype[Symbol.unscopables] )

/* log
  {
    copyWithin : true,
    entries    : true,
    fill       : true,
    find       : true,
    findIndex  : true,
    includes   : true,
    keys       : true,
    values     : true,
  }
*/


意外な使い道

HTML要素のon~属性に記述するコードは、その要素やdocumentがスコープチェーンに入るが、それはwith文で囲まれたような実装になっていることが多い。
そこで、以下のようにdocumentの余計なプロパティがスコープに入ることを防ぐ為に使えるかもしれない。

<!-- 選択された画像ファイルを表示したい -->
<input type="file" onchange="nextSibling.src = URL.createObjectURL(files[0])"><img>
<!-- しかし、「URL」が「window.URL」ではなく「document.URL」を指してしまうのでエラーになる -->
<script>
  document[Symbol.unscopables] = { URL: true }
    // これでdocument.URLがスコープに含まれることを回避できる。
</script>


実装されるバージョン

V8 (3.28.62) 3.28.64(デフォルト有効) 4.3.65(値がTruthyかどうか見るようになった)