Pytanie Czy można tworzyć niestandardowe operatory w JavaScript?


Podczas zajęć Matematyki nauczyliśmy się definiować nowych operatorów. Na przykład:

(ℝ, ∘), x ∘ y = x + 2y

To definiuje  prawo. Dla dowolnych liczb rzeczywistych x i y, x ∘ y jest x + 2 y.

Przykład: 2 ∘ 2 = 2 + 4 = 6.


Czy można zdefiniować takie operatory w JavaScript? Wiem, że funkcja spełni zadanie:

function foo (x, y) { return x + 2 * y; }

ale chciałbym mieć następującą składnię:

var y = 2 ∘ 2; // returns 6

zamiast tego:

var y = foo(2, 2);

Jakie jest najbliższe rozwiązanie tego pytania?


21
2017-12-22 10:36


pochodzenie


Inną nazwą jest notacja funkcji infix - odpowiedź brzmi: nie, nie możesz - Eric
Możesz spróbować wykorzystać valueOf z istniejącymi operatorami, ale o to chodzi w JavaScript. - elclanrs
Twierdziłbym, że naprawdę zły jest pomysł zdefiniowania operatora, którego symbol nie występuje na mojej klawiaturze - Eric
Nie. Nie możesz tego zrobić w JavaScript. Możesz to jednak zrobić w Haskell. Pierwsza linia: infixl 6 ∘. Druga linia: x ∘ y = x + 2 * y. - Aadit M Shah
Technicznie możesz, pisząc własny leksykalny analizator składni i definiując swoje własne imię i nazwisko w typie skryptu <script> blok. Technika ta jest dość szeroko stosowana. Niektóre dobrze znane przykłady obejmują Google Traceur. - Derek 朕會功夫


Odpowiedzi:


Krótka odpowiedź brzmi: nie. ECMAScript (na którym oparty jest standardowy JS) nie obsługuje przeciążania operatora.

Na marginesie, w ECMAScript 7, będziesz w stanie przeciążyć podzbiór standardowych operatorów podczas projektowania niestandardowych typy wartości. Tutaj jest slajdów przez twórcę języka i Mozilla CTO Brendan Eich o temacie. Nie zezwoli to jednak na stosowanie operatorów arbitralnych, a przeciążone znaczenie będzie stosowane tylko do typów wartości. <- haha, które się nie wydarzyło.

Możliwe jest użycie narzędzi innych firm, takich jak sweet.js aby dodać operatorów niestandardowych, chociaż wymagałoby to dodatkowego etapu kompilacji.

Ja odpowiedział rozwiązaniem z zewnątrz JavaScript używając esprimy - to jest wymiana pieniędzy JavaScript i rozszerzenie go, nie jest natywny.


18
2017-12-22 10:39



Czy możesz dodać referencję? Jak zdefiniuję takiego operatora po jego wdrożeniu? - Ionică Bizău
Wątpię, aby jakakolwiek wersja ECMAScript zawierała możliwość definiowania nowych operatorów symbolicznych - zwykle jest to zarezerwowane dla języków takich jak haskell. Podejrzewam, że przyjdzie tylko z operatorem przeciążenie - Eric
@Eric, co robi Haskell, nie jest magią. W JS nie ma problemu z wprowadzaniem zwrotów do notacji infiksów :) Jednak tak, obecna propozycja omawia przeciążanie operatorów. - Benjamin Gruenbaum
@BenjaminGruenbaum: Jasne, to nie magia, ale zdefiniowanie operatorów symbolicznych to śliskie zbocze perl - Eric
Nie widzę żadnej wzmianki na Strona ECMAScript na obiektach wartości sugerując, że kod użytkownika może zadeklarować nowe typy wartości - Eric


Nie. JavaScript nie obsługuje przeciążania operatora. ale możesz zrobić metodę klasy, aby to zrobić

var mathClass = function(value){
   this.value = value;
}

mathClass.prototype.toLaw = function(){
   return 2 * this.value;
}

var y = new mathClass(2)
2 + y.toLaw(); //2 + 2 * y

3
2017-12-22 10:43



Możesz pójść o krok dalej i dodać je do Number.prototype, jak w mojej odpowiedzi - Eric


Nie. Nie możesz tego zrobić w JS.

Najbliższe IMO możesz zaimplementuj własne obiekt, który ma interfejs łańcuchowy, czyli "płynną" składnię. W ten sposób możesz działać tak, jakbyś mówił po kolei.

var eq = new YourEquationObject();

// Then operate like 1 - 2 * 3
eq.add(1).sub(2).mul(3);

Szczegóły zależą od Ciebie. Po prostu dawanie pomysłu.


2
2017-12-22 10:41





Możesz dodać pseudooperatorów za pomocą metod na Number.prototype:

Object.defineProperty(Number.prototype, 'myOp', {
    value: function(that) {
        return this + 2 * that;
    }
});

Wtedy cała ta składnia zadziała

alert( (2).myOp(2) )
alert( 2 .myOp(2) )
alert( 2..myOp(2) )
alert( 2.0.myOp(2) )

2.myOp(2) nie działa, ponieważ kropka jest traktowana jako kropka dziesiętna


2
2017-12-22 11:08





Nieco dłuższa niż krótka jest taka, że ​​możesz, ale jest to trochę bardziej zaangażowane niż to, co zrobiłeś w klasie Math

Aby rozszerzyć język o nowe konstrukcje, możesz użyć transformatora takiego jak http://esprima.org/ lub którykolwiek z pozostałych. Musisz zdefiniować swoją składnię, napisać parser, aby przeanalizować instrukcję i na końcu dodać rzeczywisty kod, aby wykonać części matematyczne. Kiedy te części są na miejscu, stworzyłeś nowy język, który działa tak samo jak javascript, ale z dodatkowym wsparciem  operator.

To naprawdę nie jest że trudno dodać nową składnię, tutaj jest przykład z facebooków, jak dodają składnię funkcji>> strzałki

https://github.com/facebook/jstransform/blob/master/visitors/es6-arrow-function-visitors.js


1
2017-12-22 10:54





Przeczytaj komentarze poniżej odpowiedzi.

Najwyraźniej nie możesz. Oto coś bliskiego:

function exec(input) {
    return Function(
        'return ' + input.replace(/∘( *[\d.]+)/g, '+ 2 * $1') + ';'
    )();
}

exec('2 ∘ 2'); // 6

1
2017-12-22 10:46



(1 + 1) ∘ (1 + 1) zrujnuje ci dzień - Eric
Paperscript robi to całkiem nieźle - Eric
@Eric Dobre podejście, ale '2 ∘ 2' jest ciągiem. Nie chciałbym być struną. - Ionică Bizău
@ イ オ ニ カ ビ ザ ウ: Pomysł polega na oznaczeniu tagu skryptu jako language="myjavascript", a następnie masz mały skrypt do tłumaczenia twojego kodu na surowy javascript na runtine - Eric
Aby zrobić to poprawnie, będziesz potrzebował biblioteki javascript AST żołądź lub esprima. Jeśli chcesz dodać nowych operatorów symbolicznych, prawdopodobnie będziesz musiał nieco poprawić parser - Eric


Zadaję również to pytanie, a oto moja odpowiedź:

function myCustomOperation(string){
var res = String.fromCharCode(9762);
var thing = string.replace(//g," + 10 + ");
thing=thing.replace(//g," * 2 + ");
thing=thing.replace(//g," / 3 * ");
return [eval(thing),string+" = "+eval(thing)];
};
var thing = myCustomOperation("

3  4

");
document.write(thing[1]);

0
2018-01-14 21:50