Що саме таке Тип примусу в JavaScript?


122

Що саме є тип примусу в Javascript?

Наприклад, про використання ==замість ===?


21
(true == 1) => true/ (true === 1) => false.
VisioN

5
@VisioN ваш коментар зовсім не допомагає, я запитую: "чому" це відбувається?
gespinha

3
Це трапляється тому, що JavaScript був розроблений таким чином. Мій коментар повинен відповісти на ваше головне питання: Що саме таке Тип примусу в JavaScript?
VisioN

6
Через YDJS: "Перетворення значення з одного типу в інший часто називається" типом кастингу ", коли це робиться явно, і" примусом ", коли виконується неявно (вимушене правилами використання значення)". - github.com/getify/You-Dont-Know-JS/blob/master/…
mattLummus

Відповіді:


177

Примусовий тип означає, що коли операнди оператора мають різні типи, один з них буде перетворений у значення "еквівалентне" типу іншого операнда. Наприклад, якщо ви робите:

boolean == integer

булевий операнд буде перетворений на ціле число: falseстає 0, trueстає 1. Потім два значення порівнюються.

Однак якщо ви використовуєте оператор порівняння ===, який не перетворюється, такого перетворення не відбувається. Коли операнди різного типу, цей оператор повертається falseі порівнює значення лише тоді, коли вони одного типу.


1
Як я можу це поставити на практичну ситуацію? Чи не завжди я повинен використовувати, ===коли хочу порівняти, якщо значення дорівнює іншому?
gespinha

1
Це залежить від того, що ти робиш. Дивіться пов'язане питання.
Бармар

8
@GEspinha добре, що це "мистецтво" використання мовної друкованої мови. Деякі люди так думають, і взагалі думають, що невірно набрані мови є бичем світу програмування. Однак якщо ви знаєте, чим займаєтесь, це може зробити коротший, більш гнучкий код.
Crayon Violent

2
@Barmar Чи стосується це також > , <?
Рой Намір

2
Відмінна посилання та пояснення щодо примусу: github.com/getify/You-Dont-Know-JS/blob/master/…
Грег Белл

57

Почнемо з короткої системи введення типу, яка, на мою думку, допоможе вам зрозуміти загальну ідею примусу типу.

Система типів мови визначає правила, які вказують нам, які типи даних існують на цій мові та як їх можна комбінувати за допомогою різних операторів. Наприклад, одне таке правило може вказати, що оператор плюс (+) діє лише на числа. Ці правила існують насамперед для того, щоб не застрелити себе в ногу. Але що відбувається, коли програміст порушує це правило в програмі? Ніщо не заважає програмісту вводити {} + {}або “hello” + 5програму, навіть якщо мова не вважає, що ці вирази мають сенс.

Що в кінцевому підсумку трапляється в цих ситуаціях, залежить від того, наскільки суворо мова стосується правил свого типу.

Система мовних типів часто займає одну з двох позицій щодо того, як ви порушуєте її правила:

  1. Скажи "Ей, це не круто!" і негайно завершити роботу програми.
  2. Скажіть: "Я нічого не можу зробити з {} ... але я можу щось зробити з числами" і спробуйте перетворити {} на число.

Мови з типовими системами, які займають першу позицію щодо її правил, розмовно називають "сильно набраними" мовами. Вони суворо ставляться до того, щоб не дозволяти вам порушувати її правила. Ті, хто використовують другий підхід (наприклад, JavaScript), називаються "слабо набраними" або "слабо набраними" мовами. Звичайно, ви можете порушити правила, але не дивуйтеся, коли він насильно перетворює тип даних, описаний у вашій програмі, щоб відповідати її правилам. Така поведінка відома як… (барабанний рулон)… тип примусу .

Тепер давайте розглянемо кілька прикладів у JavaScript. Спочатку почнемо з виразу, який не призводить до примусу.

5 + 5

Використання оператора + з двома номерами, що цілком дійсно. Програма вважатиме +, що означає "додати", і радісно додасть два числа. Перетворення не потрібно.

А як же ...

[] + 5

