Операторы равенства и сравнения

Операторы равенства и сравнения позволяют создавать логические структуры, поэтому без них невозможен ни один неэлементарный алгоритм. Они чрезвычайно тесно связаны с условными предложениями if и else—if, о которых мы поговорим в главе 6 этой книги. Сейчас же мы обсудим наиболее общие принципы, исходя из которых сравниваются объекты данных в ActionScript.

Операторы равенства
Определить равенство некоторых объектов данных можно, используя оператор «=». Проверить неравенство одного объекта данных другому можно с применением оператора «!=». Например:

trace (1 = 1); // Выводит: true
trace (1!=1); // Выводит: false

В качестве результата операторы равенства возвращают булевы величины true (равенство истинно) и false (равенство ложно).

Перестановка операндов операторов равенства никак не сказывается на возвращаемых ими результатах: а=b эквивалентно b=а.

Оператор неравенства «!=» может быть легко эмулирован с использованием оператора равенства «==» и логического отрицания: а!=b эквивалентно !(а=b).

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


Поэтому имеет смысл подробно рассмотреть правила, следуя которым сравниваются объекты данных разных типов:

• Два числа равны, если их разность равна нулю. Этот принцип не справедлив для специальных числовых значений. Нужно знать, что выражение NaN=NaN возвращает false, a Infinity=lnfinity — true, хотя разность соответствующих величин в обоих случаях равна NaN. Для проверки того, не является ли некоторое значение неопределенным или бесконечным, вместо операторов равенства лучше использовать специальные функции isNaN() и isFinite():

var a:Number=NaN;
trace(a=NaN); // Выводит: false (на основании этого вывода
// в алгоритме может произойти сбой)
trace(isNaN(а)); // Выводит: true (верный вывод)

Две строки равны, если они образованы одинаковой последовательностью символов. При этом учитывается и регистр символов. Если необходимо сравнить строки без учета регистра, то нужно использовать метод toLowerCase() или toUpperCase() класса String:

trace("привет"="Привет"); // Выводит: false
trace("привет"="Привет".toLowerCase()); // Выводит: true

Сравнивая строки, необходимо учитывать, что русские и латинские символы различны даже тогда, когда они имеют одинаковое начертание.


Кроме того, следует помнить, что пробел также является символом:

trace("Привет всем"="Привет всем");
// Выводит: false (слова разделяет различное
// число пробелов)

• Две булевы величины равны, если они обе равны или true, или false.

• Равенство для переменных, значением которых являются составные объекты данных (объекты, функции и клипы), соблюдается в том случае, если они указывают на один объект данных. Это означает, что даже если объекты данных, на которые ссылаются переменные, идентичны по своей структуре, но занимают отдельные области памяти, они будут считаться неравными. Например:

// Создаем объект данных типа object со свойствами а, b, с
var obj1:Object = {а:1, b:2, c:3};
// Создаем такой же объект, как и хранимый переменной obj1
var obj2:Object = {а:1, b:2, c:3);
// Создаем новую переменную, указывающую на obj1
var obj3:Object = obj1;
trace(obj1 == obj2); // Выводит: false (переменные указывают на разные
// объекты)
trace(obj1 == obj3); // Выводит: true (переменные указывают
// на одинаковый объект)

Нельзя установить структурную эквивалентность двух составных объектов данных, даже если они сравниваются не через переменные, а непосредственно сопоставлением литералов (на стадии выполнения между этими двумя способами стирается всякое различие):

trace([1,2,3]==[1,2,3]); // Выводит: false

Ввиду описанных особенностей сравнения составных объектов данных, в ActionScript не так просто определить, равны ли два различных объекта по своей структуре.


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

