Приближается Новый год, наступает сезон смены работы, и я начинаю разбирать вопросы для собеседования.
Каковы основные типы?
Существует семь основных типов
nullundefinedbooleannumberstring-
symbol(более новый стандарт) -
BigInt(новый стандарт)
NaNтакже принадлежатnumberтип иNaNне равный себе
Каковы характеристики базового типа?
- Значения примитивных типов хранятся в
栈内存Простой сегмент данных - Базовый тип
不可变的- То есть его нельзя изменить принудительно:
Array.prototype.sort.call('abc');(сообщит об ошибке)
- То есть его нельзя изменить принудительно:
- нет базового типа
__proto__нет属性 - Базовый тип может быть передан
基本包装类型Доступ к свойствам/методам// 通过包装类型访问基础类型特性 let str = 'abc'; console.log(str.length) // 当你调用 `str.length` 时,实际过程是这样的: // -> 创建String类型的一个实例 // -> 在实例上调用指定的方法 // -> 销毁这个实例 let _str = new String(str); let len = _str.length; _str = null;
Как определить базовый тип?
- Обнаружение базовых типов может быть выполнено с помощью
typeof,ноtypeof null === 'object'-
nullявляется базовым типом, а не объектом - Из-за исторического наследия нуля (первые три цифры 000) используйте
typeofОбнаружение нуля вызовет ошибку
// 借鉴 Vue 源码的 object 检测方法 function isObject (obj: any): Boolean { return obj !== null && typeof obj === 'object' } -
- пройти через
Object.prototype.toString.call(Универсальный метод)- обнаружить
[[class]] - Без переопределения метода toString любой объект, вызывающий собственный метод toString объекта, вернет
[object type]
// 借鉴 Vue 源码的检测方法 let _toString = Object.prototype.toString; function toRawType (value: any): String { // 获取 从第九个到倒数第二个 字符 // 比如 [object String] 获取 String return _toString.call(value).slice(8, -1) } - обнаружить
Как преобразуются базовые типы?
- При преобразовании базового типа он сначала вызовет
valueOf, а затем позвонитеtoString. (Оба метода могут быть переопределены) - Среди четырех арифметических операций, кроме
+Все остальные операции рассчитываются как числа, если+операция, если не все литералыобеnumber(все числа являются сложением чисел), то оно будет преобразовано в строку (toString) для сращивания
Почему 0,1 + 0,2 не равно 0,3?
следитьIEEE 754 双精度版本(64位)У стандартных языков есть проблемы. Компьютеры не распознают десятичное число, JS преобразует десятичное число в соответствующий двоичный (двоичный код:0а также1).
Итак, как использовать0а также1Представлять0.1а также0.2Шерстяная ткань?
console.log(0.1.toString(2));
// -> 0.0001100110011001100110011001100110011001100110011001101
console.log(0.2.toString(2));
// -> 0.001100110011001100110011001100110011001100110011001101
Кажется, это нормально. Почему есть ошибка?
Не забывайте: интервал точности JS примерно плюс-минус.2^53, сверх лимита будет усечено. Так что 0,1, которое вы видите, на самом деле не 0,1.
Так как же решить проблему точности JS?
- Текущее основное решение
先乘再除- Например, с точностью до 2 знаков после запятой.
- Умножьте все числа, которые нужно вычислить, на 1000.
- После завершения расчета разделите результат на 1000.
- Использовать новый базовый тип
BigInt(плохая совместимость)
Каковы «истинные» ценности JS?
В JS есть «истинные» значения, отличные от «ложных».
Значение "false" включает 7
undefinednullfalseNaN''0-0
При неявном преобразовании условного суждения: «ложное» значение будет преобразовано вfalse, "истинное" значение преобразуется вtrue;
А как насчет ссылочных типов?
- За исключением базовых типов, все они являются ссылочными типами.
- Тип ссылки назначается при ее создании
两个空间- кусок в
堆Вкл, хранить данные самого ссылочного типа (конечно объем данных будет относительно большим) - кусок в
栈на, сохранить пару堆Ссылка на данные (адрес памяти в куче хранилища, то есть указатель)
- кусок в
- Ссылочные типы изменяемы: т.е.
let a={}; a.x=1; - Параметр функции передается по значению, будьте осторожны, чтобы не изменить ссылку
Как определить тип ссылки?
- пройти через
Object.prototype.toString.callобнаружить[[class]] - пройти через
instanceofОпределить тип ссылки - пройти через
constructorОпределите тип ссылки (constructorдоступен для записи, используйте с осторожностью)
Каков принцип instanceof?
instanceofВнутренний механизм черезОпределить, можно ли найти соответствующий объект в цепочке прототипов объектаprototype
Таким образом, будет ошибка при проверке iframe, потому чтоwindow.Array.prototype !== window.frames[0].Array.prototype, поэтому нет отношения наследования
// 实现 instanceof
function instanceof(obj, target) {
// 获得对象的原型
obj = obj.__proto__
// 判断对象的类型是否等于类型的原型
while (true) {
// 如果__proto__ === null 说明原型链遍历完毕
if (obj === null) {
return false
}
// 如果存在 obj.__proto__ === target.prototype
// 说明对象是该类型的实例
if (obj === target.prototype) {
return true
}
// 原型链上查找
obj = obj.__proto__
}
}
Что, если вы используете instanceof для определения базового типа?
вернусьfalseпотому что базовый тип не__proto__
let str = '123';
console.log(str instanceof String) // -> false
Но если вы измените статический методSymbol.hasInstanceты можешь судить
class StringType {
static [Symbol.hasInstance](val) {
return typeof val === 'string'
}
}
console.log(str instanceof StringType) // -> true
Давайте поговорим о массивах, не так ли?
Массив — это объект, подобный списку, данные которого также могут быть прерывистыми в памяти.
Массив должен быть линейно распределенной памятью, но метод извлечения и обновления массива JS точно такой же, как и у объекта.
- Массив превращает индекс вколичество, который используется как атрибут.это медленнее, чем реальный массив, но удобнее в использовании.
- Массив по сути является объектом, и его прототип наследуется от
Array.prototype, вверх, а затем наследовать отObject.prototype - Методы массива разработаны так, чтобы быть универсальными для объектов, и объекты также могут вызывать методы массива.
let obj = { '2': 3, '3': 4, 'length': 2, 'splice': Array.prototype.splice, 'push': Array.prototype.push } obj.push(1) obj.push(2) console.log(obj); // Object(4) [empty × 2, 1, 2, splice: ƒ, push: ƒ] - использовать
delete arr[2], не уменьшает длину, а просто удаляет соответствующий атрибут (становится пустым)
Что такое массив классов?
- Подобный массиву не является массивом, через
Array.isArray()вернусьfalse - проход в виде массива
Array.fromможно преобразовать в массив - Атрибуты должны быть индексированными (числовыми) атрибутами
- должно иметь свойство длины
Часто встречающиеся массивы классов
- нить
- Единственный родной массив классов
-
arguments- аргументы полностью доступны
...argsвместо этого, чтобы неопределенный параметр был истинным массивом - аргументы удаляются в стрелочных функциях
- аргументы полностью доступны
- DOM
[] == ![] Каков результат?
PS: спасибо за добавление @shenmo_
Преобразование типов в первую очередьvalueOfОпять такиtoString;
правильно
- из-за
!соотношение приоритетов==высокий, выполнить первым! -
![]ошибаться - провестисуждение о равенстве
-
falseпреобразовать в числа0
осталось
- воплощать в жизнь
[].valueOf()исходное значение или [] - Выполните [].toString(), чтобы получить ''
-
''преобразовать в числа0
так:0 == 0,ответtrue
проверять:
let arr1 = [];
let arr2 = [];
console.log(arr1 == !arr2) // -> true
arr1.toString = () => {
console.log(111)
return 1
}
console.log(arr1 == !arr2)
// -> 111
// -> false
Разница между == и === ?
-
===нет неявного преобразования -
==неявное преобразование-
{a: 1} == "[object Object]"левая будет выполнять.toString()
-
Как сделать условие (a == 1 && a == 2) истинным?
Все еще логика преобразования типов: базовый тип передается черезvalueOfсделать неявное преобразование
ИзменятьvalueOfметод может быть достигнут
let a = {
value: 0,
valueOf: function() {
this.value++;
return this.value;
}
};
console.log(a == 1 && a == 2);
Object.isВ чем разница между === и ?
Object.is(v1, v2)фиксированный===некоторые ошибки(-0和+0, NaN和NaN):
// === 案例
-0 === +0 // -> true
NaN !== NaN // -> false
Object.is(-0, +0) // -> false
Object.is(NaN, NaN) // -> true