Недавно я разобрался с высокочастотными вопросами фронтенд-интервью и поделился ими со всеми, чтобы учиться вместе. Если у вас есть какие-либо вопросы, пожалуйста, поправьте меня!
Статьи из серии вопросов для фронтенд-интервью:
【1】HTML-глава "2021" с высокочастотными вопросами для фронтенд-интервью
【2】Сводка вопросов по высокочастотным фронтенд-интервью «2021» CSS статьи
【3】Глава "2021" о JavaScript, посвященная высокочастотным вопросам для фронтенд-интервью (часть 1)
【4】Резюме статьи JavaScript "2021" о часто задаваемых вопросах на собеседовании (часть 2)
【5】Глава Vue "2021" о часто задаваемых вопросах на собеседовании (часть 1)
【6】Глава Vue "2021" о часто задаваемых вопросах на собеседовании (часть 2)
【7】Сводка вопросов по высокочастотным фронтенд-интервью «2021» React (часть 1)
【8】Сводка вопросов по высокочастотным фронтенд-интервью «2021» React (часть 2)
【9】Резюме вопросов высокочастотного внешнего интервью "2021" компьютерной сети
【10】«2021» высокочастотные вопросы о фронтенд-интервью краткое изложение принципов браузера
【11】Сводка вопросов по оптимизации производительности высокочастотных предварительных интервью «2021»
【12】«2021» Рукописный свод кода высокочастотных вопросов на собеседовании перед интерфейсом
【13】Сводные результаты вывода кода высокочастотных вопросов внешнего интервью «2021»
1. Тип данных
1. Какие типы данных есть в JavaScript и чем они отличаются?
JavaScript имеет восемь типов данных, а именно Undefined, Null, Boolean, Number, String, Object, Symbol и BigInt.
Где Symbol и BigInt — новые типы данных в ES6:
- Символ представляет собой уникальный и неизменяемый тип данных после создания, который в основном предназначен для решения проблемы возможных конфликтов глобальных переменных.
- BigInt — это числовой тип данных, который может представлять целые числа в формате произвольной точности. Использование BigInt позволяет безопасно хранить и обрабатывать большие целые числа, даже если число превышает безопасный целочисленный диапазон, который может представлять число.
Эти данные можно разделить на примитивные типы данных и справочные типы данных:
- Стек: примитивные типы данных (неопределенный, нулевой, логический, числовой, строковый)
- Куча: ссылочные типы данных (объекты, массивы и функции)
Разница между двумя типами заключается в том, чтоОтличия в месте хранения:
- Примитивный тип данных представляет собой простой сегмент данных, хранящийся непосредственно в стеке, занимает мало места и имеет фиксированный размер, это часто используемые данные, поэтому они хранятся в стеке;
- Справочный тип данных хранится в куче (heap), которая занимает большое пространство и имеет переменный размер. Если хранить в стеке, это повлияет на производительность программы; ссылочный тип данных хранит в стеке указатель, который указывает на начальный адрес сущности в куче. Когда интерпретатор ищет ссылочное значение, он сначала извлекает его адрес в стеке, а затем получает сущность из кучи после получения адреса.
Понятия кучи и стека существуют в структурах данных и памяти операционной системы, в структурах данных:
- В структуре данных доступ к данным в стеке осуществляется в порядке поступления.
- Куча — это приоритетная очередь, которая сортируется по приоритету, а приоритет можно указать по размеру.
В операционной системе память делится на область стека и область кучи:
- Память области стека автоматически выделяется и освобождается компилятором и хранит значения параметров функций, значения локальных переменных и т.д. Он работает как стек в структуре данных.
- Память кучи обычно выделяется и освобождается разработчиком. Если разработчик ее не освобождает, она может быть освобождена механизмом сборки мусора в конце программы.
2. Какие есть методы определения типа данных
(1) тип
console.log(typeof 2); // number
console.log(typeof true); // boolean
console.log(typeof 'str'); // string
console.log(typeof []); // object
console.log(typeof function(){}); // function
console.log(typeof {}); // object
console.log(typeof undefined); // undefined
console.log(typeof null); // object
Среди них массивы, объекты и null будут оцениваться как объекты, а остальные оценки будут правильными.
(2) экземпляр
instanceof
может правильно определить тип объекта,Его внутренний рабочий механизм должен определить, можно ли найти прототип типа в его цепочке прототипов..
console.log(2 instanceof Number); // false
console.log(true instanceof Boolean); // false
console.log('str' instanceof String); // false
console.log([] instanceof Array); // true
console.log(function(){} instanceof Function); // true
console.log({} instanceof Object); // true
можно увидеть,instanceof
Только правильно определите тип эталонных данных, и не может определить базовый тип данных.instanceof
Операторы можно использовать для проверки наличия конструктора в цепочке прототипов.prototype
Атрибуты.
(3) конструктор
console.log((2).constructor === Number); // true
console.log((true).constructor === Boolean); // true
console.log(('str').constructor === String); // true
console.log(([]).constructor === Array); // true
console.log((function() {}).constructor === Function); // true
console.log(({}).constructor === Object); // true
constructor
Есть две функции, одна для определения типа данных, а другая для передачи экземпляра объекта черезconstrcutor
Объект обращается к своему конструктору. Обратите внимание, что если вы создаете объект для изменения его прототипа,constructor
Его нельзя использовать для определения типа данных:
function Fn(){};
Fn.prototype = new Array();
var f = new Fn();
console.log(f.constructor===Fn); // false
console.log(f.constructor===Array); // true
(4) Object.prototype.toString.call()
Object.prototype.toString.call()
Используйте метод прототипа toString объекта Object, чтобы определить тип данных:
var a = Object.prototype.toString;
console.log(a.call(2));
console.log(a.call(true));
console.log(a.call('str'));
console.log(a.call([]));
console.log(a.call(function(){}));
console.log(a.call({}));
console.log(a.call(undefined));
console.log(a.call(null));
То же самое для обнаружения объекта obj вызывает метод toString, результат obj.toString() отличается от результата Object.prototype.toString.call(obj), почему это?
Это связано с тем, что toString является прототипом метода Object, а Array, function и т. д.Как экземпляр Object, этот тип переопределяет метод toString.. Когда разные типы объектов вызывают метод toString, в соответствии со знанием цепочки прототипов вызывается соответствующий переписанный метод toString (тип функции возвращает строку, содержимое которой является телом функции, тип Array возвращает строку, состоящую из элементов...) , и он не будет вызывать метод прототипа toString для Object (возвращает конкретный тип объекта), поэтому тип объекта нельзя получить с помощью obj.toString(), и только obj можно преобразовать в строковый тип, поэтому когда вы хотите получить конкретный тип объекта, следует вызвать метод toString для прототипа объекта.
3. Какими способами можно судить о массиве
- Судя по Object.prototype.toString.call()
Object.prototype.toString.call(obj).slice(8,-1) === 'Array';
- Суждение по цепочке прототипов
obj.__proto__ === Array.prototype;
- Судя по Array.isArray() в ES6
Array.isArrray(obj);
- Суждение по экземпляру
obj instanceof Array
- через Array.prototype.isPrototypeOf
Array.prototype.isPrototypeOf(obj)
4. Разница между null и undefined
Во-первых, и Undefined, и Null являются базовыми типами данных.Каждый из этих двух базовых типов данных имеет только одно значение — undefined и null.
Значение undefined в том,неопределенный, значение нуляпустой объект. Как правило, когда переменная объявлена, но еще не определена, она возвращает значение undefined, а значение null в основном используется для присвоения значения некоторым переменным, которые могут возвращать объект при инициализации.
undefined не является зарезервированным словом в JavaScript, что означает, что вы можете использовать undefined в качестве имени переменной, но такой подход очень опасен, он повлияет на оценку значения undefined. Есть несколько способов получить безопасное неопределенное значение, например, void 0.
Пустая типизация возвращает "object" при использовании typeof для этих двух типов, что является исторической проблемой. Возвращает true при сравнении двух типов значений с использованием двойного знака равенства и false при использовании трех знаков равенства.
5. Каков результат typeof null и почему?
Результатом typeof null является Object.
В первой версии JavaScript все значения хранились в 32-битных ячейках, каждая ячейка содержала небольшойТег типа (1-3 бита)и реальные данные, для которых в настоящее время сохраняется значение. Метки типов хранятся в младших битах каждой ячейки, и существует пять типов данных:
000: object - 当前存储的数据指向一个对象。
1: int - 当前存储的数据是一个 31 位的有符号整数。
010: double - 当前存储的数据指向一个双精度的浮点数。
100: string - 当前存储的数据指向一个字符串。
110: boolean - 当前存储的数据是布尔值。
Если младший бит равен 1, длина флага метки типа составляет только один бит; если младший бит равен 0, длина флага метки типа составляет три бита, что обеспечивает дополнительные два бита для хранения других четырех типов данных.
Существует два специальных типа данных:
- Значение undefined равно (-2)30 (число вне диапазона целых чисел);
- Значение null — это указатель NULL машинного кода (значение нулевого указателя — все 0)
Это означает, что метка типа null также равна 000, что совпадает с меткой типа Object, поэтому он будет оцениваться как Object.
6. Принцип реализации и реализация оператора instanceof
Оператор instanceof используется для определения того, появляется ли свойство прототипа конструктора где-либо в цепочке прототипов объекта.
function myInstanceof(left, right) {
// 获取对象的原型
let proto = Object.getPrototypeOf(left)
// 获取构造函数的 prototype 对象
let prototype = right.prototype;
// 判断构造函数的 prototype 对象是否在对象的原型链上
while (true) {
if (!proto) return false;
if (proto === prototype) return true;
// 如果没有找到,就继续从其原型上找,Object.getPrototypeOf方法用来获取指定对象的原型
proto = Object.getPrototypeOf(proto);
}
}
7. Почему 0,1+0,2 !== 0,3, как сделать равным
В процессе разработки столкнулся с такой проблемой:
let n1 = 0.1, n2 = 0.2
console.log(n1 + n2) // 0.30000000000000004
То, что вы получаете здесь, не является желаемым результатом.Чтобы он был равен 0,3, вам нужно преобразовать его:
(n1 + n2).toFixed(2) // 注意,toFixed为四舍五入
toFixed(num)
метод округления числа до числа с заданным количеством знаков после запятой. Так почему же возникает этот результат?
Компьютеры хранят данные в двоичном формате, поэтому, когда компьютер вычисляет 0,1+0,2, это на самом деле двоичная сумма двух вычисленных чисел. 0,1 в двоичном формате0.0001100110011001100...
(1100 циклов), двоичный код 0,2 равен:0.00110011001100...
(1100 циклов), двоичные числа этих двух чисел представляют собой числа с бесконечным циклом. Так как же JavaScript обрабатывает двоичные числа с бесконечным циклом?
Обычно мы думаем, что числа включают в себя целые и десятичные числа, но в JavaScript есть только один тип числа: число, его реализация соответствует стандарту IEEE 754 и представлена 64-битной фиксированной длиной, которая представляет собой стандартную двойную плавающую двойную точность. номер точки. В двоичном экспоненциальном представлении дробная часть чисел с плавающей запятой двойной точности может сохранять только до 52 бит плюс предшествующий 1, фактически зарезервировано 53 значащих цифры.
По этому принципу двоичные числа 0,1 и 0,2 складываются и преобразуются в десятичные числа следующим образом:0.30000000000000004
.
Посмотрите нижеКак хранятся числа двойной точностииз:
- Первая часть (синяя): используется для хранения знакового бита (знака), используется для различения положительных и отрицательных чисел, 0 означает положительные числа, занимающие 1 бит
- Вторая часть (зеленая): используется для хранения экспоненты (экспоненты), занимая 11 бит
- Третья часть (красная): используется для хранения дробей, занимает 52 бита.
Для 0.1 его двоичный код:
0.00011001100110011001100110011001100110011001100110011001 10011...
В экспоненциальной записи (результаты экспоненциальной записи с плавающей запятой):
1.1001100110011001100110011001100110011001100110011001*2^-4
Можно видеть, что бит знака 0,1 равен 0, бит экспоненты равен -4, а десятичный разряд равен:
1001100110011001100110011001100110011001100110011001
Потом снова возникает проблемаБит экспоненты отрицательный, как его сохранитьШерстяная ткань?
Стандарт IEEE определяет смещение.Для части экспоненты это смещение добавляется каждый раз для сохранения, поэтому, даже если экспонента имеет отрицательное значение, добавление этого смещения является положительным числом. Поскольку число в JavaScript является числом с двойной точностью, вот пример числа с двойной точностью, его экспоненциальная часть составляет 11 бит, а диапазон, который может быть представлен, составляет от 0 до 2047, что зафиксировано IEEE.Смещение для двойников 1023.
- Когда биты экспоненты не все равны 0 или все 1 (нормализованное значение), IEEE требует, чтобы формула для вычисления кода экспоненты была e-Bias. В это время минимальное значение e равно 1, тогда 1-1023=-1022, а максимальное значение e равно 2046, тогда 2046-1023=1023. Можно видеть, что диапазон значений в этом случае
-1022~1013
. - Когда все биты экспоненты равны 0 (денормализованное значение), IEEE предусматривает, что формула для вычисления кода экспоненты имеет вид 1-смещение, то есть 1-1023=-1022.
- Когда все биты экспоненты равны 1 (специальное значение), IEEE предусматривает, что это число с плавающей запятой может использоваться для представления 3 специальных значений, а именно положительной бесконечности, отрицательной бесконечности и NaN. В частности, когда десятичный разряд не равен 0, это означает NaN; когда десятичный разряд равен 0, когда бит знака s=0 означает положительную бесконечность, а когда s=1 означает отрицательную бесконечность.
Для бита степени 0,1, приведенного выше, это -4, -4 + 1023 = 1019, преобразованное в двоичное:1111111011
.
Итак, 0,1 выражается как:
0 1111111011 1001100110011001100110011001100110011001100110011001
По словам так много, пришло время задать первый вопрос, как добиться 0,1 + 0,2 = 0,3?
Простое решение этой проблемы — установить предел погрешности, часто называемый «машинной точностью». Для JavaScript это значение обычно 2-52, в ES6 обеспечиваетNumber.EPSILON
атрибут, и его значение 2-52, пока суждение0.1+0.2-0.3
Это меньше, чемNumber.EPSILON
, если меньше, то можно оценить как 0,1+0,2 ===0,3
function numberepsilon(arg1,arg2){
return Math.abs(arg1 - arg2) < Number.EPSILON;
}
console.log(numberepsilon(0.1 + 0.2, 0.3)); // true
8. Как получить безопасное неопределенное значение?
Поскольку undefined является идентификатором, его можно использовать и назначать как переменную, но это повлияет на обычное суждение о undefined. Выражение void ___ не имеет возвращаемого значения, поэтому возвращаемый результат не определен. void не меняет результат выражения, он просто заставляет выражение не возвращать значения. Таким образом, вы можете использовать void 0, чтобы получить неопределенность.
9. Каков результат typeof NaN?
NaN означает «не число», NaN — это «сигнальное значение» (обычное значение специального назначения), используемое для обозначения состояния ошибки в числовых типах, т. е. «безуспешное выполнение математической операции. Это результат, возвращаемый после сбоя» .
typeof NaN; // "number"
NaN — это специальное значение, которое не равно самому себе и является единственным значением, которое не является рефлексивным (рефлексивным, то есть x === x не выполняется). И NaN !== NaN верно.
10. В чем разница между функциями isNaN и Number.isNaN?
- После того, как функция isNaN получит параметр, она попытается преобразовать параметр в числовое значение. Любое значение, которое не может быть преобразовано в числовое значение, вернет значение true, поэтому, если передано нечисловое значение, оно также вернет значение true. , что повлияет на решение NaN.
- Функция Number.isNaN сначала определит, является ли входящий параметр числом. Если это число, она будет продолжать определять, является ли он NaN , и преобразование типа данных выполняться не будет. Этот метод более точен для оценки NaN.
11. Каковы правила приведения для оператора ==?
для==
Например, если сравнить типы обеих сторонРазные, будет продолженопреобразование типов. Если сравнитьx
а такжеy
Если они совпадают, будет выполнен следующий процесс оценки:
- Во-первых, он оценит, одинаковы ли два типа, и если они одинаковы, сравнит их размер;
- Если типы не совпадают, будет выполнено преобразование типов;
- Сначала рассудит, стоит ли сравнивать
null
а такжеundefined
, если да, он вернетсяtrue
- Определить, являются ли эти два типа
string
а такжеnumber
, если это так, он преобразует строку вnumber
1 == '1'
↓
1 == 1
- определить, является ли один из
boolean
, если да, то будетboolean
Перевести вnumber
судить снова
'1' == true
↓
'1' == 1
↓
1 == 1
- определить, является ли один из
object
а другойstring
,number
илиsymbol
, если да, то будетobject
Преобразуйте в исходный тип, а затем судите
'1' == { name: 'js' } ↓'1' == '[object Object]'
Его блок-схема выглядит следующим образом:
12. Другие правила преобразования значения в строку?
- Типы Null и Undefined, null преобразуется в «null», undefined преобразуется в «undefined»,
- Логический тип, true преобразуется в «true», а false — в «false».
- Значения типа Number преобразуются напрямую, но экспоненциальная форма используется для очень маленьких и очень больших чисел.
- Значения типа Symbol преобразуются напрямую, но разрешено только явное приведение, использование неявного приведения приведет к ошибке.
- Для обычных объектов, если не определен метод toString(), будет вызываться toString() (Object.prototype.toString()) для возврата значения внутреннего свойства [[Class]], такого как «[object Object]» . Если у объекта есть собственный метод toString(), этот метод вызывается, и его возвращаемое значение используется при преобразовании в строку.
13. Другие правила преобразования значения в числовое значение?
- Значение типа Undefined преобразуется в NaN.
- Значение типа Null преобразуется в 0.
- Значение типа Boolean, true преобразуется в 1, false преобразуется в 0.
- Значения типа String преобразуются, как если бы они были преобразованы с помощью функции Number(), и преобразуются в NaN, если они содержат нечисловые значения, и 0 для пустых строк.
- Значение типа Symbol не может быть преобразовано в число, и будет сообщено об ошибке.
- Объекты (включая массивы) сначала преобразуются в соответствующее значение примитива, а если возвращается нечисловое значение примитива, оно затем приводится к числу в соответствии с приведенными выше правилами.
Чтобы преобразовать значение в соответствующее примитивное значение, абстрактная операция ToPrimitive сначала проверяет (через внутреннюю операцию DefaultValue), имеет ли значение метод valueOf(). Если существует и возвращает примитивное значение, используйте это значение для приведения. Если нет, используйте возвращаемое значение toString() (если оно существует) для приведения.
Если ни valueOf(), ни toString() не возвращают примитивное значение, будет вызвана ошибка TypeError.
14. Каковы правила преобразования других значений в логические значения?
Ниже приведены ложные значения: • неопределенный • нулевой • ложный • +0, -0 и NaN • ""
Логическое приведение ложного значения приводит к ложному. По логике все, что находится за пределами списка ложных значений, должно быть правдой.
15. Какое значение возвращают операторы || и &&?
|| и && сначала выполняют условную оценку первого операнда, и если это не логическое значение, сначала приводят его к логическому типу, а затем выполняют условное суждение.
- Для || возвращается значение первого операнда, если условие истинно, и значение второго операнда, если ложно.
- && Наоборот, если условие истинно, возвращает значение второго операнда, а если ложно, возвращает значение первого операнда.
|| и && возвращают значение одного из своих операндов, а не результат условной проверки
16. В чем разница между Object.is() и операторами сравнения "===" и "=="?
- При использовании двойного знака равенства (==) для оценки равенства, если типы с обеих сторон несовместимы, перед сравнением будет выполнено принудительное преобразование типов.
- При использовании трех знаков равенства (===) для оценки равенства, если типы на обеих сторонах несовместимы, принудительное преобразование типов выполняться не будет, и будет возвращено значение false.
- При использовании Object.is для оценки равенства, как правило, это то же самое, что и оценка трех знаков равенства.Он обрабатывает некоторые особые случаи, такие как -0 и +0 больше не равны, и два NaN равны.
17. Что такое типы-оболочки в JavaScript?
В JavaScript базовые типы не имеют свойств и методов, но для облегчения манипулирования значениями базовых типов JavaScript будет неявно преобразовывать значения базовых типов в объекты в фоновом режиме при вызове свойств или методов базовых типов. типы, такие как:
const a = "abc";
a.length; // 3
a.toUpperCase(); // "ABC"
во время посещения'abc'.length
JavaScript'abc'
Преобразовать в фоновом режиме вString('abc')
, а затем получить доступ к егоlength
Атрибуты.
Также можно использовать JavaScriptObject
Функция явно преобразует базовый тип в тип-оболочку:
var a = 'abc'
Object(a) // String {"abc"}
также можно использоватьvalueOf
Метод инвертирует тип оболочки в базовый тип:
var a = 'abc'
var b = Object(a)
var c = b.valueOf() // 'abc'
Посмотрите, что печатает следующий код:
var a = new Boolean( false );
if (!a) {
console.log( "Oops" ); // never runs
}
Ответ заключается в том, что ничего не будет напечатано, потому что хотя базовый тип пакетаfalse
,ноfalse
После того, как он был заключен в тип-оболочку, он становится объектом, поэтому его незначение равноfalse
, поэтому содержимое тела цикла не будет выполняться.
18. Как сделать неявное преобразование типов в JavaScript?
Первый, кто представитToPrimitive
методы, которые являются неявно встроенными методами каждого значения в JavaScript для преобразования значения (будь то примитивное значение или объект) в примитивное значение. Если значение является примитивным типом, само значение возвращается напрямую; если значение является объектом, это выглядит примерно так:
/**
* @obj 需要转换的对象
* @type 期望的结果类型
*/
ToPrimitive(obj,type)
type
ценностьnumber
илиstring
.
(1) Когдаtype
дляnumber
Правила времени следующие:
- передача
obj
изvalueOf
метод, если это исходное значение, возврат, иначе следующий шаг; - передача
obj
изtoString
метод, следующий такой же, как и выше; - бросать
TypeError
аномальный.
(2) когдаtype
дляstring
Правила времени следующие:
- передача
obj
изtoString
метод, если это исходное значение, возврат, иначе следующий шаг; - передача
obj
изvalueOf
метод, следующий такой же, как и выше; - бросать
TypeError
аномальный.
Можно видеть, что основное различие между ними состоит в том, что вызовtoString
а такжеvalueOf
порядок старшинства. по умолчанию:
- Если объект является объектом Date, то
type
По умолчаниюstring
; - В других случаях
type
По умолчаниюnumber
.
Суммируя приведенные выше правила, для объектов, отличных от Date, приблизительные правила преобразования в примитивные типы можно резюмировать в виде функции:
var objToNumber = value => Number(value.valueOf().toString())
objToNumber([]) === 0
objToNumber({}) === NaN
А неявное преобразование типов в JavaScript в основном происходит в+、-、*、/
так же как==、>、<
между этими операторами. И эти операторы могут работать только на основных значениях типа, поэтому первый шаг до того, как эти операции состоит в том, чтобы использовать значения с обеих сторон сToPrimitive
Преобразуйте в базовый тип, а затем работайте.
Ниже приведены правила неявного преобразования значений примитивных типов в случае разных операторов (для объектов это будетToPrimitive
Преобразованы в базовые типы, поэтому в итоге вам все равно придется применять правила преобразования базовых типов):
-
+
оператор
+
По крайней мере по одному с каждой стороны от оператораstring
Переменные типа, обе стороны неявно преобразуются в строки, в противном случае обе стороны преобразуются в числа.
1 + '23' // '123'
1 + false // 1
1 + Symbol() // Uncaught TypeError: Cannot convert a Symbol value to a number
'1' + false // '1false'
false + true // 1
-
-
,*
,\
оператор
NaN
также номер
1 * '23' // 23
1 * false // 0
1 / 'aa' // NaN
-
для
==
оператор
Значения с обеих сторон оператора преобразуются вnumber
:
3 == true // false, 3 转为number为3,true转为number为1
'0' == false //true, '0'转为number为0,false转为number为0
'0' == 0 // '0'转为number为0
-
для
<
а также>
компаратор
Если обе стороны являются строками, сравните их в алфавитном порядке:
'ca' < 'bd' // false
'a' < 'b' // true
В других случаях преобразуйте в числа и сравните:
'12' < 13 // true
false > -1 // true
Выше приведено неявное преобразование базового типа, и объект будетToPrimitive
Преобразуйте в примитивный тип, а затем преобразуйте:
var a = {}
a > 2 // false
Процесс сравнения выглядит следующим образом:
a.valueOf() // {}, 上面提到过,ToPrimitive默认type为number,所以先valueOf,结果还是个对象,下一步
a.toString() // "[object Object]",现在是一个字符串了
Number(a.toString()) // NaN,根据上面 < 和 > 操作符的规则,要转换成数字
NaN > 2 //false,得出比较结果
Другой пример:
var a = {name:'Jack'}
var b = {age: 18}
a + b // "[object Object][object Object]"
Процесс операции выглядит следующим образом:
a.valueOf() // {},上面提到过,ToPrimitive默认type为number,所以先valueOf,结果还是个对象,下一步
a.toString() // "[object Object]"
b.valueOf() // 同理
b.toString() // "[object Object]"
a + b // "[object Object][object Object]"
19. +
Когда используются операторы для конкатенации строк?
Согласно спецификации ES5, + будет конкатенировать, если один из операндов является строкой или может быть преобразован в строку с помощью следующих шагов. Если один из операндов является объектом (в том числе массивом), сначала над ним вызывается абстрактная операция ToPrimitive, которая, в свою очередь, вызывает [[DefaultValue]] с числом в качестве контекста. Если его нельзя преобразовать в строку, для вычисления он будет преобразован в числовой тип.
Проще говоря, если один из операндов + является строкой (или строка окончательно получена с помощью вышеуказанных шагов), выполните конкатенацию строк, в противном случае выполните числовое сложение.
Затем для операторов, отличных от сложения, если один из них является числом, другая сторона будет преобразована в число.
20. Почему тамBigIntпредложение?
Number.MAX_SAFE_INTEGER в JavaScript представляет собой наибольшее безопасное число, а результат вычисления равен 9007199254740991, то есть в этом диапазоне чисел не произойдет никакой потери точности (кроме десятичных знаков). Однако, как только этот диапазон будет превышен, js будет иметь неточные вычисления, которые должны решаться некоторыми сторонними библиотеками при вычислении больших чисел, поэтому чиновник предложил BigInt для решения этой проблемы.
21. Разница между object.assign и алгоритмом расширения — глубокая копия или поверхностная копия.
Оператор спреда:
let outObj = {
inObj: {a: 1, b: 2}
}
let newObj = {...outObj}
newObj.inObj.a = 2
console.log(outObj) // {inObj: {a: 2, b: 2}}
Object.assign():
let outObj = {
inObj: {a: 1, b: 2}
}
let newObj = Object.assign({}, outObj)
newObj.inObj.a = 2
console.log(outObj) // {inObj: {a: 2, b: 2}}
Как видите, оба являются мелкими копиями.
- Первый параметр, полученный методом Object.assign(), является целевым объектом, а все последующие параметры являются исходным объектом. Затем объедините все исходные объекты в целевой объект. Он изменяет объект, тем самым запуская установщик ES6.
- Расширенный оператор (...) использует его, каждое значение в массиве или объекте копируется на новый массив или объект. Он не копирует унаследованные атрибуты или свойства класса, но он копирует атрибут символов ES6.
2. ЭС6
1. Разница между let, const и var
(1) Область действия на уровне блоков:блок ограничен{ }
Include, let и const имеют область действия блока, var не имеет области действия блока. Область действия блока решает две проблемы в ES5:
- Внутренние переменные могут переопределять внешние переменные
- Переменная цикла, используемая для подсчета, просочилась как глобальная переменная
(2) Вариативное продвижение:Var имеет продвижение переменных, а let и const не имеют продвижения переменных, то есть переменные можно использовать только после объявления, иначе будет сообщено об ошибке.
(3) Добавьте свойства в глобальные:Глобальный объект браузера — это окно, а глобальный объект узла — глобальный. Переменная, объявленная var, является глобальной переменной и добавит эту переменную в качестве свойства глобального объекта, а let и const — нет.
(4) Повторите утверждение:Когда var объявляет переменную, вы можете объявить переменную повторно, и переменная с тем же именем, объявленная позже, перезапишет обход, объявленный ранее. const и let не допускают повторных объявлений переменных.
(5) Временная мертвая зона:Переменная недоступна, пока переменная не будет объявлена с помощью команды let или const. Это синтаксически называетсяВременная мертвая зона. Переменные, объявленные с помощью var, не имеют временных мертвых зон.
(6) Установка исходного значения:Когда переменная объявлена, var и let можно использовать без установки начального значения. В то время как переменные, объявленные const, должны иметь установленное начальное значение.
(7) Указатель указывает на:И let, и const — это новые синтаксисы для создания переменных в ES6. Переменная, созданная let, может изменить указатель на (может быть переназначена). Но константные объявленные переменные не могут изменять указатель на.
разница | var | let | const |
---|---|---|---|
Есть ли область действия блока | × | ✔️ | ✔️ |
Есть ли переменный подъем? | ✔️ | × | × |
добавлять ли глобальные свойства | ✔️ | × | × |
Может повторять переменные | ✔️ | × | × |
Есть ли временная мертвая зона | × | ✔️ | ✔️ |
Должны ли вы установить начальное значение | × | × | ✔️ |
Можете ли вы изменить указатель на | ✔️ | ✔️ | × |
2. Можно ли изменить свойства константного объекта?
Константа гарантирует не то, что значение переменной нельзя изменить, а то, что адрес памяти, на который указывает переменная, не может быть изменен. Для базовых типов данных (числа, строки, логические значения) значение сохраняется по адресу памяти, на который указывает переменная, поэтому оно эквивалентно константе.
Но для данных ссылочного типа (в основном объекты и массивы) переменная указывает на адрес памяти данных и сохраняет только указатель, const может гарантировать только фиксированность указателя, а может ли структура данных, на которую она указывает, быть Если он изменится, он полностью выйдет из-под контроля.
3. Что делать, если новая функция стрелки
Стрелочная функция предложена в ES6, у нее нет ни прототипа, ни собственной этой точки, и она не может использовать параметр arguments, поэтому вы не можете создать стрелочную функцию.
Шаги внедрения нового оператора следующие:
- создать объект
- Назначьте область конструктора новому объекту (то есть укажите свойство __proto__ объекта на свойство прототипа конструктора)
- Указатель на код в конструкторе, this в конструкторе указывает на объект (то есть добавление свойств и методов к этому объекту)
- вернуть новый объект
Следовательно, на втором и третьем шагах выше стрелочные функции не могут быть выполнены.
4. Отличие стрелочных функций от обычных функций
(1) Стрелочные функции более лаконичны, чем обычные функции.
- Если параметров нет, просто напишите пустую скобку
- Если параметр только один, круглые скобки параметра можно опустить.
- Если параметров несколько, разделите их запятыми
- Если возвращаемое значение тела функции представляет собой только одно предложение, фигурные скобки можно опустить.
- Если телу функции не требуется возвращаемое значение, и есть только одно предложение, вы можете добавить ключевое слово void перед оператором. Наиболее распространенным является вызов функции:
let fn = () => void doesNotReturn();
(2) Стрелочные функции не имеют собственного this
Стрелочная функция не создает собственного this, поэтому у нее нет собственного this, она просто наследует это на один уровень выше своей области видимости. Таким образом, указатель this в функции стрелки определяется, когда он определен, и после этого не изменится.
(3) Указатель this, унаследованный функцией стрелки, никогда не изменится
var id = 'GLOBAL';
var obj = {
id: 'OBJ',
a: function(){
console.log(this.id);
},
b: () => {
console.log(this.id);
}
};
obj.a(); // 'OBJ'
obj.b(); // 'GLOBAL'
new obj.a() // undefined
new obj.b() // Uncaught TypeError: obj.b is not a constructor
Метод b объекта obj определяется с помощью функции стрелки. this в этой функции всегда указывает на this в глобальной среде выполнения, где он определен. Даже если функция вызывается как метод объекта obj, это все равно указывает к объекту окна. Обратите внимание, что фигурные скобки, определяющие объект{}
Невозможно сформировать отдельную среду выполнения, она все равно находится в глобальной среде выполнения.
(4) Call(), apply(), bind() и другие методы не могут изменить точку this в функции стрелки.
var id = 'Global';
let fun1 = () => {
console.log(this.id)
};
fun1(); // 'Global'
fun1.call({id: 'Obj'}); // 'Global'
fun1.apply({id: 'Obj'}); // 'Global'
fun1.bind({id: 'Obj'})(); // 'Global'
(5) Стрелочные функции нельзя использовать в качестве конструкторов.
О новом шаге конструктора было сказано выше, по сути, второй шаг — указать this в функции на объект. Однако, поскольку стрелочные функции не имеют собственного this, а this указывает на внешнюю среду выполнения и не может быть изменено, его нельзя использовать в качестве конструктора.
(6) Стрелочные функции не имеют собственных аргументов
Стрелочные функции не имеют собственного объекта аргументов. Доступ к аргументам в стрелочной функции фактически получает значение аргументов ее внешней функции.
(7) Стрелочные функции не имеют прототипа
(8) Стрелочные функции нельзя использовать в качестве функций-генераторов, а ключевое слово yield нельзя использовать.
5. Стрелочные функцииthisУказать куда?
Стрелочные функции отличаются от функций в традиционном JavaScript. Стрелочные функции не имеют собственного this. Его так называемое this — это значение this, которое фиксирует контекст, в котором оно находится, как собственное значение this, а так как этого нет принадлежащий самому себе, Так что он не будет называться новым, и это так называемое это не будет изменено.
Стрелочные функции можно понять с помощью Babel:
// ES6
const obj = {
getArrow() {
return () => {
console.log(this === obj);
};
}
}
После преобразования:
// ES5,由 Babel 转译
var obj = {
getArrow: function getArrow() {
var _this = this;
return function () {
console.log(_this === obj);
};
}
};
6. Роль и сценарии использования оператора спреда
(1) Оператор распространения объекта
Оператор расширения (...) объекта используется для извлечения всех проходимых свойств в объекте параметров и их копирования в текущий объект.
let bar = { a: 1, b: 2 };
let baz = { ...bar }; // { a: 1, b: 2 }
Вышеупомянутый метод фактически эквивалентен:
let bar = { a: 1, b: 2 };
let baz = Object.assign({}, bar); // { a: 1, b: 2 }
Object.assign
метод используется для слияния объектов, объединяя исходный объект(source)
Все перечисляемые свойства , скопированные в целевой объект(target)
.Object.assign
Первый параметр метода — целевой объект, а следующие параметры — исходный объект. (Если у целевого объекта есть атрибут с тем же именем, что и у исходного объекта, или у нескольких исходных объектов есть атрибуты с тем же именем, более поздние атрибуты переопределяют более ранние атрибуты.).
Аналогично, если пользовательское свойство помещается после оператора SPRECT, свойство с тем же именем внутри оператора распространения будет перезаписан.
let bar = {a: 1, b: 2};
let baz = {...bar, ...{a:2, b: 4}}; // {a: 2, b: 4}
Используя вышеперечисленные возможности, вы можете легко изменить некоторые свойства объекта. существуетredux
серединаreducer
Спецификация функции должна бытьчистая функция,reducer
серединаstate
Требования к объекту не могут быть изменены непосредственно изменены. Вы можете скопировать объекты модифицированного пути через оператор спреда, а затем создать новый объект для возврата.
требует внимания:Копия экземпляра объекта оператором распространения является поверхностной копией..
(2) Оператор расширения массива
Оператор расширения массива может преобразовать массив в последовательность аргументов, разделенных запятыми, и может расширять только один уровень массива за раз.
console.log(...[1, 2, 3])
// 1 2 3
console.log(...[1, [2, 3, 4], 5])
// 1 [2, 3, 4] 5
Ниже показано применение оператора распространения к массивам:
- Конвертировать массив в последовательность параметров
function add(x, y) {
return x + y;
}
const numbers = [1, 2];
add(...numbers) // 3
- копировать массив
const arr1 = [1, 2];
const arr2 = [...arr1];
должен помнить:Оператор распространения (...) используется для извлечения всех проходимых свойств в объекте параметра и копирования их в текущий объект., где объект параметра является массивом, все объекты массива являются базовыми типами данных, и все базовые типы данных копируются в новый массив.
- Объединить массивы
Если вы хотите объединить массивы внутри массивов, вы можете сделать это:
const arr1 = ['two', 'three'];const arr2 = ['one', ...arr1, 'four', 'five'];// ["one", "two", "three", "four", "five"]
- Оператор распространения в сочетании с назначением деструктурирования для создания массивов
const [first, ...rest] = [1, 2, 3, 4, 5];first // 1rest // [2, 3, 4, 5]
требует внимания:Если оператор расширения используется для назначения массива, его можно поместить только в последний бит параметра, иначе будет сообщено об ошибке.
const [...rest, last] = [1, 2, 3, 4, 5]; // 报错const [first, ...rest, last] = [1, 2, 3, 4, 5]; // 报错
- Преобразование строки в реальный массив
[...'hello'] // [ "h", "e", "l", "l", "o" ]
- Любой объект интерфейса Iterator можно преобразовать в реальный массив с помощью оператора распространения
Более распространенным приложением является преобразование некоторых структур данных в массивы:
// arguments对象
function foo() {
const args = [...arguments];
}
заменитьes5
серединаArray.prototype.slice.call(arguments)
написание.
-
использовать
Math
Функция для получения определенного значения в массиве
const numbers = [9, 4, 7, 1];
Math.min(...numbers); // 1
Math.max(...numbers); // 9
7. Какие функции может выполнять Proxy?
Пройдено в Vue3.0Proxy
заменить оригиналObject.defineProperty
для достижения скорости реагирования на данные.
Прокси — это новая функция в ES6, ее можно использовать для настройки работы объекта.
let p = new Proxy(target, handler)
target
Представляет объект, к которому необходимо добавить прокси,handler
Используется для настройки операций в объекте, например, для настройкиset
илиget
функция.
посредством следующихProxy
Чтобы реализовать ответ на данные:
let onWatch = (obj, setBind, getLogger) => {
let handler = {
get(target, property, receiver) {
getLogger(target, property)
return Reflect.get(target, property, receiver)
},
set(target, property, value, receiver) {
setBind(value, property)
return Reflect.set(target, property, value)
}
}
return new Proxy(obj, handler)
}
let obj = { a: 1 }
let p = onWatch(
obj,
(v, property) => {
console.log(`监听到属性${property}改变为${v}`)
},
(target, property) => {
console.log(`'${property}' = ${target[property]}`)
}
)
p.a = 2 // 监听到属性a改变
p.a // 'a' = 2
В приведенном выше коде по индивидуальному заказуset
а такжеget
Функциональный метод вставляет логику нашей функции в исходную логику и реализует уведомление, когда любое свойство объекта читается или записывается.
Конечно, это простая версия адаптивной реализации.Если вам нужно реализовать адаптивный ответ в Vue, вам нужноget
собирать зависимости вset
Распространяйте обновления, причина, по которой Vue3.0 используетProxy
Причина замены исходного API заключается в том, чтоProxy
Нет необходимости рекурсивно добавлять агентов для каждого атрибута слой за слоем, вышеперечисленные операции можно выполнить за один раз, и производительность лучше, а исходная реализация имеет некоторые обновления данных, которые нельзя отслеживать, ноProxy
Он может отлично отслеживать изменения данных любым способом, единственный недостаток — совместимость с браузером не очень хорошая.
8. Понимание деструктуризации объектов и массивов
Деструктуризация — это новый режим извлечения данных, предоставляемый ES6, который может целенаправленно получать желаемое значение из объекта или массива.1) Деструктуризация массиваПри деструктурировании массива извлеките нужные данные на основе положения элемента в качестве условия соответствия:
const [a, b, c] = [1, 2, 3]
Наконец, a, b и c присваиваются значения 0-го, 1-го и 2-го битов индекса массива соответственно:Значения элементов в индексе массива 0,1,2 положения, точно сопоставленные с переменной на левой стороне 0,1,2 идут, это режим массива деконструкции. Может также предоставляться переменным массивом, оставленным пустым заполнителем для точного добычи нескольких элементов массива:
const [a,,c] = [1,2,3]
Оставив средний бит пустым, можно успешно присвоить значения первого и последнего битов массива двум переменным a и c:
2) Разрушение объектовДеструктуризация объектов немного сложнее и мощнее, чем структуры массивов. При деконструкции объекта имя атрибута используется в качестве условия сопоставления для извлечения нужных данных. Теперь определите объект:
const stu = {
name: 'Bob',
age: 24
}
Если вы хотите деконструировать два его собственных свойства, вы можете сделать это:
const { name, age } = stu
Это дает имя и возраст двум переменным, равным stu:
Обратите внимание, что деструктурирование объекта строго основано на именах свойств, поэтому даже если поменять местами имена и возраст, результат будет тот же:
const { age, name } = stu
9. Как извлечь указанные свойства в сильно вложенных объектах?
Иногда встречаются очень глубоко вложенные объекты:
const school = {
classes: {
stu: {
name: 'Bob',
age: 24,
}
}
}
Как и переменная имени здесь, она имеет четыре уровня вложенности, и если вы все еще пытаетесь извлечь ее старым методом:
const { name } = school
Очевидно, что это не работает, потому что сам школьный объект не имеет атрибута имени, а имя находится в объекте «сын сына» школьного объекта. Чтобы извлечь имя, относительно глупый способ - деструктурировать слой за слоем:
const { classes } = school
const { stu } = classes
const { name } = stu
name // 'Bob'
Но есть более стандартный способ сделать это, который можно решить с помощью одной строки кода:
const { classes: { stu: { name } }} = school
console.log(name) // 'Bob'
Вы можете далее деконструировать его в виде двоеточия + {имя целевого атрибута} справа от имени деконструированной переменной, пока не будут получены целевые данные.
10. Понимание параметров отдыха
Когда оператор расширения используется в параметрах функции,Он также может объединять отдельные последовательности параметров в массив:
function mutiple(...args) {
let result = 1;
for (var val of args) {
result *= val;
}
return result;
}
mutiple(1, 2, 3, 4) // 24
Здесь mutiple передается в четыре отдельных аргумента, но если вы попытаетесь вывести значение args в функции mutiple, вы обнаружите, что это массив:
function mutiple(...args) {
console.log(args)
}
mutiple(1, 2, 3, 4) // [1, 2, 3, 4]
Это еще один уровень мощности оператора ... rest, который может объединять несколько входных параметров функции в массив. в этот моментОн часто используется для получения избыточных параметров функции или для решения ситуации, когда количество параметров функции неопределенно, как указано выше.
11. Синтаксис шаблона и обработка строк в ES6
ES6 ввел понятие «синтаксис шаблона». До ES6 объединение строк было громоздким:
var name = 'css'
var career = 'coder'
var hobby = ['coding', 'writing']
var finalString = 'my name is ' + name + ', I work as a ' + career + ', I love ' + hobby[0] + ' and ' + hobby[1]
Переменных всего несколько, столько плюсов написано, и надо всегда быть внимательным, не ошиблись ли в нем пробелы и знаки препинания. Но с шаблонными строками сложность сплайсинга резко падает:
var name = 'css'
var career = 'coder'
var hobby = ['coding', 'writing']
var finalString = `my name is ${name}, I work as a ${career} I love ${hobby[0]} and ${hobby[1]}`
Строки не только легче писать, но и легче читать, а общее качество кода выше. Это первое преимущество шаблонных строк — возможность встраивать переменные в виде ${}. Но дело не в этом, ключевых преимуществ шаблонных строк два:
- В строках шаблона сохраняются пробелы, отступы и новые строки.
- Строки шаблона полностью поддерживают «операционные» выражения, а некоторые вычисления можно выполнять в ${}
Исходя из первого пункта, можно беспрепятственно писать html код прямо в строку шаблона:
let list = `
<ul>
<li>列表项1</li>
<li>列表项2</li>
</ul>
`;
console.log(message); // 正确输出,不存在报错
Основываясь на втором пункте, в ${} можно добавить несколько простых вычислений и вызовов:
function add(a, b) {
const finalString = `${a} + ${b} = ${a+b}`
console.log(finalString)
}
add(1, 2) // 输出 '1 + 2 = 3'
В дополнение к шаблону синтаксиса ES6 также добавляет ряд строковых методов для повышения эффективности развития:
(1)суждение о существовании: Раньше при оценке наличия символа/строки в строке это можно было сделать только с indexOf > -1. ES6 теперь предоставляет три метода: include,startsWith,endsWith, и все они возвращают логическое значение, чтобы сообщить вам, существует ли оно.
- includes: определить отношение включения между строкой и подстрокой:
const son = 'haha'
const father = 'xixi haha hehe'
father.includes(son) // true
- startsWith: определить, начинается ли строка с определенной/строки символов:
const father = 'xixi haha hehe'
father.startsWith('haha') // false
father.startsWith('xixi') // true
- endsWith: определить, заканчивается ли строка определенной/строкой символов:
const father = 'xixi haha hehe'
father.endsWith('hehe') // true
(2)автоматический повтор: Вы можете использовать метод повтора, чтобы одна и та же строка выводилась несколько раз (реплицируется несколько раз подряд):
const sourceCode = 'repeat for 3 times;'
const repeated = sourceCode.repeat(3)
console.log(repeated) // repeat for 3 times;repeat for 3 times;repeat for 3 times;
3. Основы JavaScript
1. Принцип реализации нового оператора
Процесс выполнения нового оператора:
(1) Сначала создайте новый пустой объект
(2) Установите прототип, установите прототип объекта в прототип объекта функции.
(3) Пусть this функции указывает на этот объект, выполняет код конструктора (добавляет свойства к этому новому объекту)
(4) Определите тип возвращаемого значения функции.Если это тип значения, верните созданный объект. Если это ссылочный тип, возвращается объект этого ссылочного типа.
Реализация:
function objectFactory() {
let newObject = null;
let constructor = Array.prototype.shift.call(arguments);
let result = null;
// 判断参数是否是一个函数
if (typeof constructor !== "function") {
console.error("type error");
return;
}
// 新建一个空对象,对象的原型为构造函数的 prototype 对象
newObject = Object.create(constructor.prototype);
// 将 this 指向新建对象,并执行函数
result = constructor.apply(newObject, arguments);
// 判断返回对象
let flag = result && (typeof result === "object" || typeof result === "function");
// 判断返回结果
return flag ? result : newObject;
}
// 使用方法
objectFactory(构造函数, 初始化参数);
2. Разница между картой и объектом
Map | Object | |
---|---|---|
неожиданный ключ | Карта по умолчанию не содержит ключей, только явно вставленные ключи. | У объекта есть прототип, и имя ключа в цепочке прототипов может конфликтовать с именем ключа, заданным для объекта. |
тип ключа | Ключи карты могут быть любыми значениями, включая функции, объекты или любой примитивный тип. | Ключи объекта должны быть строковыми или символьными. |
порядок ключей | Ключи в Карте упорядочены. Поэтому при повторении объект Map возвращает ключи в том порядке, в котором они были вставлены. | Ключи объекта неупорядочены |
Size | Значение ключа карты можно легко получить с помощью свойства Size. | Количество пар ключ-значение объекта можно рассчитать только вручную. |
повторять | Карта является итерируемой, поэтому ее можно повторять напрямую. | Для повторения объекта требуется каким-то образом получить его ключи, прежде чем вы сможете выполнить итерацию. |
представление | Он лучше работает в сценариях, где пары ключ-значение часто добавляются или удаляются. | Не оптимизирован в сценариях, где пары ключ-значение часто добавляются и удаляются. |
3. Разница между картой и слабой картой
(1) КартаКарта — это, по сути, набор пар ключ-значение, но ключи в паре ключ-значение в общем объекте могут быть только строками. Структура данных карты, предоставляемая ES6, похожа на объект, но ее ключи не ограничены по объему и могут быть любого типа, что является более полной структурой хэша. Если ключ Карты является примитивным типом данных, пока два ключа строго одинаковы, они считаются одним и тем же ключом.
По сути, Map — это массив, и каждое его данные — тоже массив, и его форма такова:
const map = [
["name","张三"],
["age",18],
]
Структура данных карты имеет следующие методы работы:
-
size:
map.size
Возвращает общее количество членов структуры Map. - set(key,value): Установите значение значения ключа, соответствующее ключу имени ключа, а затем верните всю структуру Map.Если ключ уже имеет значение, значение ключа будет обновлено, в противном случае ключ будет сгенерирован заново. (Поскольку текущий объект Map возвращается, его можно вызывать в цепочке)
- get(key): этот метод считывает значение ключа, соответствующее ключу, и возвращает неопределенное значение, если ключ не найден.
- has(key): этот метод возвращает логическое значение, указывающее, находится ли ключ в текущем объекте Map.
- delete(key): этот метод удаляет ключ и возвращает true, если удаление не удалось, возвращает false.
- clear(): map.clear() очищает все члены, без возвращаемого значения.
Структура Map изначально предоставляет три функции генерации обхода и один метод обхода.
- keys(): возвращает обходчик имен ключей.
- values(): возвращает итератор ключевых значений.
- entry(): возвращает обход всех членов.
- forEach(): выполняет итерацию по всем элементам карты.
const map = new Map([
["foo",1],
["bar",2],
])
for(let key of map.keys()){
console.log(key); // foo bar
}
for(let value of map.values()){
console.log(value); // 1 2
}
for(let items of map.entries()){
console.log(items); // ["foo",1] ["bar",2]
}
map.forEach( (value,key,map) => {
console.log(key,value); // foo 1 bar 2
})
(2) Слабая картаОбъект WeakMap также представляет собой набор пар ключ-значение, где на ключи слабо ссылаются.Его ключ должен быть объектом, примитивные типы данных не могут использоваться в качестве значений ключей, а значения могут быть произвольными.
Объект также имеет следующие методы:
- set(key,value): Установите значение значения ключа, соответствующее ключу имени ключа, а затем верните всю структуру Map.Если ключ уже имеет значение, значение ключа будет обновлено, в противном случае ключ будет сгенерирован заново. (Поскольку текущий объект Map возвращается, его можно вызывать в цепочке)
- get(key): этот метод считывает значение ключа, соответствующее ключу, и возвращает неопределенное значение, если ключ не найден.
- has(key): этот метод возвращает логическое значение, указывающее, находится ли ключ в текущем объекте карты.
- delete(key): этот метод удаляет ключ и возвращает true, если удаление не удалось, возвращает false.
Его метод clear() устарел, поэтому очистку можно выполнить, создав пустую WeakMap и заменив исходный объект.
Цель разработки WeakMap заключается в том, что иногда вы хотите сохранить некоторые данные об объекте, но это сформирует ссылку на этот объект. Как только два объекта больше не нужны, ссылка должна быть удалена вручную, иначе механизм сборки мусора не освободит память, занимаемую объектами.
СЛАБАЯ КАРТАОбъект, на который ссылается имя ключа, является слабой ссылкой, то есть ссылка не учитывается механизмом сборки мусора. Поэтому, как только другие ссылки на указанный объект очищаются, механизм сборки мусора освобождает память, занятую объектом. То есть, когда он больше не нужен,Объект имени ключа и соответствующая пара ключ-значение исчезнут автоматически, нет необходимости вручную удалять ссылку.
Суммировать:
- Структура данных карты. Он подобен объекту и также представляет собой набор пар ключ-значение, но область действия «ключей» не ограничивается строками, и в качестве ключей могут использоваться различные типы значений (включая объекты).
- Структура WeakMap аналогична структуре Map и также используется для создания набора пар ключ-значение. Но WeakMap принимает в качестве ключей только объекты (кроме null), и не принимает в качестве ключей другие типы значений. И объект, на который указывает имя ключа WeakMap, не включается в механизм сборки мусора.
4. Что такое встроенные объекты JavaScript
Глобальные объекты или стандартные встроенные объекты не следует путать с «глобальными объектами». Упомянутый здесь глобальный объект означает, что в Объекты в глобальной области видимости. Другие объекты в глобальной области видимости могут быть созданы сценарием пользователя или предоставлены хост-программой.
Классификация стандартных встроенных объектов:
(1) Свойства значений, эти глобальные свойства возвращают простое значение, эти значения не имеют собственных свойств и методов. Например, Infinity, NaN, undefined, нулевые литералы.
(2) Атрибуты функций, глобальные функции могут быть вызваны напрямую без указания объекта, которому они принадлежат при вызове, и результат будет возвращен непосредственно вызывающей стороне после выполнения. например, eval(), parseFloat(), parseInt() и т. д.
(3) Базовые объекты Базовые объекты являются основой для определения или использования других объектов. К базовым объектам относятся общие объекты, функциональные объекты и объекты ошибок. Например, объект, функция, логическое значение, символ, ошибка и т. д.
(4) Объекты числа и даты, которые используются для представления чисел, дат и объектов, выполняющих математические вычисления. например, число, математика, дата
(5) Строки, объекты, используемые для представления строк и управления ими. Например, строка, регулярное выражение.
(6) Объекты индексируемых коллекций, которые представляют коллекции данных, отсортированные по значениям индекса, включая массивы и типизированные массивы, а также объекты со структурами, подобными массивам. например массив
(7) Объекты-коллекции с использованием ключей. Эти объекты-коллекции используют ключи при хранении данных и поддерживают повторяющиеся элементы в порядке вставки. Например, карта, набор, слабая карта, слабый набор
(8) Набор векторов, данные в наборе векторов SIMD будут организованы в последовательность данных. например, SIMD и т. д.
(9) Структурированные данные. Эти объекты используются для представления данных структурированного буфера и управления ими или используют данные в кодировке JSON. например JSON и т. д.
(10) Управление абстрактным объектом Например, Обещание, Генератор и т.д.
(11) РАЗМЫШЛЕНИЯ. Например, отражение, прокси
(12) Интернационализация, добавление объектов ECMAScript для поддержки многоязычной обработки. Например, Intl, Intl.Collator и т. д.
(13) Веб-сборка
(14) ДРУГОЕ. например аргументы
Суммировать:Встроенные объекты в js в основном относятся к некоторым глобальным атрибутам значений, функциям и объектам-конструкторам, определенным js, которые существуют в глобальной области до выполнения программы и используются для создания экземпляров других объектов. Обычно используемые значения глобальных переменных, такие как NaN и undefined, глобальные функции, такие как parseInt(), parseFloat(), используются для создания экземпляров конструкторов объектов, таких как Date, Object и т. д., а также отдельных встроенных объектов, обеспечивающих математические вычисления. вычисления, такие как математические объекты.
5. Какие наиболее часто используемые регулярные выражения?
// (1)匹配 16 进制颜色值
var regex = /#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})/g;
// (2)匹配日期,如 yyyy-mm-dd 格式
var regex = /^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/;
// (3)匹配 qq 号
var regex = /^[1-9][0-9]{4,10}$/g;
// (4)手机号码正则
var regex = /^1[34578]\d{9}$/g;
// (5)用户名正则
var regex = /^[a-zA-Z\$][a-zA-Z0-9_\$]{4,16}$/;
6. Понимание JSON
JSON — это облегченный текстовый формат обмена данными. Он может быть прочитан любым языком программирования и передан как формат данных.
При разработке проектов JSON используется как способ обмена данными между интерфейсом и сервером. На внешнем интерфейсе путем сериализации структуры данных, совместимой с JSON, как JSON, а затем передать ее серверной части, и серверная часть анализирует строку в формате JSON для создания соответствующей структуры данных, чтобы реализовать передачу внешних и внутренних данных.
Поскольку синтаксис JSON основан на js, легко спутать JSON и объекты в js, но следует отметить, что объекты в JSON и js — это не одно и то же, а формат объектов в JSON более строгий, например так как в JSON значения свойств не могут быть функциями, а такие значения свойств, как NaN, не могут появляться, поэтому большинство объектов js не соответствуют формату объектов JSON.
В js предусмотрены две функции для реализации обработки преобразования структуры данных js и формата JSON,
- Функция JSON.stringify преобразует структуру данных, совместимую с JSON, в строку JSON, передавая ее. Если входящая структура данных не соответствует формату JSON, при сериализации над этими значениями будет выполнена соответствующая специальная обработка, чтобы привести их в соответствие со спецификацией. При отправке данных от внешнего интерфейса к внутреннему вы можете вызвать эту функцию, чтобы преобразовать объект данных в строку в формате JSON.
- JSON.parse(), эта функция используется для преобразования строки в формате JSON в структуру данных js.Если входящая строка не является стандартной строкой в формате JSON, будет выдана ошибка. Когда строка в формате JSON получена от серверной части, этот метод можно использовать для ее анализа в структуру данных js для доступа к данным.
7. Какие есть способы ленивой загрузки скриптов JavaScript?
Ленивая загрузка означает ожидание загрузки страницы перед загрузкой файла JavaScript. js отложенная загрузка помогает повысить скорость загрузки страницы.
Обычно существуют следующие способы:
- атрибут отсрочки:Добавьте атрибут defer в скрипт js, этот атрибут заставит загрузку скрипта и синтаксический анализ документа синхронно анализировать, а затем выполнить файл скрипта после завершения синтаксического анализа документа, чтобы рендеринг страницы не был заблокирован. Несколько сценариев с установленным атрибутом defer выполняются последовательно последними по спецификации, но в некоторых браузерах это может быть не так.
- асинхронный атрибут:Добавьте в скрипт js атрибут async. Этот атрибут заставит скрипт загружаться асинхронно и не будет блокировать процесс парсинга страницы. Однако скрипт js будет выполняться сразу после загрузки скрипта. В это время, если документ не анализируется, он также будет заблокирован. Порядок выполнения скриптов с несколькими асинхронными атрибутами непредсказуем и обычно не выполняется последовательно в порядке кода.
- Динамически создать метод DOM:Динамически создавая теги DOM, вы можете отслеживать события загрузки документа, а затем динамически создавать теги сценария для импорта сценариев js при загрузке документа.
- Используйте метод задержки setTimeout:Установите таймер для задержки загрузки файлов скриптов js.
- Пусть JS загружается последним:Поместите js-скрипт в конец документа, чтобы js-скрипт максимально загружался и выполнялся в конце.
8. Каково определение массивоподобного объекта JavaScript?
Объект со свойством длины и несколькими свойствами индекса можно назвать массивоподобным объектом, массивоподобные объекты похожи на массивы, но они не могут вызывать методы массива. Обычные массивоподобные объекты имеют аргументы и возвращаемый результат методов DOM, а функцию также можно рассматривать как массивоподобный объект, поскольку она содержит значение свойства длины, которое представляет количество параметров, которые могут быть получены.
Существует несколько распространенных методов преобразования массива, подобного массиву, в массив:
(1) Преобразовать, вызвав метод среза массива
Array.prototype.slice.call(arrayLike);
(2) Преобразование реализуется вызовом метода склейки массива вызовом
Array.prototype.splice.call(arrayLike, 0);
(3) Преобразование осуществляется вызовом метода concat массива через apply
Array.prototype.concat.apply([], arrayLike);
(4) Преобразование достигается с помощью метода Array.from
Array.from(arrayLike);
9. Какие оригинальные методы в массивах?
- Методы преобразования для массивов и строк: toString(), toLocalString(), join() Метод join() может указывать разделитель при преобразовании в строку.
- Методы операций хвоста массива pop() и push(), метод push может передавать несколько параметров.
- Методы работы с заголовком массива shift() и unshift() Методы переупорядочения reverse() и sort(), метод sort() может передавать функцию для сравнения, передавать два значения до и после, если возвращаемое значение является положительное число, затем поменяйте местами два параметра.
- Метод соединения с массивом concat() возвращает конкатенированный массив, не затрагивая исходный массив.
- Метод перехвата массива slice() используется для перехвата части массива и возврата ее, не затрагивая исходный массив.
- Метод вставки массива splice(), метод, который воздействует на исходный массив, чтобы найти индекс определенного элемента, методы итерации indexOf() и lastIndexOf() Every(), some(), filter(), map() и forEach( ) методы
- Методы слияния массивов Методы reduce() и reduceRight()
10. Разница между Unicode, UTF-8, UTF-16, UTF-32?
(1) Юникод
говорящийUnicode
Нужно знать передASCII
Код: код ASCII (American Standard Code for Information Interchange
) называется Американским стандартным кодом обмена информацией.
- Это компьютерная система кодирования, основанная на латинском алфавите.
- Он определяет словарь для представления общих символов.
- Он содержит «A-Z» (включая верхний и нижний регистр), данные «0-9» и некоторые общие символы.
- Он специально разработан для английского языка со 128 кодами и ничего не может сделать для других языков.
ASCII
Коды, которые могут быть представлены кодом, ограничены.Если вы хотите представить коды других языков, вам все равно нужно использоватьUnicode
выразить, так сказатьUnicode
даASCII
надмножество .
Unicode
полное имяUnicode Translation Format
, также известный как Unicode, универсальный код и единый код.Unicode
Он создан для устранения ограничений традиционных схем кодирования символов.Он устанавливает единую и уникальную двоичную кодировку для каждого символа на каждом языке, чтобы удовлетворить требования межъязыкового и кроссплатформенного преобразования и обработки текста.
Unicode
Существует много способов реализации (то есть кодирования), наиболее распространенными являютсяUTF-8,UTF-16,UTF-32а такжеUSC-2.
(2) UTF-8
UTF-8
является наиболее широко используемымUnicode
Метод кодирования, это метод кодирования переменной длины, который может варьироваться от 1 до 4 байтов, и он может быть полностью совместимASCII
128 символов кода.
Уведомление: UTF-8
это метод кодирования,Unicode
представляет собой набор символов.
UTF-8
Правила кодирования для:
- дляодин байтСимвол байта, первый бит байта равен 0, а следующие 7 битов - это символы.
Unicode
кодировка, поэтому для английских букв ееUnicode
кодирование иACSII
такая же кодировка. - дляn байтсимвол, все первые n бит первого байта равны 1, n+1-й бит установлен на 0, первые два бита следующих байтов установлены на 10, а оставшиеся неупомянутые двоичные биты являются символическими.
Unicode
код .
Давайте посмотрим на конкретныеUnicode
Диапазон чисел соответствуетUTF-8
Двоичный формат:
Диапазон кодирования (десятичное число, соответствующее числу) | двоичный формат |
---|---|
0x00—0x7F (0-127) | 0xxxxxxx |
0x80—0x7FF (128-2047) | 110xxxxx 10xxxxxx |
0x800—0xFFFF (2048-65535) | 1110xxxx 10xxxxxx 10xxxxxx |
0x10000—0x10FFFF (выше 65536) | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
Как пройти спец.Unicode
кодирование, спец.UTF-8
Что с кодировкой?Выполните следующие действия:
- Найти
Unicode
Диапазон чисел, в котором находится кодировка, а затем найти соответствующий двоичный формат - Буду
Unicode
Преобразовать кодировку в двоичное число (удалить старший значащий 0) - Заполните двоичное число справа налево один раз в двоичном формате
X
, если естьX
Если не заполнено, установите 0
Давайте посмотрим на практический пример:
"лошадь" СловоUnicode
Кодировка:0x9A6C
, целое число равно39532
(1) Первый выбор определяет, что символ находится в третьем диапазоне, и его формат1110xxxx 10xxxxxx 10xxxxxx
(2) Двоичное число, соответствующее 39532, равно1001 1010 0110 1100
(3) Заполните двоичное число в X, результат:11101001 10101001 10101100
(3) UTF-16
1. Понятие о плоскости
в пониманииUTF-16
Перед этим взглянитеплоскийКонцепция чего-либо:Unicode
В кодировке много-много символов.Определяется не в один момент,а определяется разделами.Каждая область хранит65536(216) символов, это называетсяплоский, всего на данный момент 17 самолетов.
Первый самолет называетсяосновная плоскость, чьи кодовые точки взяты из0 — 216-1, записанный в шестнадцатеричном форматеU+0000 — U+FFFF
, остальные 16 плоскостейвспомогательная плоскость, диапазон кодовых точекU+10000—U+10FFFF
.
2. Концепция UTF-16:
UTF-16
СлишкомUnicode
Форма кодирования набора кодирования, который помещаетUnicode
Абстрактные кодовые точки набора символов отображаются в последовательности 16-битных целых чисел (т. е. кодовых единиц), используемых для хранения или передачи данных.Unicode
Для представления кодовой точки символа требуется одна или две 16-битные кодовые единицы, поэтомуUTF-16
Он также представлен байтами переменной длины.
3. Правила кодировки UTF-16:
- пронумерованы в
U+0000—U+FFFF
символ (общий набор символов), непосредственно представленный двумя байтами. - пронумерованы в
U+10000—U+10FFFF
Символы между ними должны быть представлены четырьмя байтами.
4. Распознавание кода
Итак, вопрос в том, когда встречаются два байта, как узнать, следует ли рассматривать их как символ или вместе со следующими двумя байтами как символ?
UTF-16
Кодирование, должно быть, учитывало и это, в фундаментальном плане, начиная сU+D800 — U+DFFF
Это пустой сегмент, то есть кодовые точки этого интервала не соответствуют никаким символам, поэтому эти пустые сегменты можно использовать для отображения символов вспомогательной плоскости.
Вспомогательная плоскость общая220битов символов, поэтому для представления этих символов требуется не менее 20 двоичных битов.UTF-16
Разделите 20 двоичных битов пополам, первые 10 бит отображаются вU+D800 — U+DBFF
, называетсявысоко(H), последние 10 бит отображаются вU+DC00 — U+DFFF
, называетсянизкий(Л). Это эквивалентно разделению символов вспомогательного плана на два символа основного плана для представления.
Таким образом, когда встречаются два байта, их кодовая точка находится по адресуU+D800 —U+DBFF
между ними вы можете знать, что кодовая точка двух байтов после нее должна быть вU+DC00 — U+DFFF
Между ними четыре байта должны быть объединены для интерпретации.
5. Примеры
к "𡠀"слово, например, этоUnicode
Кодовая точка0x21800
, кодовая точка находится за пределами базовой плоскости, поэтому она должна быть представлена четырьмя байтами Шаги следующие:
- Сначала вычислите результат избыточной части:
0x21800 - 0x10000
- Преобразуйте приведенный выше результат вычисления в 20-битное двоичное число и добавьте 0 впереди, если число меньше 20. Результат:
0001000110 0000000000
- Два полученных 10-битных двоичных числа соответствуют двум интервалам соответственно
-
U+D800
Соответствующее двоичное число1101100000000000
, Буду0001000110
Заполните последние 10 бит, чтобы получить1101100001000110
, преобразованный в шестнадцатеричный как0xD846
. Точно так же младший бит0xDC00
, поэтому словоUTF-16
закодировано как0xD846 0xDC00
(4) UTF-32
UTF-32
Это целочисленная двоичная форма числа, соответствующего символу.Каждый символ занимает четыре байта.Этот код преобразуется напрямую. Этот метод кодирования занимает больше места для хранения, поэтому используется реже.
Например"лошадь«Номер Unicode слова:U+9A6C
, целое число равно39532
, непосредственно преобразованный в двоичный файл:1001 1010 0110 1100
, что является его кодировкой UTF-32.
(5) Резюме
В чем разница между Unicode, UTF-8, UTF-16, UTF-32?
-
Unicode
кодированный набор символов (набор символов), аUTF-8
,UTF-16
,UTF-32
кодировка набора символов (правила кодировки); -
UTF-16
Метод кодирования с использованием последовательности символов переменной длины по сравнению с последовательностью символов фиксированной длиныUTF-32
Алгоритм более сложен, чем та же самая последовательность символов переменной длины.UTF-8
также является более сложным, поскольку вводит уникальныйсуррогатная паратакой агентский механизм; -
UTF-8
Необходимо судить информацию о начальном флагах в каждом байте, поэтому, если байт неверно во время передачи, он приведет к неправильному анализу следующие байты; иUTF-16
Он не будет судить об открывающем знаке, даже если он неправильный, он будет ошибочным только на один символ, поэтому способность отказоустойчивости сильна; - Если содержимое символов полностью на английском языке или английский язык смешан с другими символами, но английский язык составляет большинство, используйте
UTF-8
чемUTF-16
Экономит много места; и если содержание символов состоит из одинаковых символов, таких как китайский или китайский, приходится подавляющее большинство смешанных символов, тоUTF-16
Это имеет преимущество и может сэкономить много места;
11. Каковы распространенные побитовые операторы? Каковы правила его расчета?
Данные в современных компьютерах хранятся в двоичной форме, т. е. 0 и 1. Операции, выполняемые компьютерами над двоичными данными, такие как сложение, вычитание, умножение и деление, называются битовыми операциями, т. е. операциями, в которых знак бит участвует в операции.
Общие битовые операции следующие:
оператор | описывать | алгоритм |
---|---|---|
& |
а также | Когда оба бита равны 1, результат равен 1 |
` | ` | или |
^ |
исключающее ИЛИ | Два бита равны 0, разные равны 1 |
~ |
отрицать | 0 становится 1, 1 становится 0 |
<< |
сдвиг влево | Все двоичные биты сдвигаются влево на несколько битов, старшие биты отбрасываются, а младшие биты заполняются 0 |
>> |
переместить вправо | Все двоичные биты сдвигаются вправо на несколько битов, положительные числа остаются с 0, отрицательные числа остаются с 1, а правая часть отбрасывается. |
1. Побитовый оператор И (&)
определение:Два данных, участвующих в расчетепо двоичному кодуВыполните операцию И.Правила эксплуатации:
0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1
Итог: два бита равны 1, результат равен 1, иначе результат равен 0. Например: 3 и 5 это:
0000 0011
0000 0101
= 0000 0001
Итак, 3&5 имеет значение 1. Примечание. Отрицательные числа участвуют в побитовой операции И в форме дополнения.
использовать:
(1) Оценка паритета
Пока он определяется в соответствии с тем, равен ли младший бит 0 или 1, 0 — четное число, а 1 — нечетное число. Таким образом, вы можете использоватьif ((i & 1) == 0)
заменятьif (i % 2 == 0)
чтобы определить, является ли a четным.
(2) Очистить
Если вы хотите очистить ячейку, даже если все ее двоичные биты равны 0, пока она объединяется по И со значением, все биты которого равны нулю, результат равен нулю.
2. Оператор побитового ИЛИ (|)
определение:Два объекта, участвующих в операции, «обрабатываются» в соответствии с двоичным битом.
Правила эксплуатации:
0 | 0 = 0
0 | 1 = 1
1 | 0 = 1
1 | 1 = 1
Резюме: Пока один из двух объектов, участвующих в операции, равен 1, его значение равно 1. Например: 3|5 это:
0000 0011
0000 0101
= 0000 0111
Следовательно, значение 3|5 равно 7. Примечание. Отрицательные числа участвуют в побитовой операции ИЛИ в форме дополнения.
3. Оператор XOR (^)
определение:Два данных, участвующих в операции, объединяются «исключительным ИЛИ» в соответствии с двоичным битом.
Правила эксплуатации:
0 ^ 0 = 0
0 ^ 1 = 1
1 ^ 0 = 1
1 ^ 1 = 0
Резюме: два объекта участвуют в операции, если два соответствующих бита одинаковы, то это 0, а разница равна 1. Например: 3|5 это:
0000 0011
0000 0101
= 0000 0110
Итак, 3^5 имеет значение 6. Свойства операции XOR:
- Коммутативный закон:
(a^b)^c == a^(b^c)
- Ассоциативность:
(a + b)^c == a^b + b^c
- Для любого числа х имеем
x^x=0,x^0=x
- Рефлексивность:
a^b^b=a^0=a
;
4. Оператор отрицания (~)
определение:Данные, участвующие в операции, «инвертируются» в соответствии с двоичным кодом.
Правила эксплуатации:
~ 1 = 0~ 0 = 1
Резюме: побитовое инвертирование двоичного числа, то есть 0 становится 1, а 1 становится 0. Например: ~6 это:
0000 0110= 1111 1001
В компьютере положительные числа представлены исходным кодом, а отрицательные числа сохранены в дополнительном коде. Этот компьютерный двоичный код представляет собой отрицательное число, старший бит которого является битом знака. Когда побитовое отрицание оказывается отрицательным,Возьмем его дополнение напрямую, преобразованный в десятичный:
0000 0110 = 1111 1001反码:1000 0110补码:1000 0111
Следовательно, ~6 имеет значение -7.
5. Оператор сдвига влево (
определение:Сдвиньте все двоичные биты операнда влево на несколько битов, отбросьте двоичные биты слева и добавьте 0 справа. Положим a=1010 1110, a = a
6. Оператор сдвига вправо (>>)
определение:Сдвиньте все двоичные биты числа вправо на несколько битов, добавьте 0 слева для положительных чисел, добавьте 1 слева для отрицательных чисел и отбросьте право. Например: a=a>>2 Двоичный бит a сдвигается вправо на 2 бита, а левое дополнение равно 0 или левое дополнение равно 1, в зависимости от того, является ли сдвинутое число положительным или отрицательным. Каждый сдвиг операнда вправо эквивалентен делению числа на 2.
7. Исходный код, дополнительный код, обратный код
Знание дополнительного и обратного кода упоминалось выше, поэтому я добавлю его сюда. в компьютереподписанный номерСуществует три метода представления: исходный код, обратный код и дополнительный код. Три метода представления состоят из двух частей: бит знака и бит значения.Бит знака использует 0 для представления «положительного» и 1 для представления «отрицательного», а бит значения имеет три различных метода представления.
(1) Исходный код
Исходный код представляет собой двоичное число числа. Например: исходный код 10 — 0000 1010.
(2) Обратный код
- Дополнение положительного числа такое же, как исходный код, например: дополнение до 10 равно 0000 1010.
- Обратный код отрицательного числа — это бит знака, который бит за битом инвертируется, то есть 0 становится 1, а 1 становится 0.
Например: -10
原码:1000 1010
反码:1111 0101
(3) Код дополнения
- Дополнение положительных чисел такое же, как исходный код, например: дополнение до 10 равно 0000 1010.
- Дополнение отрицательного числа — это инверсия всех битов исходного кода, кроме бита знака, то есть 0 становится 1, 1 становится 0, а затем добавляется 1, то есть дополнение плюс 1.
Например: -10
原码:1000 1010
反码:1111 0101
补码:1111 0110
12. Почему параметр arguments функции похож на массив, а не на массив? Как перебрать массив классов?
arguments
это объект, свойствами которого являются числа, начинающиеся с 0 и возрастающие по порядку, иcallee
а такжеlength
и другие свойства, подобные массивам, но он не имеет общих свойств методов массивов, таких какforEach
, reduce
и т. д., поэтому назовите их массивными.
Для перебора массива классов есть три метода:
(1) Примените метод массива к массиву классов, и вы можете использовать его в это время.call
а такжеapply
методы, такие как:
function foo(){
Array.prototype.forEach.call(arguments, a => console.log(a))
}
(2) Используйте метод Array.from для преобразования массива классов в массив:
function foo(){
const arrArgs = Array.from(arguments)
arrArgs.forEach(a => console.log(a))
}
(3) Используйте оператор расширения для преобразования массива классов в массив
function foo(){
const arrArgs = [...arguments]
arrArgs.forEach(a => console.log(a))
}
13. Что такое DOM и BOM?
- DOM относится к объектной модели документа, которая относится к обработке документа как к объекту, который в основном определяет методы и интерфейсы для обработки веб-контента.
- Спецификация относится к объектной модели браузера, которая относится к обращению с браузером как к объекту, который в основном определяет методы и интерфейсы для взаимодействия с браузером. Ядром BOM является окно, а объект окна имеет двойную роль, это не только интерфейс для доступа к окну браузера через js, но и глобальный (глобальный) объект. Это означает, что любой объект, переменная и функция, определенные на веб-странице, существуют как свойство или метод глобального объекта. Объект окна содержит подобъекты, такие как объекты местоположения, объекты навигатора, объекты экрана и т. д., а самый фундаментальный объект DOM, объект документа, также является подобъектом объекта окна спецификации.
14. Понимание массивоподобных объектов, как преобразовать их в массивы
Объект со свойством длины и несколькими свойствами индекса можно назвать массивоподобным объектом, массивоподобные объекты похожи на массивы, но они не могут вызывать методы массива. Общие массивоподобные объекты включают аргументы и возвращаемый результат методов DOM.Параметры функции также можно рассматривать как массивоподобные объекты, поскольку они содержат значение свойства длины, которое представляет количество параметров, которые могут быть получены.
Существует несколько распространенных методов преобразования массива, подобного массиву, в массив:
- Преобразование реализуется вызовом метода slice массива
Array.prototype.slice.call(arrayLike);
- Преобразование реализуется вызовом метода splice массива
Array.prototype.splice.call(arrayLike, 0);
- Преобразование реализуется вызовом метода concat массива с применением
Array.prototype.concat.apply([], arrayLike);
- Преобразование достигается методом Array.from
Array.from(arrayLike);
15. Разница между escape, encodeURI и encodeURIComponent
- encodeURI предназначен для экранирования всего URI и преобразования недопустимых символов в URI в допустимые символы, поэтому некоторые символы со специальным значением в URI не будут экранированы.
- encodeURIComponent экранирует компоненты URI, поэтому некоторые специальные символы также будут экранированы.
- Функции escape и encodeURI одинаковы, но они отличаются, когда Unicode кодируется как символ, отличный от 0xff. escape заключается в добавлении %u непосредственно перед кодировкой Unicode символа, а encodeURI сначала преобразует символ в UTF-8. format , за которым следует % перед каждым байтом.
16. Понимание AJAX, реализация AJAX-запроса
AJAX — это аббревиатура асинхронного JavaScript и XML, которая относится к асинхронному взаимодействию JavaScript, который получает XML-документы с сервера для извлечения данных, а затем обновляет соответствующую часть текущей веб-страницы без обновления всей веб-страницы.
Шаги для создания запроса AJAX:
- Создайте объект XMLHttpRequest.
- на этом объектеСоздайте HTTP-запрос, используя открытый метод, параметры, требуемые открытым методом, — это метод запроса, адрес запроса, является ли он асинхронным, а также информация об аутентификации пользователя.
- Перед инициированием запроса этот объект может бытьДобавьте некоторую информацию и функции слушателя. Например, вы можете добавить информацию заголовка к запросу с помощью метода setRequestHeader. Вы также можете добавить к этому объекту функцию слушателя состояния. Объект XMLHttpRequest имеет в общей сложности 5 состояний.При изменении его состояния будет инициировано событие onreadystatechange.Вы можете настроить функцию слушателя на обработку результата после успешного выполнения запроса. Когда readyState объекта становится 4, это означает, что данные, возвращенные сервером, получены.В это время можно судить о статусе запроса.Если статус 2xx или 304, это означает, что возврат нормальный. В это время страницу можно обновить с помощью данных в ответе.
- Когда свойства объекта и функция слушателя установлены, последний вызовИспользуйте метод send, чтобы инициировать запрос к серверу, вы можете передать параметры в качестве тела данных для отправки.
const SERVER_URL = "/server";
let xhr = new XMLHttpRequest();
// 创建 Http 请求
xhr.open("GET", url, true);
// 设置状态监听函数
xhr.onreadystatechange = function() {
if (this.readyState !== 4) return;
// 当请求成功时
if (this.status === 200) {
handle(this.response);
} else {
console.error(this.statusText);
}
};
// 设置请求失败时的监听函数
xhr.onerror = function() {
console.error(this.statusText);
};
// 设置请求头信息
xhr.responseType = "json";
xhr.setRequestHeader("Accept", "application/json");
// 发送 Http 请求
xhr.send(null);
Оберните ajax с обещанием:
// promise 封装实现:
function getJSON(url) {
// 创建一个 promise 对象
let promise = new Promise(function(resolve, reject) {
let xhr = new XMLHttpRequest();
// 新建一个 http 请求
xhr.open("GET", url, true);
// 设置状态的监听函数
xhr.onreadystatechange = function() {
if (this.readyState !== 4) return;
// 当请求成功或失败时,改变 promise 的状态
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
// 设置错误监听函数
xhr.onerror = function() {
reject(new Error(this.statusText));
};
// 设置响应的数据类型
xhr.responseType = "json";
// 设置请求头信息
xhr.setRequestHeader("Accept", "application/json");
// 发送 http 请求
xhr.send(null);
});
return promise;
}
17. Почему JavaScript выполняет подъем переменных и какие проблемы это вызывает?
Эффективность продвижения переменной заключается в том, что независимо от того, где переменная объявлена в функции, кажется, что она продвигается в начало функции и может быть доступна до того, как переменная будет объявлена без ошибки.
вызвать поднятие объявления переменнойсущественная причинаЭто то, что движок js имеет процесс разбора перед выполнением кода, создает контекст выполнения и инициализирует некоторые объекты, которые необходимы для выполнения кода. При обращении к переменной она будет искать в цепочке областей видимости в текущем контексте выполнения, а начало цепочки областей видимости указывает на объект переменной текущего контекста выполнения.Этот объект переменной является атрибутом контекста выполнения, который содержит функцию параметры, все объявления функций и переменных, этот объект создается при разборе кода.
Прежде всего, вам нужно знать, что когда JS получает переменную или функцию, будет два шага, а именно парсинг и выполнение.
-
на этапе разбора, JS проверит синтаксис и прекомпилирует функцию. При синтаксическом анализе сначала будет создан глобальный контекст выполнения, а переменные и объявления функций, которые будут выполняться в коде, будут вынесены в первую очередь, переменным будет присвоено значение undefined в первую очередь, а функции будут объявлены готовыми к использованию. Перед выполнением функции также создается контекст выполнения функции, аналогичный глобальному контексту выполнения, но контекст выполнения функции будет иметь дополнительные this, аргументы и параметры функции.
- Глобальный контекст: определения переменных, объявления функций
- Контекст функции: определения переменных, объявления функций, this, аргументы
- на этапе исполнения, то есть выполнять последовательно в порядке кода.
Так почему же выполняется переменный подъем? Есть две основные причины:
- Повысить производительность
- лучшая отказоустойчивость
(1) Повышение производительностиПеред выполнением кода JS выполняется проверка синтаксиса и предварительная компиляция, и эта операция выполняется только один раз. Это сделано для повышения производительности, без этого шага переменная (функция) должна быть разобрана еще раз перед выполнением кода, что лишнее, т.к. код переменной (функции) не изменится, достаточно разобрать ее еще раз.
Во время синтаксического анализа для функции также генерируется предварительно скомпилированный код. При прекомпиляции подсчитывает, какие переменные объявлены и какие функции создаются, и сжимает код функций, удаляя комментарии, ненужные пробелы и т.п. Преимущество этого в том, что каждый раз, когда функция выполняется, пространство стека может быть выделено непосредственно для функции (нет необходимости снова анализировать его, чтобы узнать, какие переменные объявлены в коде и какие функции созданы), и из-за сжатие кода, выполнение кода также быстрее.
(2) Лучшая отказоустойчивость
Продвижение переменных может в определенной степени повысить отказоустойчивость JS, см. следующий код:
a = 1;var a;console.log(a);
Без подъема переменных эти две строки кода сообщали бы об ошибке, но с подъемом переменных этот код может выполняться нормально.
Хотя в процессе разработки можно и вовсе не писать таким образом, но иногда код получается очень сложным. Он может быть использован сначала, а затем определен из-за небрежности, поэтому он не повлияет на нормальное использование. Он отлично работает из-за переменного подъема.
Суммировать:
- Улучшения объявления во время синтаксического анализа и предварительной компиляции могут повысить производительность, позволяя функциям предварительно выделять пространство стека для переменных во время выполнения.
- Продвижение объявлений также может повысить отказоустойчивость кода JS, чтобы некоторые нестандартные коды могли выполняться нормально.
Хоть продвижение переменных и имеет некоторые преимущества, оно также вызывает определенные проблемы.В ES6 для определения переменных предложены let и const, и у них нет механизма продвижения переменных. Давайте посмотрим на проблемы, которые может вызвать подъем переменных:
var tmp = new Date();
function fn(){
console.log(tmp);
if(false){
var tmp = 'hello world';
}
}
fn(); // undefined
В этой функции изначально должна была быть напечатана переменная tmp внешнего слоя, но из-за проблемы продвижения переменной tmp, определенная во внутреннем слое, была упомянута в верхней части функции, что эквивалентно покрытию tmp внешний слой, поэтому результат печати не определен.
var tmp = 'hello world';
for (var i = 0; i < tmp.length; i++) {
console.log(tmp[i]);
}
console.log(i); // 11
Поскольку i, определенное во время обхода, будет преобразовано в глобальную переменную и не будет уничтожено после завершения функции, выведите 11.
18. Что такое хвостовой вызов и каковы преимущества его использования?
Хвостовой вызов — это когда последний шаг функции вызывает другую функцию. Выполнение кода основано на стеке выполнения, поэтому, когда функция вызывается в другой функции, текущий контекст выполнения будет сохранен, а затем будет создан и добавлен в стек другой контекст выполнения. Если используется хвостовой вызов, потому что это уже последний шаг функции, нет необходимости сохранять текущий контекст выполнения в это время, тем самым экономя память.Это оптимизация хвостового вызова. Но оптимизация хвостовых вызовов ES6 включена только в строгом режиме, нормальный режим недействителен.
19. ES6модуль сCommonJSВ чем сходство и различие между модулями?
Разница между модулем ES6 и модулем CommonJS:
- CommonJS — это мелкая копия модуля, ES6 Module — это ссылка на модуль, то есть ES6 Module хранит только read-only, и его значение нельзя изменить, то есть нельзя изменить указатель, аналогично const;
- Интерфейс импорта доступен только для чтения (состояние только для чтения), и его значение переменной не может быть изменено. То есть указатель его переменной изменить нельзя, но можно изменить внутренний указатель переменной, а пару commonJS можно переназначить (изменить на указатель), но присваивание модулю ES6 скомпилирует ошибку.
Что общего между модулями ES6 и модулями CommonJS:
- И CommonJS, и ES6 Module могут присваивать значения импортируемым объектам, то есть изменять значения внутренних свойств объектов.
20. Каковы общие операции DOM
1) Приобретение узлов DOM
API узла DOM для получения и использования:
getElementById // 按照 id 查询
getElementsByTagName // 按照标签名查询
getElementsByClassName // 按照类名查询
querySelectorAll // 按照 css 选择器查询
// 按照 id 查询
var imooc = document.getElementById('imooc') // 查询到 id 为 imooc 的元素
// 按照标签名查询
var pList = document.getElementsByTagName('p') // 查询到标签为 p 的集合
console.log(divList.length)
console.log(divList[0])
// 按照类名查询
var moocList = document.getElementsByClassName('mooc') // 查询到类名为 mooc 的集合
// 按照 css 选择器查询
var pList = document.querySelectorAll('.mooc') // 查询到类名为 mooc 的集合
2) Создание узлов DOM
Создайте новый узел и добавьте его после указанного узла.Известная структура HTML выглядит следующим образом:
<html>
<head>
<title>DEMO</title>
</head>
<body>
<div id="container">
<h1 id="title">我是标题</h1>
</div>
</body>
</html>
Требуется добавить узел span с содержимым после узла, идентификатор которого — title, метод:
// 首先获取父节点
var container = document.getElementById('container')
// 创建新节点
var targetSpan = document.createElement('span')
// 设置 span 节点的内容
targetSpan.innerHTML = 'hello world'
// 把新创建的元素塞进父节点里去
container.appendChild(targetSpan)
3) Удаление узлов DOM
удалить указанный узел DOM,Известная структура HTML выглядит следующим образом:
<html>
<head>
<title>DEMO</title>
</head>
<body>
<div id="container">
<h1 id="title">我是标题</h1>
</div>
</body>
</html>
Чтобы удалить элемент с идентификатором title, метод таков:
// 获取目标元素的父元素
var container = document.getElementById('container')
// 获取目标元素
var targetNode = document.getElementById('title')
// 删除目标元素
container.removeChild(targetNode)
Или удалить через массив дочерних узлов:
// 获取目标元素的父元素var container = document.getElementById('container')// 获取目标元素var targetNode = container.childNodes[1]// 删除目标元素container.removeChild(targetNode)
4) Изменить элементы DOM
Действие по изменению элементов DOM можно разделить на множество измерений, таких как изменение положения элементов DOM, изменение атрибутов элементов DOM и т. д.
Поменяйте местами два указанных элемента DOM,Известная структура HTML выглядит следующим образом:
<html>
<head>
<title>DEMO</title>
</head>
<body>
<div id="container">
<h1 id="title">我是标题</h1>
<p id="content">我是内容</p>
</div>
</body>
</html>
Теперь вам нужно изменить расположение Title и Content, вы можете рассмотреть INSERTBEFORE или APPENDCHILD:
// 获取父元素
var container = document.getElementById('container')
// 获取两个需要被交换的元素
var title = document.getElementById('title')
var content = document.getElementById('content')
// 交换两个元素,把 content 置于 title 前面
container.insertBefore(content, title)
21. Что такое use strict mean? В чем разница между его использованием?
use strict — это режим выполнения (строгий режим), добавленный ECMAscript5, который заставляет Javascript выполняться в более строгих условиях. Цель установления строгого режима заключается в следующем:
- Устраните необоснованный и неточный синтаксис Javascript и уменьшите странное поведение;
- Устранить небезопасность работы кода и обеспечить безопасность работы кода;
- Улучшить эффективность компилятора и увеличить скорость работы;
- Заложите основу для будущих новых версий Javascript.
разница:
- Использование оператора with запрещено.
- Ключевому слову this запрещено указывать на глобальный объект.
- Объекты не могут иметь свойства с одинаковыми именами.
22. Как узнать, принадлежит ли объект определенному классу?
- Первый способ — использовать оператор instanceof, чтобы определить, появляется ли свойство прототипа конструктора где-либо в цепочке прототипов объекта.
- Второй способ — судить по свойству конструктора объекта, свойство конструктора объекта указывает на конструктор объекта, но этот способ не очень безопасен, так как свойство конструктора можно переписать.
- Третий способ: если вам нужно оценить встроенный ссылочный тип, вы можете использовать метод Object.prototype.toString() для вывода свойства [[Class]] объекта для оценки.
23. Разница между строго типизированными и слабо типизированными языками
- строго типизированный язык: Строго типизированный язык, также известный как строго типизированный язык, — это язык, который всегда применяет определения типов, требуя, чтобы использование переменных строго соответствовало определению, и все переменные должны быть определены перед использованием. Такие языки, как Java и C++, являются обязательными определениями типов, то есть, если переменной присваивается тип данных, если она не приведена, она всегда будет иметь этот тип данных. Например, у вас есть целое число, вы не можете рассматривать его как строку без явного преобразования.
- слабо типизированный язык: Слабо типизированные языки также известны как слабо типизированные языки, в отличие от строго типизированных определений. JavaScript — слабо типизированный язык. Простое понимание — это язык, в котором типы переменных можно игнорировать. Например, JavaScript определяется слабыми типами, в JavaScript строку «12» и целое число 3 можно объединить, чтобы получить строку «123», и при добавлении будет выполнено преобразование типов.
Сравнение двух: языки со строгой типизацией могут быть немного медленнее, чем языки со слабой типизацией, но строгость, привносимая языками со строгой типизацией, может эффективно помочь избежать многих ошибок.
24. Разница между интерпретируемым и компилируемым языками
(1) Интерпретируемый язык Воспользуйтесь специальным интерпретатором, чтобы интерпретировать исходную программу построчно в машинный код для конкретной платформы и немедленно выполнить ее. Это код, который динамически транслируется и выполняется интерпретатором построчно по мере его выполнения, а не перед выполнением. Интерпретируемый язык не нужно компилировать заранее, он напрямую интерпретирует исходный код в машинный код и немедленно его выполняет, поэтому, пока определенная платформа предоставляет соответствующий интерпретатор, программа может быть запущена. Его характеристики резюмируются следующим образом
- Интерпретируемый язык должен интерпретировать исходный код в машинный код и выполнять его при каждом запуске, что менее эффективно;
- Пока платформа предоставляет соответствующий интерпретатор, исходный код может быть запущен, что удобно для переноса исходной программы;
- JavaScript, Python и т. д. являются интерпретируемыми языками.
(2) Компилируемый язык С помощью специального компилятора для конкретной платформы исходный код языка высокого уровня один раз компилируется в машинный код, который может выполняться аппаратным обеспечением платформы, и упаковывается в формат исполняемой программы, распознаваемый платформой. Перед выполнением программы, написанной на скомпилированном языке, требуется специальный процесс компиляции для компиляции исходного кода в файл на машинном языке, например файл в формате exe.При последующем запуске вы можете напрямую использовать результат компиляции, например, прямой запуск exe.document. Компилируемые языки очень эффективны, потому что их нужно скомпилировать только один раз, а затем запустить без компиляции. Его характеристики резюмируются следующим образом:
- Он одновременно скомпилирован в файлы машинного языка, связанные с платформой, а среда выполнения отделена от среды разработки, а эффективность работы высока;
- Он связан с конкретной платформой и, как правило, не может быть перенесен на другие платформы;
- C, C ++ и т. Д. Для скомпилированного языка.
Основное различие между ними заключается в следующем:Первая исходная программа может быть запущена на платформе после компиляции, а вторая компилируется во время работы. Таким образом, первый работает быстро, а второй имеет хорошую кроссплатформенную производительность.
25. Разница между for...in и for...of
for...of — это новый метод обхода в ES6, который позволяет проходить структуру данных (массив, объект и т. д.) с помощью интерфейса итератора и возвращать значение каждого элемента Отличие от for...in в ES3 составляет
- For...of traversal получает значение ключа объекта, а for...in получает имя ключа объекта;
- for... in пройдёт всю цепочку прототипов объекта, производительность очень низкая и не рекомендуется, а for... of пройдёт только текущий объект и не пройдёт цепочку прототипов;
- Для обхода массива для ... в ... Вне обратится все перечисленные свойства в массиве (включая перечисленные свойства на цепочке прототипа), для ... только возвращает значение атрибута, соответствующего индивидуальному заказу массива;
Суммировать:Цикл for...in в основном предназначен для обхода объектов, а не для обхода массивов; циклы for...of можно использовать для обхода массивов, массивоподобных объектов, строк, объектов Set, Map и Generator.
26. Как перебирать объекты, используя for...of
for...of — это новый метод обхода в ES6, который позволяет проходить структуру данных (массив, объект и т. д.), содержащую интерфейс итератора, и возвращать значение каждого элемента.Обычный обход объекта с помощью for..of будет сообщить об ошибке.
Если объект, который необходимо обойти, представляет собой массивоподобный объект, используйте Array.from, чтобы преобразовать его в массив.
var obj = {
0:'one',
1:'two',
length: 2
};
obj = Array.from(obj);
for(var k of obj){
console.log(k)
}
Если это не массивоподобный объект, добавьте к объекту свойство [Symbol.iterator] и укажите на итератор.
//方法一:
var obj = {
a:1,
b:2,
c:3
};
obj[Symbol.iterator] = function(){
var keys = Object.keys(this);
var count = 0;
return {
next(){
if(count<keys.length){
return {value: obj[keys[count++]],done:false};
}else{
return {value:undefined,done:true};
}
}
}
};
for(var k of obj){
console.log(k);
}
// 方法二
var obj = {
a:1,
b:2,
c:3
};
obj[Symbol.iterator] = function*(){
var keys = Object.keys(obj);
for(var k of keys){
yield [k,obj[k]]
}
};
for(var [k,v] of obj){
console.log(k,v);
}
27. Разница между ajax, axios и fetch
(1) АЯКСAjax, «AsynchronousJavascriptAndXML» (асинхронный JavaScript и XML), относится к технологии веб-разработки для создания интерактивных веб-приложений. Это технология, которая может обновлять части веб-страницы без перезагрузки всей веб-страницы. Ajax позволяет асинхронно обновлять веб-страницы, обмениваясь небольшими объемами данных с сервером в фоновом режиме. Это означает, что части страницы могут быть обновлены без перезагрузки всей страницы. Традиционные веб-страницы (без Ajax) должны перезагружать всю веб-страницу, если необходимо обновить содержимое. Его недостатки заключаются в следующем:
- Это для самого программирования MVC, а не в соответствии с волной внешнего интерфейса MVVM.
- Основанная на собственной разработке XHR, сама архитектура XHR не ясна.
- Не соответствует принципу разделения интересов
- Конфигурация и вызов очень запутаны, и модель Async на основе событий не является дружественным.
(2) ПринестиFetch утверждает, что является альтернативой AJAX, который появился в ES6 и использует объект обещания в ES6. Fetch разработан на основе промисов. Структура кода Fetch намного проще, чем у ajax.Fetch — это не дальнейшая инкапсуляция ajax, а собственный js без использования объекта XMLHttpRequest..
Преимущества получения:
- Лаконичный синтаксис, более семантический
- Основываясь на внедрении стандартного обещания, поддержать Async / ждать
- Более слаборазвитый, предлагает богатый API (запрос, ответ)
- Из XHR это новая реализация в спецификации ES.
Недостатки получения:
- Fetch сообщает об ошибках только в сетевых запросах, 400 и 500 считаются успешными запросами, и сервер не будет отклонять, когда сервер возвращает коды ошибок 400 и 500. Только когда сетевые ошибки приводят к сбою запроса, выборка будет отклонена.
- По умолчанию Fetch не будет получать файлы cookie, вам нужно добавить элементы конфигурации: fetch(url, {credentials: 'include'})
- Fetch не поддерживает прерывание и не поддерживает управление тайм-аутом.Контроль тайм-аута, реализованный с помощью setTimeout и Promise.reject, не может предотвратить продолжение выполнения процесса запроса в фоновом режиме, что приводит к пустой трате трафика.
- Fetch не имеет встроенной возможности отслеживать ход выполнения запроса, в то время как XHR может
(3) АксиосAxios — это HTTP-клиент на основе Promise со следующими функциями:
- Сторона браузера инициирует запрос XMLHttpRequests.
- Сторона узла инициирует http-запрос
- Обещанная поддержка API
- Прослушивание запросов и возвратов
- Преобразование запросов и возвратов
- отменить запрос
- Автоматически конвертировать данные json
- Поддержка клиентов против XSRF-атак
28. Какие существуют методы обхода массива
метод | следует ли изменить исходный массив | Функции |
---|---|---|
forEach() | нет | Метод массива, не изменяет исходный массив, не возвращает значение |
map() | нет | Метод массива, не изменяет исходный массив, имеет возвращаемое значение и может вызываться в цепочке |
filter() | нет | Метод массива, фильтрует массив, возвращает массив, содержащий элементы, удовлетворяющие условию, может вызываться по цепочке |
for...of | нет | for...of проходит свойства объекта с помощью итератора Iterator и возвращает элементы массива и значения свойств объекта.Он не может проходить обычные объекты obj, превращая асинхронный цикл в синхронный цикл |
каждый () и некоторые () | нет | Метод массива, some() возвращает true, если хотя бы одно из них истинно, а every() возвращает false, если хотя бы одно из них ложно. |
найти() и найтииндекс() | нет | Метод массива, find() возвращает первое значение, удовлетворяющее условию; findIndex() возвращает значение индекса первого значения, которое возвращает условие |
уменьшить() и уменьшитьПраво() | нет | Метод массива, reduce() работает с массивом в положительном порядке; reduceRight() работает с обратным порядком массива. |
Подробное объяснение метода обхода:«Обратный отсчет этих обходов и циклов в JavaScript»
29. В чем разница между методами forEach и map
Этот метод используется для обхода массива, разница между ними заключается в следующем:
- Метод forEach() выполнит предоставленную функцию для каждого элемента, а операция над данными изменит исходный массив, и этот метод не имеет возвращаемого значения;
- Метод map() не изменяет значение исходного массива, а возвращает новый массив, а значение в новом массиве — это значение, обработанное вызывающей функцией исходного массива;
4. Прототип и цепочка прототипов
1. Понимание прототипа и цепочки прототипов
В JavaScript конструктор используется для создания нового объекта. Каждый конструктор имеет внутри свойство прототипа, а его значением свойства является объект. Этот объект содержит свойства и методы, которые могут быть общими для всех экземпляров конструктора. Когда конструктор используется для создания нового объекта, объект будет содержать указатель, указывающий на значение, соответствующее свойству прототипа конструктора.В ES5 этот указатель называется прототипом объекта. Вообще говоря, это значение нельзя было получить, но теперь оно реализовано в браузерах.protoсвойство для доступа к этому свойству, но лучше не использовать это свойство, так как оно не указано в спецификации. В ES5 добавлен новый метод Object.getPrototypeOf(), который можно использовать для получения прототипа объекта.
При доступе к свойству объекта, если свойство не существует в объекте, то он перейдет к своему объекту-прототипу, чтобы найти свойство, а объект-прототип будет иметь свой собственный прототип, поэтому он продолжает искать его, то есть , Концепция цепи прототипа. Концом цепочки прототипов обычно является Object.prototype, поэтому вновь создаваемые объекты могут использовать такие методы, как toString().
Функции:Объекты JavaScript передаются по ссылке, и каждый новый созданный объект не имеет собственной копии прототипа. При изменении прототипа связанные с ним объекты также наследуют изменения.
2. Модификация прототипа, перезапись
function Person(name) {
this.name = name
}
// 修改原型
Person.prototype.getName = function() {}
var p = new Person('hello')
console.log(p.__proto__ === Person.prototype) // true
console.log(p.__proto__ === p.constructor.prototype) // true
// 重写原型
Person.prototype = {
getName: function() {}
}
var p = new Person('hello')
console.log(p.__proto__ === Person.prototype) // true
console.log(p.__proto__ === p.constructor.prototype) // false
Можно видеть, что конструктор p не указывает на Person при изменении прототипа, потому что, когда объект-прототип Person напрямую присваивается объекту, его конструктор указывает на корневой конструктор Object, поэтому в настоящее времяp.constructor === Object
, вместоp.constructor === Person
. Чтобы настроить, используйте конструктор, чтобы указать его обратно:
Person.prototype = {
getName: function() {}
}
var p = new Person('hello')
p.constructor = Person
console.log(p.__proto__ === Person.prototype) // true
console.log(p.__proto__ === p.constructor.prototype) // true
3. Цепочка прототипов указывает на
p.__proto__ // Person.prototype
Person.prototype.__proto__ // Object.prototype
p.__proto__.__proto__ //Object.prototype
p.__proto__.constructor.prototype.__proto__ // Object.prototype
Person.prototype.constructor.prototype.__proto__ // Object.prototype
p1.__proto__.constructor // Person
Person.prototype.constructor // Person
4. Что является конечной точкой цепочки прототипов? Как распечатать конечную точку цепочки прототипов?
из-заObject
является конструктором, а конечная точка цепочки прототиповObject.prototype.__proto__
,а такжеObject.prototype.__proto__=== null // true
, поэтому конечная точка цепочки прототиповnull
. Все прототипы в цепочке прототипов являются объектами, и все объекты в конечном итоге создаютсяObject
построен, иObject.prototype
Следующий уровеньObject.prototype.__proto__
.
5. Как получить свойства непрототипной цепочки объекта?
После использованияhasOwnProperty()
метод, чтобы определить, является ли свойство частью цепочки прототипов:
function iterate(obj){
var res=[];
for(var key in obj){
if(obj.hasOwnProperty(key))
res.push(key+': '+obj[key]);
}
return res;
}
5. Контекст выполнения/цепочка областей/замыкание
1. Понимание замыканий
Замыкание — это функция, которая имеет доступ к переменной в области видимости другой функции., наиболее распространенным способом создания замыкания является создание другой функции внутри функции, и созданная функция может получить доступ к локальным переменным текущей функции.
Замыкания имеют два распространенных применения;
- Первое использование замыканий — позволить нам получить доступ к переменным внутри функции извне функции. Используя замыкание, вы можете получить доступ к переменным внутри функции извне, вызвав функцию замыкания извне.Вы можете использовать этот метод для создания закрытых переменных.
- Другим применением замыкания является сохранение объекта переменной в контексте функции, которая завершила выполнение в памяти.Поскольку функция закрытия сохраняет ссылку на объект переменной, объект переменной не будет повторно использован.
Например, если внутри функции A есть функция B, и функция B может получить доступ к переменным в функции A, то функция B является замыканием.
function A() {
let a = 1
window.B = function () {
console.log(a)
}
}
A()
B() // 1
В JS значение замыканий заключается в том, чтобы позволить нам косвенно обращаться к переменным внутри функций. Классический вопрос на собеседовании: использование замыканий в циклах для решения проблемы var, определяющей функции
for (var i = 1; i <= 5; i++) {
setTimeout(function timer() {
console.log(i)
}, i * 1000)
}
Во-первых, потому чтоsetTimeout
Это асинхронная функция, поэтому все циклы будут выполняться первыми.i
Это 6, поэтому он выведет кучу из 6. Есть три решения:
- Во-первых, это использование замыканий.
for (var i = 1; i <= 5; i++) { ;(function(j) { setTimeout(function timer() { console.log(j) }, j * 1000) })(i)}
В приведенном выше коде функция немедленного выполнения сначала используется дляi
Передал в функцию, на этот раз значение фиксируется в параметреj
Вышеупомянутое не изменится при следующем выполненииtimer
При этом замыкании можно использовать переменные внешней функцииj
, чтобы достичь цели.
- Второй заключается в использовании
setTimeout
Третий параметр , этот параметр будет рассматриваться какtimer
Передаются параметры функции.
for (var i = 1; i <= 5; i++) {
setTimeout(
function timer(j) {
console.log(j)
},
i * 1000,
i
)
}
- В-третьих, использовать
let
определениеi
Приходите, чтобы решить проблему, это также самый рекомендуемый способ
for (let i = 1; i <= 5; i++) {
setTimeout(function timer() {
console.log(i)
}, i * 1000)
}
2. Понимание масштаба и цепочки масштабов
1) Глобальный объем и объем функций
(1) Глобальный охват
- Самая внешняя функция и переменные, определенные за пределами самой внешней функции, имеют глобальную область видимости.
- Все переменные с неопределенным прямым назначением автоматически объявляются глобальными.
- Все свойства объекта окна имеют глобальную область видимости.
- У глобальной области видимости есть большие недостатки: слишком много переменных глобальной области видимости загрязняют глобальное пространство имен и легко вызывают конфликты имен.
(2) Объем функций
- Объявление области действия функции становится нулевым внутри функции, обычно только фиксированные фрагменты кода могут получить к нему доступ.
- Области иерархичны, внутренние области могут иметь доступ к внешним областям, но не наоборот.
2) Область блока
- Используйте новые директивы let и const в ES6 для объявления области на уровне блока. Область на уровне блока может быть создана в функции или в блоке кода (с помощью
{ }
завернутый фрагмент кода) - Переменные, объявленные с помощью let и const, не будут иметь подъема переменных и не могут быть объявлены повторно.
- Лучше связать область на уровне блока в цикле, чтобы объявленная переменная-счетчик могла быть ограничена внутри цикла.
Цепочка охвата:Найдите требуемую переменную в текущей области видимости, но в области видимости нет переменной, значит переменная является свободной переменной. Если вы не можете найти переменную в своей области, перейдите в родительскую область для поиска, а затем поочередно ищите в области верхнего уровня, пока не будет получен доступ к объекту окна и он не будет завершен. Отношение уровня - это цепочка областей видимости.
Роль цепочки областей видимостиОбеспечьте упорядоченный доступ ко всем переменным и функциям, к которым имеет доступ среда выполнения.Через цепочку областей можно получить доступ к переменным и функциям во внешней среде.
Цепочка областей видимости — это, по сути, список указателей на переменные объекты. Переменный объект — это объект, который содержит все переменные и функции в среде выполнения. Передний конец цепочки областей всегда является переменным объектом текущего контекста выполнения. Переменный объект глобального контекста выполнения (то есть глобальный объект) всегда является последним объектом в цепочке областей видимости.
При поиске переменной, если она не найдена в текущей среде выполнения, ее можно искать в обратном направлении по цепочке областей видимости.
3. Понимание контекста выполнения
1. Тип контекста выполнения
(1) Глобальный контекст выполнения
Все, что не находится внутри функции, является глобальным контекстом выполнения.Сначала она создает глобальный объект окна и устанавливает значение this равным этому глобальному объекту.В программе существует только один глобальный контекст выполнения.
(2) Контекст выполнения функции
Когда функция вызывается, для функции создается новый контекст выполнения, и может быть любое количество контекстов для функции.
(3)eval
контекст выполнения функции
Код, выполняемый в функции eval, будет иметь свой собственный контекст выполнения, но функция eval используется нечасто и не будет представлена.
2. Стек контекста выполнения
- Механизмы JavaScript используют стек контекста выполнения для управления контекстами выполнения.
- Когда JavaScript выполняет код, он сначала сталкивается с глобальным кодом, создает глобальный контекст выполнения и помещает его в стек выполнения. Всякий раз, когда встречается вызов функции, для функции создается новый контекст выполнения, который помещается на вершину стека. Engine выполнит функцию в верхней части стека контекста выполнения.Когда выполнение функции завершено, контекст выполнения выталкивается из стека и продолжает выполнять следующий контекст. Когда весь код выполнен, глобальный контекст выполнения извлекается из стека.
let a = 'Hello World!';
function first() {
console.log('Inside first function');
second();
console.log('Again inside first function');
}
function second() {
console.log('Inside second function');
}
first();
//执行顺序
//先执行second(),在执行first()
3. Создайте контекст выполнения
Существует две фазы создания контекста выполнения:создать сценуа такжеэтап выполнения
1) Этап создания
(1) эта привязка
- В глобальном контексте выполнения это указывает на глобальный объект (объект окна)
- В контексте выполнения функции указатель this зависит от того, как была вызвана функция. Если он вызывается для ссылочного объекта, это будет установлено на этот объект, в противном случае значение этого будет установлено на глобальный объект или не определено
(2) Создайте компонент лексического окружения
- Лексическая среда - этоИдентификатор-переменное отображениеСтруктура данных, идентификатор относится к имени переменной/функции, а переменная является ссылкой на фактический объект или необработанные данные.
- Внутри лексического окружения есть два компонента:смелый стиль: регистратор среды: используется для хранения фактического местоположения объявлений переменных и функций.ссылка на внешнюю среду: имеет доступ к родительской области
(3) Создание переменных компонентов среды
- Среда переменных также является лексической средой, регистратор среды которой содержит привязки, созданные оператором объявления переменной в контексте выполнения.
2) Этап исполненияНа этом этапе завершается назначение переменных и, наконец, выполняется код.
Проще говоря, контекст выполнения относится к:
Перед выполнением кода JS код необходимо проанализировать. При синтаксическом анализе сначала будет создан глобальный контекст выполнения, а переменные и объявления функций, которые будут выполняться в коде, будут вынесены в первую очередь, переменным будет присвоено значение undefined в первую очередь, а функции будут объявлены готовыми к использованию. После завершения этого шага начинается формальная процедура исполнения.
Перед выполнением функции также создается контекст выполнения функции, аналогичный глобальному контексту выполнения, но контекст выполнения функции будет иметь дополнительные this, аргументы и параметры функции.
- Глобальный контекст: определения переменных, объявления функций
- Контекст функции: определения переменных, объявления функций,
this
,arguments
Примечание:Из-за ограничения на количество слов остальная часть содержания будет кратко изложена в следующей главе.