Странные вещи в JavaScript

и почему

Банан JavaScript

Это один из самых известных примеров, который просто показывает кому-то, насколько странным может быть JavaScript.

Итак, если вы запустите следующий код

console.log(('b' + 'a' + + 'a' + 'a').toLowerCase());

Этот код даст вам результат «банан»

Почему

Ответ прост: Принуждение типа.

Приведение типов - это процесс преобразования значения из одного типа в другой (например, из строки в число, из объекта в логическое и т. Д.). Любой тип, будь то примитив или объект, является допустимым объектом для приведения типа.

Как

В JavaScript мы можем использовать оператор + как унарный оператор для преобразования строки в число. Итак, давайте сделаем утверждение более ясным, разделив элементы выражения.

('b') + ('a') + (+ 'a') + ('a')

Теперь первый термин оценивается как «b».

Второй член оценивается просто как «а»

Третий член (+ "а")

В этом случае оператор '+' используется как унарный оператор, который пытается преобразовать 'a' в число, и, очевидно, 'a' не является числом, поэтому этот термин оценивается как "NaN", что означает "Not a number". ».

а четвертый член снова оценивается как «а»

Итак, теперь у нас есть:

'b' + 'a' + NaN + 'a'

Здесь, как мы видим, NaN не относится к строке типа, как другие термины, но в JavaScript из-за неявного преобразования типа NaN преобразуется в строку «NaN», поэтому мы имеем

console.log( 'b' + 'a' + 'NaN' + 'a' )

если мы console.log это выражение, мы получим «baNaNa» в качестве вывода, и вот где функция .toLowerCase() начинает играть и преобразует строку из «baNaNa» в просто «банан».

Не число - это число.

Термин NaN сам по себе странен и может сбить с толку многих, пытающихся начать с Js.

если вы прямо сейчас зайдете в консоль и проверите тип NaN

console.log( typeof NaN )

он выдаст вам «число».

NaN используется для представления значения недопустимой операции, но для его хранения используется тип данных Number, даже если это не число.

Не только это, но он не ведет себя как любой другой номер

console.log( NaN === NaN )

Это выражение всегда будет давать ложное. Это сделано намеренно и не является ошибкой.

правильный способ проверить, является ли переменная NaN, - использовать функцию .isNaN()

Почему

Это в основном для целей проектирования, и этот стандарт был установлен IEEE. согласно стандарту представление NaN не может быть истинным по сравнению с самим собой, для более подробной информации обратитесь к этому ответу на переполнение стека.

Вещи, которые бесполезны, но все равно разрешены

Вы можете определить undefined и NaN

undefined = 'defined' // 'defined'
NaN = 1234455 // 1234455
undefined = NaN

но сохранят ли они то значение, которое вы им присвоили?

точно нет

это бесполезно

но он все еще существует

Почему

Как бы странно это ни было, хотя undefined и NaN имеют особое значение, они не являются частью набора зарезервированных слов в JavaScript, поэтому он не будет содержать значение, которое вы ему даете, но вы все равно можете присвоить ему значение.

Стрелочные функции похожи на обычные, не так ли?

нет, это не так.

Зачем

скажем, мы объявляем объект с именем obj

const obj = {
    print1: function(){
        console.log(this);
    },
    print2: () => {
        console.log(this);
    }
}

теперь этот объект имеет 2 функции печати, которые печатают ссылку this, которая используется для ссылки на сам объект, но

obj.print1() // prints the obj object as expected

и

obj.print2() // prints the window object

Почему снова

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

Другой почему

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

Итак, мы знаем, что obj.print2() правильно печатает глобальный объект окна вместо obj, но что, если мы хотим, чтобы ключевое слово this в этой функции ссылалось на obj или на действительно любой объект, который вы хотите ...

Метод 1. Жесткий переплет

obj.print2.bind(obj1)
obj.print2() /* this will now print obj object and not the global object */

Метод 2. Явная привязка

obj.print2.call(obj1) // this will print obj object as well

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

Заключение

Не заменяйте все обычные функции стрелочными функциями только потому, что они новые и выглядят круче.

Сразу вызываемые функции

(function(){console.log('i hate')})();
(()=>{console.log('this')})();
(async()=>{console.log('but its so convenient')})();

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

делает

(()=>console.log('this is odd'))()

это то же самое, что и делать

const foo = (()=>console.log('this is odd'));
foo();

Предупреждение

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

В JavaScript не всегда нужны точки с запятой

но здесь нужно правильно использовать

пример:

console.log('this')
console.log('will')
console.log('run')
console.log('perfectly')

но

console.log('this')
console.log('will')
console.log('throw an')
( ()=>console.log('error') )()

какая ошибка, эта ошибка VM168:2 Uncaught TypeError: console.log(…) is not a function

это происходит потому, что мы видим приведенный выше код как 4 оператора

но вот как это запускает javascript:

console.log('this')
console.log('will')
console.log('throw an')( ()=>console.log('error') )()

И вот почему нет смысла кричать на ваш старый компилятор cpp, чтобы просто добавить точку с запятой, потому что, очевидно, он знает, где это, ну, в отличие от вашего компилятора cpp, javascript может вроде как это сделать, но он должен понимать, где заканчивается ваш оператор но в приведенном выше случае мы используем () после console.log (…), а javascript не «просто добавляет точку с запятой», как это понималось ранее.

и чтобы исправить это, вам нужно будет использовать;

console.log('this')
console.log('will')
console.log('run'); ( ()=>console.log('perfectly') )()

и this will run perfectly, это один из немногих случаев, когда JavaScript требует, чтобы вы указали ему, где заканчивается ваш оператор.

Заключение

просто используйте точки с запятой

(0.1 + 0.2) !== 0.3

Да, в JavaScript это вернет истину.

но это проблема не только JavaScript, это проблема самой информатики и затрагивает многие языки программирования, которые используют числа с плавающей запятой, но, в отличие от большинства языков, JavaScript только использует значения с плавающей запятой.

Машинная точность

Поскольку JavaScript пытается оценить приведенное выше выражение, он преобразует значения в их двоичные эквиваленты, и 0,1 на самом деле не 0,1, а скорее его двоичный эквивалент, который похож, но не является точным равным….

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

Вывод

JavaScript странный, но он того стоит, по крайней мере, для большинства проектов.