Ой-ой. У JavaScript +може означати додавання двох чисел або об'єднання двох рядків. У цьому випадку у нас немає ні двох чисел, ні двох рядків. У нас є лише одне число та об’єкт. Згідно з типовими правилами JavaScript, це не має логічного сенсу. Оскільки пробачити про те, що ти порушуєш її правила, замість того, щоб збій, він намагається все-таки зрозуміти це. Отже, що робить JavaScript? Ну, він знає, як об'єднати рядки, тому він перетворює і [], і 5 в рядки, а результат - значення рядка "5".

В чому справа з операторами порівняння ==і ===? Чому існують два оператори порівняння?

==не захищений від поведінки типу конверсії типу JavaScript. Такі вирази, як, наприклад 5 == “5”, оцінюватимуться як істинні, оскільки JavaScript намагатиметься перетворити один з них так, щоб він порівнював однотипні дані.

У багатьох випадках це не бажано, оскільки ви, мабуть, хочете дізнатися, чи є деякі дані, з якими ви порівнюєте, іншого типу, щоб ви могли вирішити, що з цим робити. Тут використовується ===оператор. При використанні ===перетворення типів не відбудеться. Тому вираз 5 === “5”буде оцінено на хибне.


4
дякую за приємне пояснення, особливо за "Система типів мов часто займає одну з двох позицій"
Humoyun Ahmad

1
Це має бути прийнятою відповіддю, оскільки це показує примус автоматичного типу у кількох гранях, а не лише приклад порівняння ==. Ця відповідь робить набагато кращу загальну роботу щодо відповіді на питання та усунення всієї неоднозначності. Дякуємо, що знайшли час, щоб його написати.
чад

6

У Python, якщо ви спробуєте додати, скажімо, рядки та цілі числа, ви отримаєте помилку:

>>> "hi" + 10
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: cannot concatenate 'str' and 'int' objects

Однак у JavaScript ви цього не зробите. 10Перетвориться в рядок:

> "hi" + 10
"hi10"

"Введіть примус" - це просто химерна помилка для сказаного. Насправді жодна мова не має "типів" у значенні Java чи C або інших мов із системами статичного типу. Як мови трактують взаємодію між різними нестатично набраними значеннями - це питання вибору та домовленості.


1
Я думаю, що у прикладі, який ви взяли, є певна проблема. Те, що ви запропонували як приклад для JS, працює бездоганно з Java та C #. Отже, згідно з цією відповіддю, якщо зробити висновок, що Java та C # підтримують примус, який не буде цілком вірним ...
Ромео Сьєрра

3

дозвольте мені пояснити примус типу на наступному прикладі

Тип примусу означає, що Javascript автоматично (на ходу) перетворює змінну з одного типу даних в інший

Наприклад: 123 + "4"зазвичай виникає помилка, але в Javascript через примус типу, це призводить 1234до рядка

if(23 == "23"){
    console.log(" this line is inside the loop and is executed ");
}

У наведеному вище коді через примусу типу - JavaScript вважає 23(число) та "23"(рядок) те саме. це робить умову істинною та друкує console.log

В іншому випадку

if(23 === "23"){
   console.log(" this line is inside the loop and is NOT executed");
}

У ===випадку, якщо Javascript не робить Type Coercion, а оскільки 23є числом і "23"є String, а ===ці два типи даних є різними, що призводить до хибного стану. Він не друкує console.log

Простими словами

У цьому випадку =це оператор присвоєння - який присвоює такі значення, як var a = 3;і т.д.

(нижче для порівняння оператори)

У цьому випадку ==Javascript перетворює / примушує тип даних до іншого, а потім порівнює його.

У цьому випадку === Javascript не перетворює / не примушує тип даних

Щоб уникнути помилок і в цілях налагодження використовується ===в основному

Будь ласка, повідомте мені точність наведеної інформації.


2

Що таке примус:

Типове примушування в JavaScript відбувається, коли двигун Javascript повинен виконати певну операцію, для якої йому потрібні дані для певного типу. Коли двигун стикається з даними певного типу, які не застосовуються для роботи, він примушує дані до певного типу. Це потрібно, тому що змінні в javascript динамічно набираються, а це означає, що даній змінній може бути призначено значення будь-якого типу.

Приклад:


if(1){
  // 1 gets coerced to true
}