// Функция, сравнивающая два массива arrl и arr2
function arrEq (arr1:Array, arr2:Array):Boolean {
if (arr1 == arr2) { // Если переменные указывают на один массив,
// дальнейшая проверка излишняя
return true;
}
if (arr1.length!= arr2.length) { // Если не равны длины массивов,
// то они автоматически не равны
return false;
}
for (var i = 0; i if (arr1[i]!= arr2[i)) { // Если i-e элементы arr1 и arr2
// не равны, то не равны и массивы
return false;
}
}
return true; // Если все элементы arr1 и arr2 равны, возвращаем true
}
trace(arrEq([l,2,3], [1,2,3])); // Выводит: true
trace(arrEq([l,2,3], [1,2,4])); // Выводит: false

Более сложно определить, совпадают ли по структуре объекты, так как их свойства никак не сортируются, сохраняя порядок, в котором они выводятся при перечислении циклом for-in, в соответствии с последовательностью задания. Впрочем, такая задача, в отличие от установления равенства массивов, вряд ли может возникнуть на практике.

Если операнды оператора равенства являются объектами данных разных типов, то они чаще всего автоматически приводятся к числовому (number) типу.


Например:

trace(true=l); // Выводит: true (true преобразуется в 1)
trace("0.01"=0.01); // Выводит: true (строка "0.01" преобразуется
// в число 0.01)

Правила, по которым различные типы данных преобразуются в числа, поэтому сейчас мы их повторять не будем.

Если сравнивается null и undefined, возвращается true. Это противоречит тому, что Number(null)=Number(undefined)=NaN, a следовательно, является особенностью этих типов данных (они считаются эквивалентными). Ни null, ни undefined, будучи заданными в качестве операндов «—» или «!=», в числа не преобразуются, даже если второй операнд принадлежит к отличному от них типу:

trace(null=undefined); // Выводит: true

Если сравнивается составной объект данных с элементарным, то вначале проводится его преобразование к элементарному типу, и лишь затем осуществляется непосредственно сравнение. Например:

var bul:Boolean=new Boolean(l); // Создаем объект класса Boolean
// со значением true
trace (typeof bul); // Выводит: object bul действительно ссылается на объект)
trace (bul=l); // Выводит: true (bul преобразуется в элементарную
// величину true, которая затем переводится в число 1)

Таким образом, если сравниваются два объекта данных, принадлежащих к разным типам, их эквивалентность определяется за счет преобразования к числовому типу (причем с исключениями).

Это не всегда удобно.


Чтобы заставить систему приводить операнды операторов «==» или «!=» к нужному типу, можно воспользоваться функциями преобразования типов. Однако
гораздо изящнее применить следующие определения, использующие автоматическое приведение типов операндов некоторыми операторами:

• Сравнение в виде строк: ""+а=""+b
• Сравнение в виде чисел: а-0==b-0 (или +а=+b)
• Сравнение в виде булевых величин: !а==!b

Например:
var a ="";
var b=null;
trace(a=b); // Выводит: false (величины сравниваются за счет приведения
// к числам)
trace(!a=!b); // Выводит: true (операнды сравниваются, как булевы величины)

Очень часто бывает необходимо, чтобы сравнение величин производилось более строго, чем с использованием операторов «==» и «/=». Это связано с тем, что автоматическое преобразование типов, осуществляемое этими операторами, может. Привести к неверным выводам. Например, переменная, хранящая значение null, будет приравнена к переменной, которая вообще не определена:

var a=null;
trace (a=b); // Выводит: true

Для того чтобы можно было предупредить возникновение ошибок из-за преобразования типов, в ActionScript имеются специальные операторы строгого (strict) равенства, возвращающие false, если их операнды принадлежат к разным типам. Они отличаются от «обычных» дополнительным знаком «=»: «=» и «!—». Принципы, по которым осуществляется сравнение объектов данных, у операторов «обычного» и строгого равенства абсолютно идентичны. Пример:

trace(true=l); // Выводит: true (true преобразуется в 1)
trace(true===l); // Выводит: false (преобразования типов нет)
traсе(3!="3"); // Выводит: false (строка "3" преобразуется в число 3)
trace(3!=="3"); // Выводит: true (преобразования типов нет)

