Можно ли создавать собственные операторы в JavaScript?

Во время занятий по математике мы научились определять новые операторы. Например:

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

Это определяет закон. Для любых действительных чисел x и yx ∘ y равно x + 2y.

Пример: 2 ∘ 2 = 2 + 4 = 6,


Можно ли определить такие операторы в JavaScript? Я знаю, что функция сделает работу:

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

но я хотел бы иметь следующий синтаксис:

var y = 2 ∘ 2; // returns 6

вместо этого:

var y = foo(2, 2);

Что является наиболее близким решением этого вопроса?

11 ответов

Решение

Краткий ответ: нет. ECMAScript (на котором основан стандарт JS) не поддерживает перегрузку операторов.

Кроме того, в ECMAScript 7 вы сможете перегружать подмножество стандартных операторов при разработке пользовательских типов значений. Вот слайд-колода от создателя языка и технического директора Mozilla Брендана Айча по этому вопросу. Однако это не позволит использовать произвольные операторы, а перегруженное значение будет применяться только к типам значений. <- ха-ха, что в итоге не случилось.

Можно использовать сторонние инструменты, такие как sweet.js, для добавления пользовательских операторов, хотя это потребует дополнительного шага компиляции.

Я ответил с помощью решения извне JavaScript с использованием esprima - это изменяет JavaScript и расширяет его, оно не является нативным.

Учитывая несколько новую функцию литералов тегов с шаблонами, которая была добавлена ​​в ES6, можно создавать собственные DSL для обработки встроенных выражений, таких как эти, включая различные алгебраические символы.

ех. (запустить в stackblitz)

function math(strings, x, y) {
  // NOTE: Naive approach as demonstration

  const operator = strings[1].replace(/\s/gi, "");

  if (operator == "∘") {
    return x + 2 * y;
  }
  else if (operator == "^") {
    return Math.pow(x, y);
  }
  else {
    return `Unknown operator '${operator}'`;
  }
}

console.log(math`${2} ∘ ${2}`)

Обратите внимание, что поскольку теговые литералы шаблона не обязательно возвращают строки в качестве результатов, они могут возвращать более сложные промежуточные структуры, подобные AST, для создания выражения, которое затем может быть дополнительно уточнено и затем интерпретировано при сохранении близости к языку, специфичному для предметной области. Я не нашел ни одной существующей библиотеки, которая бы делала это для Javascript, но это должно быть интересным и вполне доступным делом из того, что я узнал из теговых литералов шаблонов и использования в таких местах, как lit-html.

Вы можете добавить псевдо-операторы через методы на Number.prototype:

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

Тогда весь этот синтаксис будет работать

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

2.myOp(2) не работает, потому что период рассматривается как десятичная точка

Вы не можете сделать это в JS.

Самое близкое, что вы можете иметь к IMO, это реализовать свой собственный объект, который имеет цепочечный интерфейс, то есть "свободный" синтаксис. Таким образом, вы можете действовать, как если бы вы говорили в последовательности.

var eq = new YourEquationObject();

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

Подробности до вас, хотя. Просто выдавать идею.

Нет. JavaScript не поддерживает перегрузку операторов. но вы можете сделать метод класса для этого

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

Набор скомпилированных в JS языков поддерживает пользовательские операторы.

Я бы выделил ReasonML (ocaml-syntax-readable-by-js-folks) и Bucklescript (ocaml-to-js-compiler), благодаря которым пользовательские операторы выглядят аккуратно:

Например, оператор объединения строк может выглядеть так:

let (>|<) = (list, seperator) => Belt.List.reduce(list, "", (a, b) => a ++ seperator ++ b);

который затем можно использовать как:

[Styles.button, Media.Classes.atLeastTablet] >|< " "

Обратной стороной всего этого является тот факт, что он должен быть написан на языке, скомпилированном в js, и имеет множество плюсов и минусов, но обычно эти языки имеют привлекательность тонны приятного синтаксического сахара, которого вы не получаете в js /ts

Прочитайте комментарии ниже ответа.

Видимо, вы не можете. Вот что-то близкое:

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

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

Чуть дольше, чем короткий, так это то, что да, но это немного сложнее, чем то, что вы делали на уроке математики.

Чтобы расширить язык новыми конструкциями, вы можете использовать преобразователь, такой как http://esprima.org/ или любой другой. Вам нужно определить свой синтаксис, написать синтаксический анализатор для анализа вашего оператора и, наконец, добавить фактический код для выполнения математических частей. Когда эти части будут на месте, вы создали новый язык, который работает так же, как JavaScript, но с дополнительной поддержкой оператор.

Это действительно не так сложно, чтобы добавить новый синтаксис, вот пример facebooks, как они добавляют => синтаксис функции стрелки

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

Поскольку JS сейчас не позволяет определять собственные операторы, и если вы не хотите использовать сложные решения, вы можете рассмотреть расширениеNumberкласс с необходимыми функциями (операторами), например:

      Number.prototype.o = function(y) {
  return this + 2 * y;
};

// 2 ∘ 2

let n = 2;
const r1 = n.o(2);
console.log(r1); // Prints: 6

// OR

const r2 = (2).o(2);
console.log(r2); // Prints: 6

При таком подходе вы можете создавать сложные математические выражения, соединяя операторы один за другим:

      Number.prototype.pow = function(exponent) {
  return Math.pow(this,  exponent);
};

Number.prototype.sqrt = function() {
  return Math.sqrt(this);
};

// √((2 ∘ 2)² - 11)

const r3 = (((2).o(2)).pow(2) - 11).sqrt();
console.log(r3); // Prints: 5

Я тоже задавал этот вопрос, и вот мой ответ:

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]);

Есть несколько инструментов, компиляторов или языковых расширений, предоставляющих такую ​​возможность и даже использующих смайлики и другие вещи, которые редко встречаются в самом JavaScript.sweet.jsявляется самым близким, который я могу вспомнить, а также может быть полезен другой скомпилированный инструмент JavaScript .

Другие вопросы по тегам