if(4 > '3') {
  // 3 gets coerced into a number
}


44 == "44"  // true, the string 44 gets converted to a nr

Булевий примус:

У примусі JavaScript всі значення перетворюються на trueвинятки, крім наступних значень, до яких примусово false:

console.log(!!"");         // false
console.log(!!0);          // false
console.log(!!null);       // false
console.log(!!undefined);  // false
console.log(!!NaN);        // false
console.log(!!false);      // false

Також зауважте, що у наведеному вище прикладі, що подвійний! використовується оператор. The! оператор позначення примушує значення в булеве значення з протилежним значенням. Ми можемо використовувати цей оператор двічі для перетворення будь-якого значення в булеве значення.


1

a == bозначає, що JavaScript буде оцінюватися aна bоснові того, чи можна оцінити значення однаково. Наприклад, false == 0буде оцінено вірно, оскільки 0 також є значенням булевої помилки. Однак false === 0оцінюватиметься помилковим, оскільки суворо порівнюючи, 0 не є таким самим фізичним значенням, як хибне. Інший приклад - false == ''це в основному слабке порівняння порівняно з суворим порівнянням, тому що javascript - це дуже типова мова. Тобто javascript спробує перетворити змінну на основі контексту коду, і це призведе до того, щоб зробити речі рівними, якщо їх не суворо порівнювати. php також має таку поведінку.


0 is not the same physical value as false. ІМО фізично falseсаме 0в пам’яті. Я скоріше скажу, що вони різняться за типом, оскільки falseбулева, тоді 0як ціла.
VisioN

1

