$ mol_strict: Que tal eu [objeto Object] seu NaN indefinido‼

Olá, meu nome é Dmitry Karlovsky e eu ... não perdoo erros. Assim que vejo, jogo imediatamente algo extremamente pesado. E como é difícil o trabalho de um programador JS ...







class Foo extends Object {}
const foo = new Foo

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

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

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

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





Existem várias maneiras de aliviar seu sofrimento.







  1. Cubra-se com um texto datilografado. Mas em tempo de execução, os pés ainda permanecem descalços e sempre alguém pisa neles.
  2. Para impor cheques. Mas você hesita um pouco e o ancinho em tempo de execução atinge imediatamente a cabeça.
  3. Corrija o JS. Nem espere.
  4. Corrija o tempo de execução do JS. Bem, vamos pensar ..


Os problemas de tipagem dinâmica JS surgem por 2 motivos principais:







  • Moldagem automática (e às vezes inadequada) de tipo quando um valor de um tipo é usado em um contexto destinado a outro.
  • Retorna undefined como o valor de campos não declarados.


Vamos lidar com o primeiro problema primeiro. JS é projetado de tal forma que não podemos corrigir a conversão de tipos primitivos de forma alguma. Mas temos controle total sobre o lançamento de objetos. Portanto, vamos corrigir o protótipo global de todos os objetos para que nenhum dos objetos possa ser lançado por padrão:







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