$ mol_strict:私はどうですか[オブジェクトオブジェクト]あなたの未定義のNaN!

こんにちは、私の名前はドミトリー・カルロフスキーです。私は...間違いを許しませんそれを見るとすぐに、非常に重いものを投げますそして、JSプログラマーの仕事はどれほど難しいか...







class Foo extends Object {}
const foo = new Foo

`, ${ foo }!`
// " [object Object]!"

`     ${ foo / 1000 }  .`
// "     NaN  ."

`  "${ 'foo'[4] }" - .`
// "  "undefined" - ."

`  ${ foo.length - 1 }     .`
// "  NaN     ."
      
      





彼の苦しみを和らげるにはいくつかの方法があります。







  1. タイプスクリプトで身を隠してください。しかし、実行時には、足はまだ裸のままであり、誰かが常に足を踏みます。
  2. チェックを課すため。しかし、少し躊躇すると、ランタイムレーキがすぐに頭に浮かびます。
  3. JSを修正します。希望すらしないでください。
  4. JSランタイムを修正しました。さて、考えてみましょう..


JS動的型付けの問題は、主に2つの理由で発生します。







  • あるタイプの値が別のタイプを対象としたコンテキストで使用される場合の自動(場合によっては不適切な)型キャスト。
  • 宣言されていないフィールドの値としてundefinedを返します。


最初に最初の問題に対処しましょう。JSは、プリミティブ型のキャストを修正できないように設計されています。ただし、オブジェクトのキャストは完全に制御できます。したがって、すべてのオブジェクトのグローバルプロトタイプにパッチを適用して、デフォルトでどのオブジェクトもキャストできないようにします。







Object.prototype[ Symbol.toPrimitive ] = function() {
    throw new TypeError( `Field Symbol(Symbol.toPrimitive) is not defined` )
}
      
      





, , Symbol.toPrimitive



.







, . - … - ! … , .







- , . JS — . , :







export let $mol_strict_object = new Proxy( {}, {

    get( obj: object, field: PropertyKey, proxy: object ) {
        const name = JSON.stringify( String( field ) )
        throw new TypeError( `Field ${ name } is not defined` )
    },

})
      
      





, prototype



Object



, , . Object.prototype



null



. Object



:













:







for( const name of Reflect.ownKeys( $ ) ) {
    // ...
}
      
      





, :







const func = Reflect.getOwnPropertyDescriptor( globalThis, name )!.value
if( typeof func !== 'function' ) continue
if(!( 'prototype' in func )) continue
      
      





, globalThis[name]



, .







, Object



:







const proto = func.prototype
if( Reflect.getPrototypeOf( proto ) !== Object.prototype ) continue
      
      





, , Object.prototype



:







Reflect.setPrototypeOf( proto, $mol_strict_object )
      
      





, , . , .







, , Object, , EventTarget, .







CSSStyleDeclaration



: ( , ), , , 89 style



dom-:







( <div style={{ color: 'red' }} /> ).outerHTML // <div></div>
      
      





.







… :







class Foo {}
      
      





. :







class Foo extends Object {}
      
      





… . Object



:







globalThis.Object = function $mol_strict_object( this: object, arg: any ) {
    let res = Object_orig.call( this, arg )
    return this instanceof $mol_strict_object ? this : res
}

Reflect.setPrototypeOf( Object, Reflect.getPrototypeOf({}) )
Reflect.setPrototypeOf( Object.prototype, $mol_strict_object )
      
      





, Object



, .







, ...







class Foo extends Object {}
const foo = new Foo

`, ${ foo }!`
// TypeError: Field "Symbol(Symbol.toPrimitive)" is not defined

`     ${ foo / 1000 }  .`
// TypeError: Field "Symbol(Symbol.toPrimitive)" is not defined

`  "${ 'foo'[4] }" - .`
// TypeError: Field "4" is not defined

`  ${ foo.length - 1 }     .`
// TypeError: Field "length" is not defined
      
      





, , :







, - . — .







, : JavaScript ?.







: $mol_strict.







NPM - :







import "mol_strict"
      
      





:







require("mol_strict")
      
      





$mol : $mol: Usage from NPM ecosystem.







JS , :









, _jinnin , JS, UX .








All Articles