Примус типу - це процес перетворення значення з одного типу в інший (наприклад, рядок у число, об'єкт булевим тощо). Будь-який тип, будь то примітивний або об'єкт, є дійсним предметом для примусу типу. Нагадаємо, примітивами є: число, рядок, логічне значення, null, undefined + Symbol (додано в ES6).

Неявне проти явного примусу Тип примусу може бути явним і неявним.

Коли розробник висловлює намір конвертувати між типами, написавши відповідний код, наприклад Number(value) , це називається явним примусом типу (або кастингом типу).

Оскільки JavaScript є слабко типованою мовою, значення також можуть автоматично перетворюватися між різними типами, і це називається примусовим неявним типом. Зазвичай це відбувається , коли ви застосовуєте оператори значень різних типів, як 1 == null, 2/’5', null + new Date()або він може бути викликаний навколишнім контекстом, як і з if (value) {…}, де значенням приводяться до булева.

Один оператор, який не викликає примусовий неявний тип, - ===це називається оператором суворої рівності. З ==іншого боку, оператор вільної рівності виконує примушення як порівняння, так і введення при необхідності.

Примусовий примус типу - це подвійний меч: це чудове джерело розчарування та дефектів, а також корисний механізм, який дозволяє нам писати менше коду, не втрачаючи читабельності.

Три типи конверсії Перше правило, яке потрібно знати, є лише три типи перетворень у JavaScript:

  • нанизувати
  • булевим
  • нумерувати

По-друге, логіка перетворення примітивів та об'єктів працює по-різному, але і примітиви, і об'єкти можуть бути перетворені лише трьома способами.

Почнемо спочатку з примітивів.

Перетворення рядків

Для явного перетворення значень у рядок застосуйте функцію String (). Неявний примус ініціюється оператором бінарних +, коли будь-який операнд є рядком:

String(123) // explicit
123 + ''    // implicit

Усі примітивні значення природним чином перетворюються на рядки:

String(123)                   // '123'
String(-12.3)                 // '-12.3'
String(null)                  // 'null'
String(undefined)             // 'undefined'
String(true)                  // 'true'
String(false)                 // 'false'

Перетворення символів є дещо складним, оскільки його можна перетворити лише явно, але не неявно.

String(Symbol('my symbol'))   // 'Symbol(my symbol)'
'' + Symbol('my symbol')      // TypeError is thrown

Булева конверсія

Для явного перетворення значення в булеве значення застосуйте Boolean()функцію. Неявне перетворення відбувається в логічному контексті або викликане логічними операторами ( || && !).

Boolean(2)          // explicit
if (2) { ... }      // implicit due to logical context
!!2                 // implicit due to logical operator
2 || 'hello'        // implicit due to logical operator

Примітка: Логічні оператори, такі як || and &&булева конверсія внутрішньо, але насправді повертають значення оригінальних операндів, навіть якщо вони не булеві.

// returns number 123, instead of returning true
// 'hello' and 123 are still coerced to boolean internally to calculate the expression
let x = 'hello' && 123;   // x === 123

Щойно є лише 2 можливі результати булевого перетворення: істинне чи помилкове, просто простіше запам'ятати список хибних значень.

Boolean('')           // false
Boolean(0)            // false     
Boolean(-0)           // false
Boolean(NaN)          // false
Boolean(null)         // false
Boolean(undefined)    // false
Boolean(false)        // false

Будь-яке значення , яка не входить в список перетвориться в trueтому числі object, function, Array, Date, що визначається користувачем типу, і так далі. Символи - це правдиві значення. Порожній об'єкт і масиви є також істинними значеннями:

Boolean({})             // true
Boolean([])             // true
Boolean(Symbol())       // true
!!Symbol()              // true
Boolean(function() {})  // true

Числове перетворення

Для явного перетворення просто застосуйте Number()функцію так само, як ви робили з Boolean()і String().

Неявне перетворення є складним, оскільки воно спрацьовує в більшості випадків:

  • оператори порівняння (>, <, <=,> =)

  • побітові оператори (| & ^ ~)

  • арифметичні оператори (- + * /%). Зауважте, що двійковий + не запускає числове перетворення, коли будь-який операнд є рядком.

  • унар + оператор

  • оператор вільної рівності == (включаючи! =).

    Зауважте, що == не запускає числове перетворення, коли обидва операнди є рядками.

    Число ('123') // явно + '123' // неявно 123! = '456' // неявно 4> '5' // неявно 5 / null // неявна правда | 0 // неявно

Ось як примітивні значення перетворюються на числа:

Number(null)                   // 0
Number(undefined)              // NaN
Number(true)                   // 1
Number(false)                  // 0
Number(" 12 ")                 // 12
Number("-12.34")               // -12.34
Number("\n")                   // 0
Number(" 12s ")                // NaN
Number(123)                    // 123



0
var str = 'dude';
console.log(typeof str); // "string"
console.log(!str); // false
console.log(typeof !str); // "boolean"

Приклад змінної, яка спочатку оголошується як рядок, примусовий до булевого значення з допомогою! оператор


3
Будь-ласка, уточнюйте свою відповідь. Відповіді лише на код не дуже корисні.
cezar

3
особисто я знаходжу код лише прикладів лаконічних, пояснюючих себе та дуже корисних, я думаю, це питання особистої думки
Містер П

0

Примус типу - це процес перетворення значення з одного типу в інший (наприклад, рядок у число, об'єкт булевим тощо). Будь-який тип, будь то примітивний або об'єкт, є дійсним предметом для примусу типу. Нагадаємо, примітивами є: число, рядок, логічне значення, null, undefined + Symbol (додано в ES6).

Примусовий тип може бути явним і неявним.

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

Оскільки JavaScript є слабко типованою мовою, значення також можуть автоматично перетворюватися між різними типами, і це називається примусовим неявним типом. Зазвичай це відбувається, коли ви застосовуєте операторів до значень різних типів, таких як 1 == null, 2 / '5', null + new Date (), або це може бути викликано оточуючим контекстом, як, наприклад, if (значення) {… }, де значення примусово до булевого.

ось приклад примусового неявного типу:

true + false
12 / "6"
"number" + 15 + 3
15 + 3 + "number"
[1] > null
"foo" + + "bar"
'true' == true
false == 'false'
null == ''
!!"false" == !!"true"
[‘x’] == x
[] + null + 1
[1,2,3] == [1,2,3]
{}+[]+{}+[1]
!+[]+[]+![]
new Date(0) - 0
new Date(0) + 0

читати більше: https://www.freecodecamp.org/news/js-type-coercion-explained-27ba3d9a2839/


-2

Якщо тип даних не дорівнює один одному, примус стається. як 3 == "3" або boolen == ціле число

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.