ECMAScript 7仕様のToPrimitive抽象的な操作

8977 ワード

本明細書では、ECMAScript7仕様におけるToPrimitiveの抽象的な動作を紹介する.
予備知識
ECMAScriptデータタイプECMAScriptデータタイプは2種類のデータタイプに細分化されています.1つは言語タイプで、1つは規範タイプです.
  • 言語タイプは開発者が直接使用できるデータタイプです.
  • 規範タイプはmeta-values(メタ値)を表し、アルゴリズムでECMAScript言語構造および言語タイプの意味を記述するために使用される.それらは主に仕様の説明に用いられ、本当に実現される必要はない.
  • ECMAScriptの言語タイプは全部で7種類あります.
  • Udefined
  • Null
  • Boolean、ブールタイプ
  • String、文字列タイプ
  • Symbol、シンボルタイプ
  • Number、デジタルタイプ
  • Object、オブジェクトタイプ
  • 元のデータタイプは、上記UndefinedNullBooleanStringSymbolNumber、およびListの総称であり、非対象データタイプである.以下に関連する仕様タイプは、« »だけであり、つまり、配列に類似したリストであり、シンボルSymbolで表される.
    @toPrimitive@@toPrimitiveには、Symbol.toPrimitiveなどの多くの有名なシンボルがあります.Symbolオブジェクトに定義されている属性の一つです.
    ToPrimitive(input[,PrferredType])
    抽象的な動作は、パラメータinputとオプションのパラメータPreferredTypeとを受け入れる.この抽象的な動作の目的は、パラメータinputを非オブジェクトデータタイプ、すなわち元のデータタイプに変換することである.inputが複数の元のデータに同時に変換できる場合、PreferredTypeの値を優先的に参照する.転化過程は下表を参照する.
    パラメータinputのデータタイプ
    結果
    Udefined
    input自身に戻ります
    Null
    input自身に戻ります
    ボロア
    input自身に戻ります
    Number
    input自身に戻ります
    String
    input自身に戻ります
    Symbol
    input自身に戻ります
    Object
    次のステップを実行します.inputのデータタイプがオブジェクトである場合、以下のステップが実行される.
  • PreferredTypeパラメータに入っていない場合、hint"default"に等しい.
  • もしPreferredTypehint Stringであれば、hint"string"に等しくなるようにする.
  • もしPreferredTypehint Numberであれば、hint"number"に等しくなるようにする.
  • は、exoticToPrimGetMethod(input, @@toPrimitive)に等しくさせる.概ね、意味は、パラメータinputを取得する@@toPrimitiveの方法である.
  • もしexoticToPrimUndefinedではないなら、
  • は、resultCall(exoticToPrim, input, « hint »)に等しくする.
  • は、exoticToPrim(hint)が元のデータタイプである場合、resultに戻る.
  • 投げタイプエラーの異常.
  • もしresulthintであれば、"default"hintに等しくなるようにする.
  • は、"number"の抽象的な動作の結果を返す.
  • Ordinary ToPrimitive(O,hint)OrdinaryToPrimitive(input, hint)のデータタイプは対象であり、Oのデータタイプは文字列であり、hintの値はhintであるか、"string"であるかのいずれかである.この抽象的な操作の手順は以下の通りである.
  • もし"number"hintであれば、"string"methodNamesに等しくなるようにする.
  • もし« "toString", "valueOf" »hintであれば、"number"methodNamesに等しくなるようにする.
  • は、各反復値« "valueOf", "toString" »について、順序で反復リストmethodNamesを反復する.
  • は、namemethodに等しくする.概ね、語義は、取得対象Get(O, name)O値に対応する属性である.
  • もしnameが起動できるなら、
  • は、methodmethodに等しくする.
  • は、Call(method, O)のタイプがオブジェクトでない場合、method()に戻る.
  • 投げタイプエラーの異常.
  • 上記の操作手順で分かります.
  • は、オプションパラメータresultが提供されていない場合、resultは、ToPrimitiveにデフォルトであることを6によって知る.
  • は、PreferredTypeのステップhintによって、規格で定義されている"number"の日付オブジェクトおよびToPrimitiveのシンボルオブジェクトのいずれもがプロトタイプに4の方法を定義するように、デフォルト動作をカバーすることができることが分かる.
  • 実践
    なぜ規範の抽象的な方法を説明するのかという質問があるかもしれませんが、抽象的な方法はまだ使えません.実はそうではないです.この方法は多くのところで使われます.あなたが知らないだけです.いくつかの実例を説明して、理解を深めます.
    ''+[1,2,3]
    '' + [1, 2, 3] // "1,2,3"
    標準の足し算操作によれば、動作@@toPrimitiveに対して、DateおよびSymbolを呼び出して@@toPrimitiveおよびx + yを元のデータタイプに変換する.上記の例ではToPrimitive(x)自体が元のデータタイプなので、ToPrimitive(y)自体に戻ります.xはオブジェクトタイプであり、配列はy属性を定義していない.''が提供されていないので、''が動作するステップ[1, 2, 3]において@@toPrimitivePreferredTypeに変化するので、ToPrimitive6hintである.
    var a = [1, 2, 3]
    a.valueOf() // [1, 2, 3],  a  
    a.toString() // "1,2,3"
    "number"は、配列OrdinaryToPrimitive自体か、オブジェクトタイプかを返しているので、methodNames方法を呼び出し続け、文字列« "valueOf", "toString" »に戻ります.
    '' + [1, 2, 3] // => '' + '1,2,3' => '1,2,3'
    この方法が元のデータタイプに戻るように配列プロトタイプ上のvalueOf方法をカバーすると、結果はどうなるだろうか?
    var a = [1, 2, 3]
    a.valueOf = function () {
        console.log('trigger valueOf')
        return 'hello'
    }
    '' + a //  => '' + 'hello' => 'hello'
    デフォルトのaを上書きした後、呼び出しtoStringは元のデータタイプに戻ります."1,2,3"valueOfによれば、この時は直接に戻ってきます.valueOf方法は再起動されません.また、コンソールvalueOfからOrdinaryToPrimitiveが出ています.つまり3.2.2は確かに呼び出されました.この方法がオブジェクトタイプに戻るように配列のデフォルトtoString方法をカバーすると、その結果はどうなるだろうか?
    var a = [1, 2, 3]
    a.toString = function () {
        console.log('trigger toString')
        return this
    }
    '' + a // Uncaught TypeError: Cannot convert object to primitive value
    配列プロトタイプ上のlog方法がオブジェクトタイプに戻るため、上記の例では"trigger valueOf"をカバーし、オブジェクトタイプにも戻すことで、valueOftoStringの第valueOfのステップ、すなわちタイプエラーの異常を捨てて、対象を元のデータタイプに変換することができない.上記では、toString方式によりOrdinaryToPrimitiveの動作をカスタマイズすることができると述べた.
    var a = [1, 2, 3]
    a[Symbol.toPrimitive] = function () {
        return 'custom'
    }
    '' + a // => '' + 'custom' => 'custom'
    加算動作は、4を呼び出したときに@@toPrimitiveを提供していません.次に、ToPrimitiveを優先的に使用するToPrimitiveの例として使用します.
    var a = [1, 2, 3]
    a.valueOf = function () {
        console.log('trigger valueOf')
        return 'hello'
    }
    a.valueOf() // "hello"
    a.toString() // "1,2,3"
    var obj = {}
    obj[a] = 'hello' // obj {1,2,3: "hello"}
    変数をキーとして使用すると、キー値を元のデータタイプに変換するPreferredTypeが呼び出され、hint Stringの値はPreferredTypeです.上記の例からも分かるように、ToPrimitiveおよびPreferredTypeの結果はすべて文字列であるが、hint Stringを使用し、a.valueOfを使用した結果である.もちろん、a.toString方法を再定義し、オブジェクトに戻ると、'1,2,3'の値が使用される.
    var a = [1, 2, 3]
    a.valueOf = function () {
        console.log('trigger valueOf')
        return 'hello'
    }
    a.toString = function () {
        console.log('trigger toString')
        return this
    }
    var obj = {}
    obj[a] = 'hello' // obj {hello: "hello"}
    そして、a.toStringは、コンソールでtoStringを先に出し、valueOflogを出す.もちろん、この二つが全部対象に戻ると、エラーが発生します.
    var a = [1, 2, 3] //        valueOf  
    a.toString = function () {
        console.log('trigger toString')
        return this
    }
    var obj = {}
    obj[a] = 'hello' // Uncaught TypeError: Cannot convert object to primitive value
    Date
    上記"trigger toString"において、logオブジェクトおよび"trigger valueOf"オブジェクトについては、プロトタイプにToPrimitive方法が定義されている.Dateの第Symbolステップの動作では、@@toPrimitiveが提供されていないときに、優先的にToPrimitiveを呼び出す方法を見ることができる.Date原型上の@toPrimitiveによって行われることは、非常に簡単である.6が提供されていない場合、優先的にPreferredType方法を呼び出す.したがって、上記の動作については、valueOfオブジェクトの動作が異なる.
    var a = [1, 2, 3]
    a.valueOf = function () {
        return 'hello'
    }
    a.valueOf() // "hello"
    a.toString() // "1,2,3"
    '' + a // "hello"
    var date = new Date()
    date.valueOf() // 1536416960724
    date.toString() // "Sat Sep 08 2018 22:29:20 GMT+0800 (      )"
    '' + date // "Sat Sep 08 2018 22:29:20 GMT+0800 (      )"
    PreferredTypetoString方法およびDate方法は、元のデータタイプに戻るが、優先的にdate方法を使用することができる.
    締め括りをつける
    本論文は主にvalueOfの抽象的な操作と関連した例を説明します.もしこの文章に何か間違いや不備があったら、コメントエリアにコメントしてください.