Операторы сравнения
К операторам сравнения в ActionScript, равно как и в математике, относятся следующие:

< Меньше
> Больше
<= Меньше или равно
>= Больше или равно

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

trace(l<=2); // Выводит: true
trace("A">"B"); // Выводит: false

Операции сравнения возможны только в случае числовых и строковых значений операндов. Если в качестве операндов используются объекты данных других типов, то они приводятся к допустимым типам по правилам, о которых мы поговорим ниже.

Если сравниваемые величины являются числами, то они сопоставляются по тем же правилам, что используются в математике. Никаких особенностей, кроме того, что нельзя сравнивать при помощи операторов «<» и «>» неопределенные значения (NaN), при этом не имеется:

trace(Number.POSITIVE_INFINITY>Number.MAX_VALUE); // Выводит: true
trace(NaN<=NaN); // Выводит: true (NaN==NaN лает false)
trace(NaN < NaN); // Выводит: undefined

Обратите внимание, что сравнение двух неопределенных числовых величин (NaN) при помощи операторов «<=» и «>=» дает в результате истину (true). Это достаточно необычно, так как операторы равенства «=» и «=» возвращают в этом случае false.

Если сравниваемые величины являются строками, то реализуется следующий алгоритм (для определенности приведем его вариант для выражения а>b):

1. Проверяется, не является ли b подстрокой а. Если это так, возвращается true. При этом учитывается, что любая строка является подстрокой самой себя, слитой с пустой строкой.

2. Если а является подстрокой b, возвращается false.

3. Определяется, на какой позиции в строках а и b впервые встречаются отличные символы. Соответствующий им индекс заносится в переменную k.

4. Вычисляются Unicode-коды символов, расположенных на позиции k в строках а и b. Полученные значения заносятся в переменные т и п.

5. Если т>п, возвращается true. Иначе результат — false.

Примеры сравнения строк:

trace("А">"В"); // Выводит: false (латинской А соответствует
// позиция 0x0041, а В - 0x0042)
trace("АВС">"АВ"); // Выводит: true ("АВ" является подстрокой "ABC")
trace("ABC">"abc"); // Выводит: false (буквы нижнего регистра расположены
// раньше, чем верхнего)
trace("АВС">"АВС"); // Выводит: false (символы кириллицы в Unicode занимают
// более "удаленный" интервал, чем латиницы)

На практике чаще всего сравнение строк используется для того, чтобы производить сортировку по алфавиту. Такая возможность существует благодаря тому, что в Unicode национальные алфавиты занимают отдельные блоки, в которых сохраняется традиционная последовательность символов.

При этом буквы верхнего регистра обычно располагаются позже, чем нижнего

Если переданные оператору сравнения величины являются объектами данных элементарных типов, отличных от string и number (null, undefined или boolean), то перед сопоставлением производится их преобразование к числовому типу:

trace(true>false); // Выводит: true (аналогично 1>0)

Если сравниваемые объекты данных представляют один из составных типов, то осуществляется их преобразование к элементарным типам, а затем полученные значения сопоставляются по описанным выше правилам. Например:

// Создаем два различных объекта типа object — obj1 и obj2
var obj1:Object = {a:1, b:2, c:3};
var obj2:Object = {a:4, b:5, c:6};
trace(obj1.toString()); // Выводит: [object Object]
trace(obj1>=obj2); // Выводит: true (объекты преобразуются в информационные
// строки [object Object])
trace(obj1>obj2); // Выводит: false

Из приведенного примера следует, что при использовании операторов сравнения равными могут быть признаны объекты данных, даже если они имеют различную структуру. Это связано с особенностями проводимого преобразования к элементарным типам и в принципе существенным недостатком не является, так как составные объекты данных сравниваются весьма редко.

Оцените статью: (0 голосов)
0 5 0

Статьи из раздела Action Script на эту тему:
Арифметические операторы
Виды операторов
Логические операторы
Поразрядные операторы
Служебные операторы

Вернуться в раздел: Action Script / 5. Операторы