Почему 2+ 40 равны 42?

Я был сбит с толку, когда коллега показал мне эту строку оповещения для JavaScript 42.

alert(2+ 40);

Ответ 1

Этот символ "OGHAM SPACE MARK" , который является символом пробела. Таким образом, код эквивалентен alert(2+ 40).

Я также хотел бы знать, есть ли больше персонажей, которые ведут себя так.

Любой символ Юникода в классе Zs является символом пробела в JavaScript, но, похоже, что многие.

Однако JavaScript также позволяет использовать символы Unicode в идентификаторах, что позволяет использовать интересные имена переменных, например ಠ_ಠ.

Ответ 2

Прочитав другие ответы, я написал простой script, чтобы найти все символы Unicode в диапазоне U + 0000-U + FFFF, которые ведут себя как белые пробелы. Как кажется, в зависимости от браузера есть 26 или 27, с разногласиями относительно U + 0085 и U + FFFE.

Обратите внимание, что большинство этих символов просто выглядят как обычное пустое пространство.

function isSpace(ch)
{
    try
    {
        return Function('return 2 +' + ch + ' 2')() === 4;
    }
    catch(e)
    {
        return false;
    }
}

for (var i = 0; i <= 0xffff; ++i)
{
    var ch = String.fromCharCode(i);
    if (isSpace(ch))
    {
        document.body.appendChild(document.createElement('DIV')).textContent = 'U+' + ('000' + i.toString(16).toUpperCase()).slice(-4) + '    "' + ch + '"';
    }
}
div { font-family: monospace; }

Ответ 3

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

 
-

Верх - это то, что вы используете, нижняя часть - знак минуса. Вы, кажется, уже знаете это, поэтому теперь давайте посмотрим, почему Javascript делает это.

Символ, который вы используете, на самом деле является ogham space mark, который является символом пробела, поэтому он в основном интерпретируется как то же, что и space, что означает, что ваше утверждение выглядит как alert(2+ 40) для Javascript.

В Javascript есть другие символы, подобные этому. Вы можете увидеть полный список здесь, в Википедии.


Что-то интересное, которое я заметил об этом персонаже, - это то, как Google Chrome (и возможные другие браузеры) интерпретирует его в верхней строке страницы.

enter image description here

Это блок с 1680 внутри него. Это фактически номер юникода для метки ogham space. Кажется, это только моя машина делает это, но это странно.


Я решил попробовать это на других языках, чтобы узнать, что происходит, и это те результаты, которые я получил.


Языки, в которых он не работает:

Python 2 и 3

>> 2+ 40
  File "<stdin>", line 1
    2+ 40
        ^
SyntaxError: invalid character in identifier

Ruby

>> 2+ 40
NameError: undefined local variable or method ` 40' for main:Object
    from (irb):1
    from /home/michaelpri/.rbenv/versions/2.2.2/bin/irb:11:in `<main>'

Java (внутри метода main)

>> System.out.println(2+ 40);
Main.java:3: error: illegal character: \5760
            System.out.println(2+?40);
                                 ^
Main.java:3: error: ';' expected
            System.out.println(2+?40);
                                  ^
Main.java:3: error: illegal start of expression
            System.out.println(2+?40);
                                    ^
3 errors

PHP

>> 2+ 40;
Use of undefined constant  40 - assumed ' 40' :1

С

>> 2+ 40
main.c:1:1: error: expected identifier or '(' before numeric constant
 2+ 40
 ^
main.c:1:1: error: stray '\341' in program
main.c:1:1: error: stray '\232' in program
main.c:1:1: error: stray '\200' in program

exit status 1

Go

>> 2+ 40
can't load package: package .: 
main.go:1:1: expected 'package', found 'INT' 2
main.go:1:3: illegal character U+1680

exit status 1

Perl 5

>> perl -e'2+ 40'                                                                                                                                   
Unrecognized character \xE1; marked by <-- HERE after 2+<-- HERE near column 3 at -e line 1.

Языки, на которых он работает:

Схема

>> (+ 2  40)
=> 42

С# (внутри метода Main())

Console.WriteLine(2+ 40);

Output: 42

Perl 6

>> ./perl6 -e'say 2+ 40' 
42

Ответ 4

Я предполагаю, что он должен что-то сделать с тем, что по какой-то странной причине он классифицируется как пробел:

$ unicode  
U+1680 OGHAM SPACE MARK
UTF-8: e1 9a 80  UTF-16BE: 1680  Decimal: &#5760;
  ( )
Uppercase: U+1680
Category: Zs (Separator, Space)
Bidi: WS (Whitespace)

Ответ 5

Я также хотел бы знать, есть ли больше персонажей, которые ведут себя так.

Кажется, я помню, как некоторое время читал кусочек о том, чтобы озорно заменить полуколоны (U + 003B) в чей-то код с U + 037E, который является греческим вопросительным знаком.

Оба они выглядят одинаково (в той мере, в какой я считаю, что сами греки используют U + 003B), но в этой статье говорится, что другой не будет работать.

Дополнительная информация об этом из Википедии находится здесь: https://en.wikipedia.org/wiki/Question_mark#Greek_question_mark

И (закрытый) вопрос об использовании этого как шалости от самой SO. Не там, где я изначально читал его AFAIR, хотя: JavaScript Prank/Joke