Comments 93
Что насчет кроссбраузерности? Во всех IE корректно работает?
+3
Думаю нет ) Это же ИЕ.
-11
Во всех, только нужно помнить о больших числах.
+5
Побитовые операторы появились задолго до IE, а таблицы неявного приведения типов существуют с «бородатых» лет первой спецификации. (9 Type Conversion)
+3
UFO just landed and posted this here
~~null; // => 0
~~undefined; // => 0
~~0; // => 0
~~{}; // => 0
~~[]; // => 0
~~(1/0); // => 0
~~false; // => 0
~~true; // => 1
~~1.2543; // => 1
~~4.9; // => 4
~~(-2.999); // => -2
+16
UFO just landed and posted this here
Важным достоинством «~~» является другой приоритет, который в ряде случаев экономит усилия по расстановке скобок:
Правда, зато «~~» приходится записывать не по порядку операций (наподобие того,как «(x / 1024)|0» означает «сперва поделить, затем отбросить дробную часть»), а спереди.
(А ещё «~~» ничего не означает в asm.js, но за пределами asm.js это не недостаток.)
( "-3.8"|0 ) === -3; // true
"-3.8"|0 === -3; // -3
~~"-3.8" === -3; // true
Правда, зато «~~» приходится записывать не по порядку операций (наподобие того,
(А ещё «~~» ничего не означает в asm.js, но за пределами asm.js это не недостаток.)
+7
Я про это писал на Хабре ажно три года назад. Тогда не оценили :-)
+2
Дык оттого и не оценили, что Вы сами тогда, находясь под влиянием замеров скорости работы джаваскриптов, принизили значение своего сообщения, высказали «не ведитесь на короткую крутую запись» и проч.
С тех пор скорости работы движков, JavaScript исполняющих, существенно изменились, причём в лучшую сторону, тогда как средняя скорость пробежки по клавиатуре босыми пальцами рук ничуть не переменилася.
Вывод: предпочитать следует такие приёмы, которые экономят труд программиста, даже если вычислительно они представляются несколько малоэффективными.
С тех пор скорости работы движков, JavaScript исполняющих, существенно изменились, причём в лучшую сторону, тогда как средняя скорость пробежки по клавиатуре босыми пальцами рук ничуть не переменилася.
Вывод: предпочитать следует такие приёмы, которые экономят труд программиста, даже если вычислительно они представляются несколько малоэффективными.
0
блин, век живи — век учись…
+12
Я просто оставлю это здесь: Bitwise Operators
+25
UFO just landed and posted this here
Стоит упомянуть про подводные камни с большими числами:
4242334634634634523523 | 0; // => 368574464
3234534534 | 0; // => -1060432762
+34
Только помните:
~~"12345678901" // -539222987
"12345678901"|0 // -539222987
"12345678901"*1 // 12345678901
parseInt("12345678901", 10) // 12345678901
+18
Хорошо, что Вы напомнили про это, но стоило бы ещё и упомянуть, почему это так. А так оно потому что согласно стандарту операнды битового оператора приводятся в 32-х битному знаковому числу, и, как следствие,
Результат является знаковым 32-битовым целым.
+10
Кстати об использовании таких штук, по моему гораздо удобнее это писать перед выражением, то есть
Тогда сразу видно приведение типов.
var a = 0 ^ x
, b = 0 | x
Тогда сразу видно приведение типов.
0
ИМХО, стоит всё-таки знать меру в использовании особенностей таких конструкций в JS. Кстати говоря, я более, чем уверен, что у многих программистов на JS есть проблема с тем, чтобы разобраться в чужом JS-коде, в том числе из-за использования таких конструкций. Если вам нужно сократить объем кода, то в современных реалиях намного проще будет использовать тот же Google Closure Compiler и учитывать, как он работает, нежели писать такой «код» самому. Из моего опыта, понятность кода (даже на JS) намного важнее лишних пары килобайт, которые будут «выжаты» путем такой «оптимизации».
+24
Код пишется для людей, а не для интерпретатора же. Нужно писать его так, чтобы его легко было прочитать. Разве что только код пишется специально для конкурса обфускаторов.
Даже в таком слабо типизированном языке с динамической типизацией как javascript в ваших программах вы всё равно знаете, откуда к вам приходят данные и какого типа. От этого уже можете плясать.
Даже в таком слабо типизированном языке с динамической типизацией как javascript в ваших программах вы всё равно знаете, откуда к вам приходят данные и какого типа. От этого уже можете плясать.
+13
// Но иногда удобнее писать
if( ~str.indexOf('sub') ){
}
// чем
if( str.indexOf('sub') != -1 ){
}
+1
А если вам нужно рядом инвертировать условие, и реализовать логику «нет в подстроке», то как вы будете писать?
0
if (!~str.indexOf('sub')) {
}
не?
вообще, если один раз запомнить, то такое легко читается.
0
Лично меня `!~` пугает. Я всё-таки выражения читаю по большей части слева-направо: «в строке индекс подстроки не равен -1»
+4
Вы правы, я тоже никогда так не писал, а потом стал набирать много кода на jquery и приучился писать так:
согласитесь, тут больше смысла. хотя да, пугает иногда.
if (!~$.inArray(str, arr)) { }
согласитесь, тут больше смысла. хотя да, пугает иногда.
0
Вы используете библиотеку для поиска вхождения одной строки в другую?
Теперь я понимаю кто такой «программист на jquery»
Теперь я понимаю кто такой «программист на jquery»
-5
0
Странный вопрос и выводы.
Я не использую библиотеку для поиска вхождений одной строки в другую. С чего вы взяли? В коде написан поиск строки в массиве. Но если вам интересно, то и так я уже давно не пишу. Просто добавляю к проекту SugarJS и использую стандартный indexOf(). Но раньше, когда моё бывшее начальство краснело от идеи изменения прототипов, мне приходилось для поиска внутри массива использовать jQuery, чтобы это везде работало. (до 9 версии IE её не поддерживал). А поиск строки в строке вроде очень давно во всех браузерах реализован, так что использовал его, ну уж точно не $.inArray(), акститесь.
Я не использую библиотеку для поиска вхождений одной строки в другую. С чего вы взяли? В коде написан поиск строки в массиве. Но если вам интересно, то и так я уже давно не пишу. Просто добавляю к проекту SugarJS и использую стандартный indexOf(). Но раньше, когда моё бывшее начальство краснело от идеи изменения прототипов, мне приходилось для поиска внутри массива использовать jQuery, чтобы это везде работало. (до 9 версии IE её не поддерживал). А поиск строки в строке вроде очень давно во всех браузерах реализован, так что использовал его, ну уж точно не $.inArray(), акститесь.
+2
ясно, я неверно вас понял
да и не знал, что с indexOf для Array у ie была беда
да и не знал, что с indexOf для Array у ie была беда
0
у меня аж руки затряслись когда прочитал что indexOf() до 9 ИЕ не поддерживался. shift+ctrl+F по проекту — 189 вхождений, ПАНИКА!
Работает все в восьмом, напугали блин.
Работает все в восьмом, напугали блин.
0
Что это, Бэрримор?
В смысле зачем? Расширить прототип я и сам могу.
А indexOf работает начиная с IE8, что собственно и требуется.
В смысле зачем? Расширить прототип я и сам могу.
А indexOf работает начиная с IE8, что собственно и требуется.
+2
Удобнее, но не читабельнее. Я вообще предпочту написать так:
if( str.contains('sub') ){
}
+6
С 0 выйдет конфуз у вас
-4
Согласен, но на участках с очень большим количеством итераций, лучше перестраховаться.
+ Это не кроссбраузерно, а ломать голову, расширен ли прототип на проекте не охота.
+ Это не кроссбраузерно, а ломать голову, расширен ли прототип на проекте не охота.
0
+ Это не кроссбраузерно, а ломать голову, расширен ли прототип на проекте не охота.
Как это не кроссбраузерно? А вы ломаете голову, подключён ли у вас jQuery, объявлена ли функция foo или bar при её вызове? Метод contains точно такой же, как любой другой. Или у вас есть этот метод или нету.
Согласен, но на участках с очень большим количеством итераций, лучше перестраховаться.
Этот аргумент вообще не понял. По-моему нету ничего более очевидного, чем слово
contains
— это самая лучшая перестраховка.-1
Насчёт кросс-браузерности полезна библиотека Underscore.string и запись «_.str.include(str, 'sub')».
0
Chrome 25 — www.rubaxa.org/screenshot/6b15eb6a74e217165b52df651dd2.png
И да, когда я разрабатываю код, который будет работать в неизвестном мне месте, стараюсь писать так, чтобы понял и IE6. + Даже подключенный shim будет на 10 порядково медленней.
И да, когда я разрабатываю код, который будет работать в неизвестном мне месте, стараюсь писать так, чтобы понял и IE6. + Даже подключенный shim будет на 10 порядково медленней.
+1
за
if (~arr.indexOf(val)) { /* ... */ }
на меня косо смотрят, а вот за такое наверное вообще убьют :)+4
Вообще у этого «трюка» есть немного иное назначение, не только для приведения к int, но и замене Math.round — `(x + .5)|0` или Math.floor. С такой же целью это используется в ActionScript.
-1
Пожалуйста, внимательно прочитывайте блогозапись до конца перед сочинением комментариев к ней. Вы пропустили характеристику «удобное средство отбрасывания дробной части».
-1
Простите меня.
+1
Охотно прощаю.
-1
Но прошу заменить, в статье не написано, что `(x + .5)| 0` по скорости быстрей Math.round (если рассматривать синтетический тест).
+1
Да, не написано, Вы правы.
0
А потом кто-то после вас застрянет на этом месте и будет думать: «а что же имел в виду автор?». Данная конструкция заметно ухудшает читабельность кода.
Указанный метод быстрее, но оба округления настолько быстры, что экономить стоит только в тех случаех когда у вас миллионы округлений в секунду.
P.S.
Указанный метод быстрее, но оба округления настолько быстры, что экономить стоит только в тех случаех когда у вас миллионы округлений в секунду.
P.S.
+4
Спасибо за тесты.
В Файерфоксе они показывают одинаковые значения скорости того и другого округления.
В Файерфоксе они показывают одинаковые значения скорости того и другого округления.
0
Друзья, я просто пытаюсь показать, что данная практика имеет свои предпосылки, а не только из-за короткой записи. Писав маленькое приложение под iPhone где приходилось работать с пикселями (canvas) такие микро оптимизации помогали. Это всё было 3 года назад, надеюсь сейчас ситуация изменилась.
+1
тест этот совсем не замеряет скорости округления, потому что loop invariant code motion выносит инвариант цикла за цикл.
замеряется по сути дела скорость кручения пустого цикла.
почитайте: mrale.ph/blog/2012/12/15/microbenchmarks-fairy-tale.html
замеряется по сути дела скорость кручения пустого цикла.
почитайте: mrale.ph/blog/2012/12/15/microbenchmarks-fairy-tale.html
+3
Конструкция Math.floor() гораздо очевидней, чем |0. Это уже повод не использовать второй путь, даже без учета сообщений выше про проблемы с большими числами. И вообще, не зря битовые операции по умолчанию запрещены в jslint и jshint
+7
До известной степени это впечатление справедливо.
Я замечу, однако, что программист до известной степени способен воздействовать на собственное впечатлениеот «|0» при помощи мнемотехники, то есть мысленно связать этот оператор с некоторым запоминающимся символом с той целью, чтобы надёжнейше обеспечить себе его очевидность, причём надолго.
На ум приходит, например, идея рассматривать вертикальную черту как острый и безжалостный нож гильотины, отсекающий последующую цифру — что метафорически символизирует отсечение всей дробной части числа. Такой символ очень неплохо передаёт всю суть происходящего — не хуже, чем английское слово «floor» передаёт суть названного им метода.
Я замечу, однако, что программист до известной степени способен воздействовать на собственное впечатление
На ум приходит, например, идея рассматривать вертикальную черту как острый и безжалостный нож гильотины, отсекающий последующую цифру — что метафорически символизирует отсечение всей дробной части числа. Такой символ очень неплохо передаёт всю суть происходящего — не хуже, чем английское слово «floor» передаёт суть названного им метода.
0
UFO just landed and posted this here
Вдругорядь
куда-куда?)
+1
Эта конструкция делает следующее: объект.toString().перевод_в_integer, если_это_число_иначе_в_ноль. Сразу становится понятно почему массив из двух элементов преобразуется в ноль. Потому что [1,2].toString() это «1,2».
+1
Бесконечность?
Может кто-нибудь объяснить зачем она нужна и как ее использовать? Чес слово не могу придумать.
Может кто-нибудь объяснить зачем она нужна и как ее использовать? Чес слово не могу придумать.
0
> не округляет, а именно отбрасывает дробную часть
Раньше это называлось округлением вниз по модулю. Да, есть разные способы окрулять.
Раньше это называлось округлением вниз по модулю. Да, есть разные способы окрулять.
+1
UFO just landed and posted this here
(вдруг кто не знал)
Из подобных вещей я чаще всего использую || для обработки undefined и null / false значений:
Аналогично для строк:
Особенно это актуально когда конструируем data для ajax запроса, т.к. там если в поле передадим «undefined», то на сервер это в null не переведёт и будет ругаться (по крайней мере для MVC2 это так).
Из подобных вещей я чаще всего использую || для обработки undefined и null / false значений:
function GetRow (index)
{
return $("selector").eq (index || 0);
}
Аналогично для строк:
$("selector").val (n || "")
Особенно это актуально когда конструируем data для ajax запроса, т.к. там если в поле передадим «undefined», то на сервер это в null не переведёт и будет ругаться (по крайней мере для MVC2 это так).
0
оператор || возвращает первый положительный вариант или последний из условия, если все остальные дают false
То есть вы можете писать и такие конструкции
То есть вы можете писать и такие конструкции
> null || 0 // => 0
> null || 0 || 1 // =>1
> null || 1 || 0 // => 1
> null || 0 || 0 // => 0
> null || 0 || null // => null
> null || 0 || null || undefined // => undefined
> null || 0 || '' || [] || undefined // => []
> null || 0 || '' || false || undefined // => undefined
> null || 0 || '' || false || undefined || 1 // => 1
> null || 0 || '' || false || 1 || undefined // => 1
+2
Хоть бы разок упомянули об операторе побитовое «или»:
developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Bitwise_Operators#.7C_(Bitwise_OR)
А не про «символьную конструкцию «|0» в JavaScript»
developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Bitwise_Operators#.7C_(Bitwise_OR)
А не про «символьную конструкцию «|0» в JavaScript»
+3
Я это нарочно.
Я опасался вот чего: если думатьпро «|0» в терминах «побитовое ИЛИ с нулём», то этот оператор воспринимается в качестве NOP-подобной «мусорной команды», потому что из курса двоичной арифметики каждому известно, что побитовое ИЛИ с нулём не меняет значение другого (ненулевого) операнда.
Роль этого оператора в джаваскрипте определяется правилами предварительного преобразования операнда к целому числу, а не смыслом самóй операции. Но мне не хотелось упоминать и об этом: смысл статьи сильнее дойдёт до читателя, если читатель сам проделает часть пути к его разгадке.
Я опасался вот чего: если думать
Роль этого оператора в джаваскрипте определяется правилами предварительного преобразования операнда к целому числу, а не смыслом самóй операции. Но мне не хотелось упоминать и об этом: смысл статьи сильнее дойдёт до читателя, если читатель сам проделает часть пути к его разгадке.
-1
На jsPerf, оказывается, уже есть тест в тему: jsperf.com/bitwise-or-vs-math-floor
0
Вы должны учитывать то что в этом тесте не учитывается оверхед на вызов функции Math.round
Вот подобный, но учитывающий вызовы: jsperf.com/math-round-vs-x-0-5-0/2
Вот подобный, но учитывающий вызовы: jsperf.com/math-round-vs-x-0-5-0/2
+1
Просто так
Python 2.7.3 |EPD_free 7.3-2 (32-bit)| (default, Apr 12 2012, 14:30:37) [MSC v.1500 32 bit (Intel)] on win32
Type «copyright», «credits» or «license()» for more information.
>>> 3|0
3
>>> 3.8|0
Traceback (most recent call last):
File "<pyshell#1>", line 1, in 3.8|0
TypeError: unsupported operand type(s) for |: 'float' and 'int'
>>> -3|0
-3
>>> '3'|0
Traceback (most recent call last):
File "<pyshell#3>", line 1, in '3'|0
TypeError: unsupported operand type(s) for |: 'str' and 'int'
>>>
Python 2.7.3 |EPD_free 7.3-2 (32-bit)| (default, Apr 12 2012, 14:30:37) [MSC v.1500 32 bit (Intel)] on win32
Type «copyright», «credits» or «license()» for more information.
>>> 3|0
3
>>> 3.8|0
Traceback (most recent call last):
File "<pyshell#1>", line 1, in 3.8|0
TypeError: unsupported operand type(s) for |: 'float' and 'int'
>>> -3|0
-3
>>> '3'|0
Traceback (most recent call last):
File "<pyshell#3>", line 1, in '3'|0
TypeError: unsupported operand type(s) for |: 'str' and 'int'
>>>
-1
ааа, мои глаза…
После этого вы говорите, что код Perl вам трудно понять?
:)
После этого вы говорите, что код Perl вам трудно понять?
:)
0
Вроде уж совсем основы.
n|0 или n>>0 выполнят преобразование ToInt32, n>>>0 — ToUInt32, для отбрасывания дробной части использовать аккуратно — с большими числами будут проблемы — (Math.pow(2,31)|0)===-2147483648.
Т.к. внутренние операции преобразования типов наружу не вынесены, приходится крутиться
n|0 или n>>0 выполнят преобразование ToInt32, n>>>0 — ToUInt32, для отбрасывания дробной части использовать аккуратно — с большими числами будут проблемы — (Math.pow(2,31)|0)===-2147483648.
Т.к. внутренние операции преобразования типов наружу не вынесены, приходится крутиться
function ToInt32(val){
return val>>0}
function ToUInt32(val){
return val>>>0}
function ToUInt16(val){
return (val>>>0)%65536}
var ToInteger=Number.toInt||Number.toInteger||function(val){
return val=+val,val!==val?0:val!==0&&val!==Infinity&&val!==-Infinity?(val>0||-1)*Math.floor(Math.abs(val)):val}
+1
да чего уж там
//никогда не делайте так со своим кодом
Math.floor = function (x){
return x|0;
}
//никогда не делайте так со своим кодом
-1
Кроме Math.floor есть ещё round и ceil, также существует parseInt, и все они работают в несколько раз быстрее у меня сейчас в хроме.
-1
Sign up to leave a comment.
Вертикальная черта, затем ноль