предисловие
пожалуйста, скажите мне
JavaScriptтип данных в ?
Предполагается, что в предварительном интервью всем задавали этот вопрос.
отвечать:JavascriptТипы данных включают примитивные типы и ссылочные типы. где примитивные типы включаютnull,undefined,boolean,string,symbol,bigInt,number. ссылочный тип относится кObject.
Да, я ответил так же, но это обычно первый вопрос, и из этого вопроса может быть поднято много-много вопросов, таких как
-
Nullа такжеUndefinedКакая разница? На что следует обратить внимание в пустых суждениях о фронтенде? -
typeof nullЗачемobject? - Зачем
ES6предложитьSymbol? -
BigIntВ чем проблема? - Зачем
0.1 + 0.2 !== 0.3?Как решить эту проблему? - Как определить значение - это массив?
- ...
слабо типизированный язык
потому чтоJavaScriptЭто язык со слабой типизацией или динамический язык. Это означает, что вам не нужно заранее объявлять тип переменной, тип будет автоматически определяться во время работы программы, а это значит, что вы можете использовать одну и ту же переменную для хранения значений разных типов.
var foo = 42; // foo is a Number now
foo = "bar"; // foo is a String now
foo = true; // foo is a Boolean now
Хотя эта функция приносит нам удобство, она также приносит нам много ошибок типов. Представьте, еслиJSГоворят, что это строго типизированный язык, тогда нет преобразования между различными типами, и есть слой разделения или уровень защиты.Будет ли легче поддерживать? - это может бытьTypeScriptПричина рождения.
правильноJavaScriptОсвоение типов данных является самым базовым знанием внешнего интерфейса.
нулевой или неопределенный
определение
undefinedПредставляет неопределенную переменную.nullЗначение представляет нулевой указатель объекта.
Возвращаясь к первоисточнику: В начале
JavaScriptдизайнерBrendan EichНа самом деле он просто определяетnull,nullкак будтоJavaрассматривается как объект. Но потому чтоJavaScriptСуществует два типа данных: примитивные типы данных и ссылочные типы данных.Brendan EichЯ думаю, что значения, которые представляют «нет», лучше не являются объектами.
такJavascriptДизайнnull — это объект, представляющий «ничего», который равен 0 при преобразовании в числовое значение; undefined — это примитивное значение, представляющее «ничего», которое равно NaN при преобразовании в числовое значение.
Number(null)
// 0
5 + null
// 5
Number(undefined)
// NaN
5 + undefined
// NaN
Разница и применение Null и Undefined
null означает "нет объекта", т.е. там не должно быть никакого значения., типичное использование выглядит следующим образом
- В качестве аргумента функции это означает, что аргумент функции не является объектом.
- как конец цепочки прототипов объектов.
Object.getPrototypeOf(Object.prototype)
// null
undefined означает "отсутствующее значение", т.е. здесь должно быть значение, но оно не определено. Типичное использование:
- Когда переменная объявлена, но ей не присвоено значение, она равна
undefined. - При вызове функции не был указан параметр, который должен быть указан, и параметр равен
undefined. - Объект не имеет назначенного свойства, значение свойства равно
undefined. - Когда функция не имеет возвращаемого значения, она возвращается по умолчанию.
undefined.
var i;
i // undefined
function f(x){console.log(x)}
f() // undefined
var o = new Object();
o.p // undefined
var x = f();
x // undefined
На что следует обратить внимание при оценке пустого?
javaScriptПять видов нулевых и ложных значений, соответственно undefined, null, false, "", 0, NAN
Иногда это может легко привести к некоторым проблемам, таким как
let a = 0;
console.log(a || '/'); // 本意是只要 a 为 null 或者 Undefined 的时候,输出 '/',但实际上只要是我们以上的五种之一就输出 '/'
Конечно, мы можем написать
let a = 0;
if (a === null || a === undefined) {
console.log('/');
} else {
console.log(a);
}
всегда не очень элегантен, поэтому спецификация ES предлагает оператор объединения null (??)
Оператор объединения null (??) — это логический оператор, который возвращает правый операнд, когда левый операнд имеет значение null или не определен, в противном случае возвращает левый операнд.
Приведенный выше пример можно записать так:
let a = 0;
console.log(a??'/'); // 0
typeof null — ошибки JS
typeof null // "object"
JavaScriptЗначение в представлено меткой, представляющей тип и фактическое значение данных. первое изданиеJavaScriptЗначение хранится в 32 битах, а тип идентифицируется младшими 1 или 3 битами значения, а тег типа объекта равен 000. следующим образом
- 1: Целое (целое)
- 000: Тип ссылки (объект)
- 010: тип с плавающей запятой двойной точности (двойной)
- 100: строка (строка)
- 110: логическое значение (логическое значение)
Но есть два особых значения:
- undefined, используйте целое число -2^30 (отрицательное 2 в 30-й степени, не в диапазоне целых чисел)
- null, нулевой указатель машинного кода (определение макроса C/C++), младшие три цифры также равны 000
из-заnullПредставляет нулевой указатель (младшие три бита также000 ),因此,nullТег типа000,typeof nullСледовательно, возвращается «объект».
ЭтоJavaScriptОшибка дизайна, но ее нельзя изменить, ведь если вы ее модифицируете, это повлияет на существующий код.
Номер - 0,1 + 0,2! == 0,3
Феномен
существуетJavaScriptБудет явление похожее на следующее
0.1 + 0.2
0.30000000000000004
причина
В процессе работы с числами с плавающей запятой нам необходимо преобразовать десятичное число в двоичное. Правила преобразования десятичного числа в двоичное следующие:
Умножьте число после запятой на 2, возьмите целую часть результата (либо 1, либо 0), затем умножьте дробную часть на 2, затем возьмите целую часть результата... и так далее до дробной части часть 0 или бит Число достаточно, и все в порядке. Затем расположите взятые целые части по порядку
В соответствии с приведенными выше правилами окончательное представление 0,1 выглядит следующим образом:
0.000110011001100110011(0011无限循环)……
Таким образом, потеря точности — это не языковая проблема, а неотъемлемый недостаток хранения чисел с плавающей запятой.
JavaScriptда64Число двойной точности с плавающей запятой хранит всеNumberзначение типа, согласноIEEE754Спецификация, двоичное число 0,1 сохраняет только 52 значащие цифры, то есть
1.100110011001100110011001100110011001100110011001101 * 2^(-4)
Точно так же двоичное число 0,2 равно
1.100110011001100110011001100110011001100110011001101 * 2^(-3)
Таким образом, была потеряна точность при преобразовании между основаниями. Операция выглядит следующим образом
0.00011001100110011001100110011001100110011001100110011010
+0.00110011001100110011001100110011001100110011001100110100
------------------------------------------------------------
=0.01001100110011001100110011001100110011001100110011001110
Таким образом, это приводит к 0,1 + 0,2 !== 0,3 в конечном результате расчета.
Как решить
- Преобразование чисел в целые числа
function add(num1, num2) {
const num1Digits = (num1.toString().split('.')[1] || '').length;
const num2Digits = (num2.toString().split('.')[1] || '').length;
const baseNum = Math.pow(10, Math.max(num1Digits, num2Digits));
return (num1 * baseNum + num2 * baseNum) / baseNum;
}
- библиотека классов
NPMСуществует много поддержки наJavaScriptа такжеNode.jsматематические библиотеки, такие какmath.js,decimal.js,D.jsтак далее
- ES6
ES6существуетNumberК объекту добавлена очень маленькая константа -Number.EPSILON
Number.EPSILON
// 2.220446049250313e-16
Number.EPSILON.toFixed(20)
// "0.00000000000000022204"
Цель введения такой малой суммы — установить диапазон ошибок для вычислений с плавающей запятой, если ошибка может быть меньшеNumber.EPSILON, можно считать результаты достоверными.
function withinErrorMargin (left, right) {
return Math.abs(left - right) < Number.EPSILON
}
withinErrorMargin(0.1+0.2, 0.3)
Будущие решения -TC39 Decimal proposal
в настоящее время вStage 1предложение. упоминается позжеBigIntрасширенныйJSПоложительная граница , превышает задачу 2^53 безопасных целых чисел.DecimalЭто решить десятичную проблему JS -2 ^ 53. Это предложение вводит новые примитивные типы в JS:decimal(суффикс m), объявляет, что число является десятичной операцией.
let zero_point_three = 0.1m + 0.2m;
assert(zero_point_three === 0.3m);
// 提案中的例子
function calculateBill(items, tax) {
let total = 0m;
for (let {price, count} of items) {
total += price * BigDecimal(count);
}
return BigDecimal.round(total * (1m + tax), {maximumFractionDigits: 2, round: "up"});
}
let items = [{price: 1.25m, count: 5}, {price: 5m, count: 1}];
let tax = .0735m;
console.log(calculateBill(items, tax));
Расширение - хранение чисел с плавающей запятой в памяти
Так как же выглядит итоговое число с плавающей запятой в памяти?EEE754Дано определение представления чисел с плавающей запятой
(-1)^S * M * 2^E
Значение каждого символа следующее: S — бит знака, который определяет, является ли он положительным или отрицательным, когда он равен 0, это положительное число, а когда он равен 1, это отрицательное число. M относится к эффективному количеству цифр, больше 1 и меньше 2. E, является битом экспоненты.
Javascript — это 64-битное число двойной точности с плавающей запятой, старший 1 бит — это бит знака S, следующие 11 бит — показатель степени E, а оставшиеся 52 бита — мантиссы M.
доступны с помощьюэтот инструмент визуализацииСм. двоичное представление чисел с плавающей запятой в памяти)
BigInt — преодолевая самые большие ограничения
JavaScriptизNumberТипДвойная точность IEEE 754 64-битная с плавающей запятойТипы.
Максимальное значение в JavaScript равно2^53.
BigIntЧисловые типы произвольной точности вошли в спецификацию stage3.BigIntМожет представлять произвольно большие целые числа. создатьBigInt, нам просто нужно добавить суффикс n к любому целочисленному литералу. Например, напишите 123 как 123n. Этот глобальный BigInt(число) можно использовать для преобразования числа в BigInt, что означает, что BigInt(123) === 123n. Теперь позвольте мне использовать эти два пункта для решения проблемы, о которой мы упоминали ранее:
Символ - я самый красивый мальчик
определение
ES6 представляет новый примитивный тип данныхSymbol, представляющий уникальное значение
let s = Symbol();
typeof s
// "symbol"
Сценарии применения
-
Определите набор констант, чтобы убедиться, что наборы констант не равны. Избавьтесь от волшебных строк
-
Объекты гарантированно имеют разные имена свойств
let mySymbol = Symbol();
// 第一种写法
let a = {};
a[mySymbol] = 'Hello!';
// 第二种写法
let a = {
[mySymbol]: 'Hello!'
};
// 第三种写法
let a = {};
Object.defineProperty(a, mySymbol, { value: 'Hello!' });
// 以上写法都得到同样结果
a[mySymbol] // "Hello!"
-
Vueсерединаprovideа такжеinject.provideа такжеinjectКомпоненту-предку может быть разрешено внедрять зависимость во всех своих потомков, независимо от того, насколько глубока иерархия компонентов, и это всегда будет действовать до тех пор, пока устанавливаются отношения восходящего и нисходящего потоков. Но эта инвазивность также очень сильна, используяSymbolsтак какkeyЭто может избежать вмешательства в код компонента, и не будет проблем, таких как одинаковые имена.
Массив - особое существование в объекте
Подскажите, пожалуйста, как судить о Array?
Зачем задавать этот вопрос?
Поскольку массив — это особое существование, это одна из структур данных, с которыми мы обычно чаще всего соприкасаемся, это особый объект, а его индекс — «обычный объект».keyстоимость. Но у него также есть некоторые методы, которых нет у «обычных объектов», напримерmapЖдать
typeofдаjavascriptВстроенный оператор для определения типа данных, который возвращает строку, представляющую тип данных параметра. но мы не можем пройтиtypeofОпределить, является ли массив. потому чтоtypeofмассивы и простые объекты иnull, оба возвращают "объект"
const a = null;
const b = {};
const c= [];
console.log(typeof(a)); //Object
console.log(typeof(b)); //Object
console.log(typeof(c)); //Object
Как оценить массив
-
Object.prototype.toString.call().
каждое наследствоObjectобъекты имеютtoStringметод, еслиtoStringЕсли метод не переопределен, он вернет[Object type],вtypeтип объекта
const a = ['Hello','Howard'];
const b = {0:'Hello',1:'Howard'};
const c = 'Hello Howard';
Object.prototype.toString.call(a);//"[object Array]"
Object.prototype.toString.call(b);//"[object Object]"
Object.prototype.toString.call(c);//"[object String]"
- Array.isArray()
const a = [];
const b = {};
Array.isArray(a);//true
Array.isArray(b);//false
Array.isArray()даES5Добавлен метод, когда он не существуетArray.isArray(),Можно использоватьObject.prototype.toString.call()выполнить
if (!Array.isArray) {
Array.isArray = function(arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
}
-
instanceof.instanceofОператоры могут использоваться для определения значения конструктора.prototypeСуществует ли объект, на который указывает свойство, в цепочке прототипов другого объекта, подлежащего тестированию. Поскольку конструктор массиваArray, поэтому можно судить по следующему.Примечание. Поскольку массивы также являются объектами, поэтомуa instanceof Objectтакже дляtrue
const a = [];
const b = {};
console.log(a instanceof Array);//true
console.log(a instanceof Object);//true,在数组的原型链上也能找到Object构造函数
console.log(b instanceof Array);//false
-
constructor. Экземпляр, созданный с помощью конструктора, имеетconstructorАтрибуты.
function B() {};
let b = new B();
console.log(b.constructor === B) // true
И массив состоит из вызываемогоArrayреализована функция. так что вы можете
let c = [];
console.log(c.constructor === Array) // true
Примечание: конструктор может быть изменен. Поэтому не рекомендуется судить
let c = [];
c.constructor = Object;
console.log(c.constructor === Array); // false
В заключение
Согласно приведенному выше описанию, метод суждения о личной рекомендации имеет следующие приоритеты.
isArray > Object.prototype.toString.call() > instanceof > constructor
Суммировать
Эта статья направлена наJavaScriptОбсуждаются и анализируются некоторые распространенные проблемы с типами данных. Я надеюсь, что это может быть полезно для всех на собеседованиях или работе в обычное время. Кроме того, вещи, которые могут быть не упомянуты, например, преобразование типов, имеют возможность обсудить еще раз.
Наконец, приглашаю всех обратить внимание на мою официальную учетную запись - интерфейсный продуктовый магазин, обсудить технические вопросы~
Ссылаться на
- Разница между неопределенным и нулем
- История «типа null»
- 0,1 + 0.2 не равен 0,3? Почему у JavaScript есть такая «садовая» операция?
- Глубокое понимание JavaScript в потере точности
- Знаменитый вопрос JavaScript для интервью: 0,1 + 0,2 !== 0,3, скоро уйдет в прошлое
- BigInt: целые числа произвольной точности в JavaScript
- Начало работы с ECMAScript 6
- В JavaScript, как определить, является ли массив массивом?