Я искал код из Mozilla, который добавляет метод фильтра в Array, и в нем была строка кода, которая смутила меня.
var len = this.length >>> 0;
Я никогда не видел >>> используется в JavaScript раньше.
Что это такое и что оно делает?
javascript
operators
bit-shift
Кеннет Дж
источник
источник
Array.prototype.push
/Array.prototype.pop
- hexmen.com/blog/2006/12/push-and-pop (хотя он делал тесты, ха-ха).Ответы:
Он не просто конвертирует не-числа в число, он конвертирует их в числа, которые могут быть выражены как 32-разрядные целые числа без знака.
Хотя Числа JavaScript являются двойной точности поплавки (*), операторы битовые (
<<
,>>
,&
,|
и~
) определены в терминах операций на 32-разрядных целых чисел. Выполнение побитовой операции преобразует число в 32-разрядное целое число со знаком, теряя все дроби и старшие разряды, чем 32, перед выполнением вычисления и последующим преобразованием обратно в число.Таким образом, выполнение побитовой операции без реального эффекта, например, сдвиг вправо на 0 бит
>>0
, - это быстрый способ округлить число и убедиться, что оно находится в 32-битном диапазоне int. Кроме того, тройной>>>
оператор после выполнения своей операции без знака преобразует результаты своего вычисления в число как целое число без знака, а не как целое число со знаком, как это делают другие, поэтому его можно использовать для преобразования отрицаний в дополнение 32-бит-два. Версия как большой номер. Использование>>>0
гарантирует, что у вас есть целое число от 0 до 0xFFFFFFFF.В этом случае это полезно, потому что ECMAScript определяет индексы массива в терминах 32-битных беззнаковых целых. Поэтому, если вы пытаетесь реализовать
array.filter
таким образом, который бы точно повторял то, что говорится в стандарте ECMAScript Fifth Edition, вы бы преобразовали число в 32-битное целое число без знака, как это.(На самом деле существует мало практическая потребность в этом , как мы надеемся , что люди не будут установки
array.length
на0.5
,-1
,1e21
или'LEMONS'
. Но это авторы JavaScript мы говорим о, так что вы никогда не знаете ...)Резюме:
(*: ну, они определены как ведущие себя как плавающие. Меня не удивит, если какой-то движок JavaScript действительно использует int, когда это возможно, по соображениям производительности. Но это будет деталь реализации, которую вы не захотите взять. преимущество.)
источник
RangeError: invalid array length
.Array.prototype.filter.call
), поэтому наarray
самом деле может не быть действительнымArray
: это может быть какой-то другой определенный пользователем класс. (К сожалению, это не может быть надежным NodeList, когда вы действительно захотите это сделать, поскольку это хост-объект. Это оставляет единственное место, где вы действительно можете сделать это, какarguments
псевдо-массив.)if
выглядело это утверждение при попытке определить, что левая часть оценки не является целой?'lemons'>>>0 === 0 && 0 >>>0 === 0
оценивает как правда? хотя лимоны, очевидно, слово ..?Оператор сдвига вправо без знака используется во всех реализациях метода extra этого массива в Mozilla, чтобы гарантировать, что
length
свойство представляет собой 32-разрядное целое число без знака .length
Свойство объектов массива будет описано в описании как:Этот оператор является кратчайшим путем для достижения этого, методы внутреннего массива используют
ToUint32
операцию, но этот метод недоступен и существует в спецификации для целей реализации.Реализации дополнительных функций в массиве Mozilla стараются быть совместимыми с ECMAScript 5 , посмотрите описание
Array.prototype.indexOf
метода (§ 15.4.4.14):Как вы можете видеть, они просто хотят воспроизвести поведение
ToUint32
метода в соответствии со спецификацией ES5 для реализации ES3, и, как я уже говорил, оператор беззнакового сдвига вправо является самым простым способом.источник
ToUint32
мне это немного не нужно.Array.prototype
методов являются преднамеренно общими , их можно использовать в объектах, подобных массивам, напримерArray.prototype.indexOf.call({0:'foo', 1:'bar', length: 2}, 'bar') == 1;
.arguments
Объект также является хорошим примером. Для объектов чистого массива невозможно изменить типlength
свойства, потому что они реализуют специальный внутренний метод [[Put
]], и когда присваиваетсяlength
свойство свойству, он снова преобразуетсяToUint32
и выполняются другие действия, такие как удаление индексов выше новая длина ...Это оператор беззнакового сдвига вправо . Разница между этим и подписанным правом оператора сдвига бит , является то , что без знака правый бит - оператор сдвига ( >>> ) заполняется нулями слева, и подписал правый бит оператор сдвига ( >> ) заполняется знаковый бит, таким образом , сохранение знака числового значения при смещении.
источник
>>>
конвертирует в целое число, которое+
не делает унарное.Дриис достаточно объяснил, что такое оператор и что он делает. Вот смысл этого / почему он был использован:
Сдвиг любого направления на
0
действительно возвращает исходное число и приведётnull
к0
. Похоже, что пример кода, который вы просматриваете, используетсяthis.length >>> 0
для обеспечения того, чтобыlen
он был числовым, даже еслиthis.length
он не определен.Для многих людей побитовые операции неясны (и Дуглас Крокфорд / Jslint предлагает не использовать такие вещи). Это не означает, что это неправильно, но существуют более благоприятные и знакомые методы, которые делают код более читабельным. Более ясный способ гарантировать , что
len
это0
является одним из следующих двух способов.или
источник
NaN
... Например+{}
... Лучше всего объединить два:+length||0
>>>
это беззнаковый оператор сдвига вправо ( см. 76 1.5 спецификации JavaScript ), в отличие от>>
, с подписью правильного оператора сдвига.>>>
изменяет результаты сдвига отрицательных чисел, потому что он не сохраняет знаковый бит при сдвиге . Последствия этого можно понять на примере интерпретатора:Итак, что, вероятно, предполагается сделать здесь, это получить длину или 0, если длина не определена или не является целым числом, как в
"cabbage"
примере выше. Я думаю, что в этом случае можно с уверенностью предположить, чтоthis.length
никогда не будет< 0
. Тем не менее, я бы сказал, что этот пример - мерзкий взлом по двум причинам:Поведение
<<<
при использовании отрицательных чисел, побочный эффект, вероятно, не предназначен (или может произойти) в примере выше.Намерение кода не очевидно , поскольку существование этого вопроса подтверждает.
Лучше всего использовать что-то более читабельное, если производительность не является абсолютно критичной:
источник
-1 >>> 0
когда-нибудь случиться случай , и если да, то действительно ли желательно изменить его на 4294967295? Похоже, это приведет к тому, что цикл будет запущен несколько раз, чем необходимо.this.length
этого невозможно узнать. Для любой «нормальной» реализации длина строки никогда не должна быть отрицательной, но тогда можно утверждать, что в «нормальной» среде мы можем предположить существованиеthis.length
свойства, которое всегда возвращает целое число.Две причины:
Результатом >>> является «интеграл»
undefined >>> 0 = 0 (поскольку JS попытается привести LFS к числовому контексту, это также будет работать для "foo" >>> 0 и т. д.)
Помните, что числа в JS имеют внутреннее представление double. Это просто «быстрый» способ ввода здравомыслия в длину.
Тем не менее , -1 >>> 0 (ой, скорее всего, не желаемой длины!)
источник
Пример кода Java ниже хорошо объясняет:
Вывод следующий:
источник