Может ли кто-нибудь объяснить мне, что такое логический флаг "LeftFirst", который они определили в спецификации ecmaScript

Может кто-нибудь объяснить мне, что такое LeftFirstЛогический флаг? при чтении спецификации EcmaScript о [реляционных операторах] ( https://tc39.es/ecma262/"определение реляционных операторов в ECMAScript") и абстрактном реляционном сравнении я обнаружил что-то вродеLeftFirst Boolean Flag либо становится true или false но я не знаю, для чего это нужно и для чего это нужно, может кто-нибудь четко объяснить мне, в чем цель LeftFirst Логический флаг и почему он используется в спецификации, объяснение, которое они дали, не очень понятно Я хочу знать, как он используется. leftFirst Логический флаг и почему он используется?

2 ответа

Решение

Как вы заметили, это один из входов в алгоритм абстрактного реляционного сравнения. Его единственная цель - определить, какой операнд алгоритм сравнения передается в ToPrimitive первым: левый (leftFirst = true) или правый (leftFirst = false). Причина в том, что абстрактное реляционное сравнение всегда< сравнение, но оно также используется при оценке >выражения (с перевернутыми операндами). Поэтому при обращении с>, сначала нужно указать ToPrimitive в правом операнде.

Вы можете увидеть его использование на первом этапе алгоритма:

  1. Если флаг LeftFirst истинен, то
    • Пусть будет px? ToPrimitive(x, номер подсказки).
    • Пусть ру будет? ToPrimitive (y, номер подсказки).
  2. В противном случае,
    ПРИМЕЧАНИЕ. Порядок оценки необходимо изменить на обратный, чтобы сохранить оценку слева направо.
    • Пусть ру будет? ToPrimitive (y, номер подсказки).
    • Пусть будет px? ToPrimitive(x, номер подсказки).

Также в описании:

Флаг используется для управления порядком, в котором операции с потенциально видимыми побочными эффектами выполняются над x и y. Это необходимо, потому что ECMAScript определяет оценку выражений слева направо.

Например, если вы посмотрите на < а также >операции,&lt; операция делает:

  1. Пусть r будет результатом выполнения абстрактного реляционного сравнения lval .

При этом используется значение по умолчанию leftFirst, то естьtrue. Такlval передается через ToPrimitive до rval.

Но > операция делает:

  1. Пусть r будет результатом выполнения абстрактного реляционного сравнения rval < lval с LeftFirst, равным false.

Обратите внимание, что это rval < lvalне lval > rval. Но он использует leftFirst =falseпотому что важно, чтобы правый операнд проходил через ToPrimitive перед левым операндом, поскольку реальная операцияlval > rval, так lval сначала нужно пройти через ToPrimitive.


В комментарии вы сказали:

Большое спасибо, я знаю, почему, если < оператор LeftFirst true Почему <= тоже не LeftFirst true и почему если > оператор LeftFirst false то >= оператор тоже не LeftFirst false

Это определенно немного сбивает с толку. Причина, по которой< а также <= не совпадают (и > а также >= не совпадают) в том, что <=/>=Операторы инвертируют результат абстрактного реляционного сравнения (ARC). Так:

  • lval < rval делает:

    let r = ARC(lval < rval, leftFirst = true);
    return r === undefined ? false : r; // Returns what ARC returned (but
                                        // turns `undefined` into `false`)
    
  • lval <= rval делает

    let r = ARC(rval < lval, leftFirst = false);
    return r === undefined ? true : !r; // Returns the *inverse* of what ARC
                                        // returned (and turns `undefined`
                                        // into `true`)
    
  • lval > rval делает:

    let r = ARC(rval < lval, leftFirst = false);
    return r === undefined ? false : r; // Returns what ARC returned (but
                                        // turns `undefined` into `false`)
    
  • lval >= rval делает:

    let r = ARC(lval < rval, leftFirst = true);
    return r === undefined ? true : !r; // Returns the *inverse* of what ARC
                                        // returned (and turns `undefined`
                                        // into `true`)
    

И последнее замечание, давайте рассмотрим это:

const obj = {
    get lval() {
        console.log("obj.lval was evaluated");
        return {
            valueOf() {
                console.log("lval was passed through ToPrimitive");
                return 42;
            }
        };
    },
    get rval() {
        console.log("obj.rval was evaluated");
        return {
            valueOf() {
                console.log("rval was passed through ToPrimitive");
                return 24;
            }
        };
    }
};

console.log("Using >");
const result1 = obj.lval > obj.rval;
// "obj.lval was evaluated"
// "obj.rval was evaluated"
// "lval was passed through ToPrimitive"
// "rval was passed through ToPrimitive"
console.log(result1);
// true

console.log("Using <");
const result2 = obj.lval < obj.rval;
// "obj.lval was evaluated"
// "obj.rval was evaluated"
// "lval was passed through ToPrimitive"
// "rval was passed through ToPrimitive"
console.log(result2);
// false
.as-console-wrapper {
    max-height: 100% !important;
}

Результат, который вы видите, таков:

Использование> obj.lval было оценено obj.rval было оценено lval было передано через ToPrimitive rval было передано через ToPrimitive true Использование

Вот что происходит при создании этого вывода для >:

  1. В obj.lval > obj.rval выражение оценивается
  2. В > выполняется операторный алгоритм:
    1. Он оценивает lval = obj.lval (Шаги 1 и 2), что вызывает "obj.lval was evaluated" выход
    2. Он оценивает rval = obj.rval (Шаги 3 и 4), что вызывает "obj.rval was evaluated" выход
    3. Он вызывает ARC (шаг 5): ARC(obj.rval < obj.lval, leftFirst = false)
      1. ARC получает obj.rval как x а также obj.lval как y
      2. ARC видит leftFirst = false и так оно и есть:
        • py = ToPrimitive(y) (Шаг 2.b), что вызывает "lval was passed through ToPrimitive" выход
        • px = ToPrimitive(x) (Шаг 2.c), что вызывает "rval was passed through ToPrimitive" выход
      3. ARC возвращается false
  3. В > оператор инвертирует возвращаемое значение ARC и возвращает true

Вот что происходит при создании последующего вывода для <:

  1. В obj.lval < obj.rval выражение оценивается
  2. В < выполняется операторный алгоритм:
    1. Он оценивает lval = obj.lval (Шаги 1 и 2), что вызывает "obj.lval was evaluated" выход
    2. Он оценивает rval = obj.rval (Шаги 3 и 4), что вызывает "obj.rval was evaluated" выход
    3. Он вызывает ARC (шаг 5): ARC(obj.lval < obj.rval) (leftFirst по умолчанию - true)
      1. ARC получает obj.lval как x а также obj.rval как y
      2. ARC видит leftFirst = true и так оно и есть:
        • px = ToPrimitive(x) (Шаг 1.а), что вызывает "lval was passed through ToPrimitive" выход
        • py = ToPrimitive(y) (Шаг 1.b), что вызывает "rval was passed through ToPrimitive" выход
      3. ARC возвращается false
  3. В < оператор возвращает возвращаемое значение ARC, false

Как указано в спецификации в вашей ссылке:

Сравнение x Флаг используется для управления порядком, в котором операции с потенциально видимыми побочными эффектами выполняются над x и y. Это необходимо, потому что ECMAScript определяет оценку выражений слева направо. Значение по умолчанию LeftFirst -true и указывает, что параметр x соответствует выражению, которое встречается слева от соответствующего выражения параметра y. Если LeftFirst ложно, то все наоборот, и операции должны выполняться над y перед x.

В качестве примера рассмотрим два сравниваемых объекта. За<для выполнения на них оба должны быть сначала приведены к примитивам, и это примитивное принуждение может иметь побочные эффекты, которые могут повлиять на принуждение другого объекта. Это было бы странно, но синтаксически это возможно, поэтому в спецификации необходимо указать, что должно произойти в такой ситуации.

Имейте в виду, что существует только одна версия абстрактного реляционного сравнения - дляexpr1 < expr2. Нет отдельной версии дляexpr1 > expr2. ВLeftFirst Флаг используется при вызове абстрактного реляционного сравнения, чтобы указать, какое из выражений должно быть вычислено первым, так что порядок операций слева направо сохраняется.

Вот пример:

let val = 1;
const obj1 = {
  valueOf() {
    val++;
    return val;
  }
};
const obj2 = {
  valueOf() {
    val++;
    return val;
  }
};
console.log(obj1 < obj2);

Выражения оцениваются слева направо. obj1 оценивается до obj2, поэтому после извлечения примитивов obj1 меньше чем obj2.

let val = 1;
const obj1 = {
  valueOf() {
    val++;
    return val;
  }
};
const obj2 = {
  valueOf() {
    val++;
    return val;
  }
};
console.log(obj2 > obj1);

В obj2 > obj1 фактически вызывает абстрактное реляционное сравнение obj1 < obj2, с LeftFirst из false. В итоге правая сторона,obj2 оценивается первым, потому что он идет первым в исходном коде.

Интуитивно, при оценке слева направо, мы ожидали

obj2 > obj1

привести к

// evaluate obj2, increment val
2 > obj1

// evaluate obj1, increment val
2 > 3

в результате чего false.

Если бы не такой флаг, приведенный выше пример привел бы к obj1 сначала оценивается, и в результате obj1 будет меньше чем obj2, и результат сравнения будет true. Но это нежелательно: выражения следует оценивать слева направо.

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