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.
- 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.
- Para impor cheques. Mas você hesita um pouco e o ancinho em tempo de execução atinge imediatamente a cabeça.
- Corrija o JS. Nem espere.
- 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 , :
- ( . , , , .)
- UfoStation Chat ( — .)
, _jinnin , JS, UX .