1: Тип и метод обнаружения
1: встроенные типы данных js
js тип данных, как показано ниже
javascriptВсего существует 8 типов данных, из которых 7 основных типов данных:Null,Undefiend,Boolen,String,Number,Symbol(Новое в es6, создайте уникальное значение),BigInt(Новое в es10); также есть ссылочный тип данных: Object (Object — это, по сути, неупорядоченный набор пар ключ-значение) содержит обычные объекты —Object, объект массива -Array, обычный объект -RegExp, объект даты -Date, математическая функция -Math, объект функции -Function
Поскольку различные типы данных javascript в конечном итоге будут помещены в разную память после инициализации, вышеуказанные типы данных можно условно разделить на две категории:
- Примитивный тип данных: базовый тип хранится в стеке, при ссылке или копировании на него будет создана полностью равная переменная, занимает мало места и имеет фиксированный размер, это часто используемые данные, поэтому хранится в стек.
- Тип справочных данных: Тип справочных данных хранится в куче памяти, а адрес сохраняется. Несколько ссылок указывают на один и тот же адрес. Здесь будет разработана концепция «совместного использования», которая занимает большое пространство и размер не фиксированный. Ссылочный тип хранит в стеке указатель, указывающий на начало объекта в куче. Когда интерпретатор ищет ссылочное значение, он сначала извлекает его адрес в стеке, а затем получает сущность из кучи после получения адреса.
Как данные в JavaScript хранятся в памяти?
在 JavaScript 中,原始类型的赋值会完整复制变量值,而引用类型的赋值是复制引用地址。В процессе выполнения JavaScript в основном используются три типа пространства памяти, а именно代码空间,栈空间,堆空间. Кодовое пространство в основном предназначено для хранения исполняемого кода.Значения данных примитивных типов (Number, String, Null, Undefined, Boolean, Symbol, BigInt) хранятся непосредственно в «стеке», а значения ссылочного типа (Object ) хранится в «куче». Поэтому в пространстве стека (контексте выполнения) исходный тип хранит значение переменной, а ссылочный тип хранит свой адрес в «пространстве кучи». Доступ по адресу эквивалентен дополнительному процессу перехода из рук в руки.
В процессе компиляции, если движок JavaScript определяет замыкание, он также создает объект «closure(fn)» в пространстве кучи (это внутренний объект, к которому JavaScript не может получить доступ), который используется для сохранения замыкания в Переменные. Таким образом, переменные в замыкании хранятся в «куче».
Движок JavaScript должен использовать стек для поддержания состояния контекста во время выполнения программы.Если пространство стека велико, все данные хранятся в пространстве стека, что повлияет на эффективность переключения контекста, что, в свою очередь, повлияет на выполнение эффективность всей программы. В нормальных условиях пространство стека не слишком велико и в основном используется для хранения небольших данных примитивных типов. Данные ссылочного типа занимают много места, поэтому данные этого типа будут храниться в куче. Пространство кучи велико и может хранить много больших данных. Однако недостатком является то, что выделение и освобождение памяти займет определенное время. количество времени. Следовательно, требуется пространство как «стек», так и «куча».
2. Определение типа данных
(1) тип
typeof对于原始类型来说,除了null都可以显示正确的
console.log(typeof 2); // number
console.log(typeof true); // boolean
console.log(typeof 'str'); // string
console.log(typeof []); // object []数组的数据类型在 typeof 被解释为object
console.log(typeof function(){}); // function
console.log(typeof {}); // object
console.log(typeof undefined); // undefined
console.log(typeof null); // object null 的数据类型被 typeof 解释为 object
typeof 对于对象来说,除了函数都会显示 object,所以说 typeof 并不能准确判断变量到底是什么类型,所以想判断一个对象的正确类型,这时候可以考虑使用 instanceof
(2) экземпляр
instanceof 可以正确的判断对象的类型,因为内部机制是通过判断对象的原型链中是不是能找到类型的 prototype
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
// console.log(undefined instanceof Undefined);
// console.log(null instanceof Null);
- instanceof может точно оценивать сложные справочные типы данных, но не может правильно оценивать базовые типы данных;
- У typeof тоже есть недостатки: хотя он может судить об основном типе данных (кроме null), ссылочный тип данных нельзя судить, кроме типа функции.
реализовать instanceof
function instanceof (left, right) {
// 获取类型的原型
let prototype = right.prototype
// 判断数据类型
while (true) {
// 获取对象的原型
left = left.__proto__
if (left === null) return false
if (prototype === left) return true
}
}
(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就会变得不可靠了
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()
toString() 是 Object 的原型方法,调用该方法,可以统一返回格式为 “[object Xxx]” 的字符串,其中 Xxx 就是对象的类型。对于 Object 对象,直接调用 toString() 就能返回 [object Object];而对于其他对象,则需要通过 call 来调用,才能返回正确的类型信息。我们来看一下代码。
Object.prototype.toString({}) // "[object Object]"
Object.prototype.toString.call({}) // "[object Object]"
Object.prototype.toString.call(1) // "[object Number]"
Object.prototype.toString.call('1') // "[object String]"
Object.prototype.toString.call(true) // "[object Boolean]"
Object.prototype.toString.call(function(){}) // "[object Function]"
Object.prototype.toString.call(null) //"[object Null]"
Object.prototype.toString.call(undefined) //"[object Undefined]"
Object.prototype.toString.call(/123/g) //"[object RegExp]"
Object.prototype.toString.call(new Date()) //"[object Date]"
Object.prototype.toString.call([]) //"[object Array]"
Object.prototype.toString.call(document) //"[object HTMLDocument]"
Object.prototype.toString.call(window) //"[object Window]"
Реализовать глобально общий метод определения типа данных
function getType(obj){
let type = typeof obj;
if (type !== "object") { // 先进行typeof判断,如果是基础数据类型,直接返回
return type;
}
// 对于typeof返回结果是object的,再进行如下的判断,正则返回结果
return Object.prototype.toString.call(obj).replace(/^\[object (\S+)\]$/, '$1'); // 注意正则中间有个空格
}
(5) Резюме
- typeof
- Обнаружение на основе значения типа данных (бинарный) прямо в нижней части компьютера
- Причина, по которой typeof null является объектом, заключается в том, что объект существует на компьютере и хранится в двоичном формате, начиная с 000, поэтому обнаруженный результат является объектом
- typeof обычные объекты/объекты массива/обычные объекты/объекты даты - все объекты
- typeof NaN === 'number'
- instanceof
- Проверить, принадлежит ли текущий экземпляр этому классу
- Базовый механизм: пока текущий класс появляется в прототипе экземпляра, результат верен.
- Невозможно обнаружить примитивные типы данных
- constructor
- Поддержка основных типов
- Конструктор может быть изменен по желанию, и это не допускается
- Object.prototype.toString.call([val])
- Возвращает информацию о классе текущего экземпляра
2: Это
1: прямо на картинке
3: Принцип применения/вызова/привязки
Здесь вы можете сослаться на мою другую статью:Наггетс.Талант/пост/698169…
4: Вариативное продвижение
当执行 JS 代码时,会生成执行环境,只要代码不是写在函数中的,就是在全局执行环境中,函数中的代码会产生函数执行环境,只此两种执行环境。
func() // call func
console.log(code) // undefined
var code = 'Hello world'
function func() {
console.log('call func')
}
Вы должны были понять приведенный выше вывод, это из-за продвижения функций и переменных. Обычным объяснением повышения является перемещение заявленного кода наверх, что на самом деле не является неправильным и понятным для всех. Но более точное объяснение должно быть таким: при создании среды выполнения есть две фазы. Первый этап - этап создания.JS-интерпретатор выяснит переменные и функции, которые нужно продвигать, и заранее освободит место в памяти для них.Если функция является функцией, вся функция будет сохранена в память.Переменная только объявлена и назначена как неопределенная, поэтому на втором этапе, который является этапом выполнения кода, мы можем использовать его непосредственно заранее
var может генерировать много ошибок, поэтому let был введен в ES6. let нельзя использовать перед объявлением, но об этом не часто говорят, что let не будет продвигаться, пусть продвигается, и память уже освободила место для него на первом этапе, но из-за особенностей этого объявления нельзя используется перед объявлением.
5: Закрытие
На самом деле замыкание — это функция, которая может обращаться к переменным внутри других функций. Самый распространенный способ создания замыкания — создать функцию внутри другой функции, при этом созданная функция может обращаться к локальным переменным текущей функции.
Как это обычно бывает, функция внутренних переменных (то есть разница между глобальными переменными и локальными переменными) не может быть доступна извне, использование роли замыкания, реализованная функция может получить доступ к функции внутренних переменных снаружи, чтобы эти значения внутренних переменных всегда можно было хранить в памяти
function fun1() {
var a = 1;
return function(){
console.log(a);
};
}
fun1();
var result = fun1();
result(); // 1
// 结合闭包的概念,我们把这段代码放到控制台执行一下,就可以发现最后输出的结果是 1(即 a 变量的值)。那么可以很清楚地发现,a 变量作为一个 fun1 函数的内部变量,正常情况下作为函数内的局部变量,是无法被外部访问到的。但是通过闭包,我们最后还是可以拿到 a 变量的值
1: замыкание имеют два обычных использования
-
Первое использование замыканий — позволить нам получить доступ к переменным внутри функции извне функции. Используя замыкания, мы можем получить доступ к переменным внутри функции извне, вызвав функцию замыкания извне, и мы можем использовать этот метод для создания закрытых переменных.
-
Другая цель функции состоит в том, чтобы сохранить переменный объект в контексте функции, которая завершила выполнение в памяти.Поскольку функция закрытия сохраняет ссылку на переменный объект, переменный объект не будет повторно использован.
2: Как замыкания хранят данные
О реализации замыкания и защиты от встряски см. в этой статье:Наггетс.Талант/пост/698130…
6: Принцип Нового
Вот еще одна статья для ознакомления:Наггетс.Талант/пост/698172…
7: Прототип/цепочка прототипов
__proto__а такжеprototypeсвязь:__proto__а такжеconstructorявляется уникальным для объекта.prototypeСвойства уникальны для функций
В js мы используем конструктор для создания нового объекта.Каждый конструктор имеет внутри значение свойства прототипа.Это значение свойства является объектом, который содержит свойства, которые могут быть общими для всех экземпляров конструктора и метода. Когда мы используем конструктор для создания нового объекта, объект будет содержать указатель, который указывает на значение, соответствующее свойству прототипа конструктора, В ES5 этот указатель называется прототипом объекта. Вообще говоря, у нас не должно быть возможности получить это значение, но теперь браузеры реализуют атрибут proto, чтобы мы могли получить доступ к этому атрибуту, но нам лучше не использовать этот атрибут, потому что он не указан в спецификации. В ES5 был добавлен новый метод Object.getPrototypeOf(), и мы можем использовать этот метод для получения прототипа объекта.
Когда мы получаем доступ к свойству объекта, если свойство не существует в объекте, то оно обращается к своему объекту-прототипу, чтобы найти это свойство, а у объекта-прототипа будет свой собственный прототип, поэтому мы продолжаем его искать. это концепция цепочки прототипов. Концом цепочки прототипов обычно является Object.prototype, поэтому наши вновь созданные объекты могут использовать такие методы, как toString().
- Каждая функция имеет свойство прототипа, кроме Function.prototype.bind(), которое указывает на прототип.
- Каждый объект имеетprotoСвойство, указывающее на прототип конструктора, создавшего объект. На самом деле это свойство указывает на [[prototype]], но [[prototype]] — это внутреннее свойство, к которому мы не можем получить доступ, поэтому мы используем _proto_ для доступа к нему.
- объекты могут бытьprotoнайти свойства, которые не принадлежат объекту,protoСоединение объектов вместе образует цепочку прототипов.
8: Механизм событий
1. Введение
Поток событий — это процесс, посредством которого события распространяются по определенной структуре данных. Всплывание и перехват — это два разных метода распространения потока событий в DOM.
Поток событий состоит из трех этапов.
- этап захвата событий
- на целевой стадии
- фаза всплытия события
захват событий
Захват событий: общепринятое понимание состоит в том, что когда мышь щелкает или запускает событие dom, браузер запускается с корневого узла, чтобы распространить событие снаружи внутрь, то есть щелкнуть дочерний элемент, если родительский элемент регистрируется с помощью метода захвата событий. Если есть соответствующее событие, событие, привязанное к родительскому элементу, будет инициировано первым.
всплывающее окно события
Всплывающие события (дублированные всплывающие сообщения): в отличие от захвата событий, последовательность всплывающих событий представляет собой распространение событий изнутри наружу до корневого узла.
Будь то захват событий или пузырька событий, все они имеют общее поведение, которое является распространением событий
2. Захват и пузырь
<div id="el1">
<div id="el2"></div>
</div>
<script>
let div1 = document.getElementById('el1');
let div2 = document.getElementById('el2');
div1.onClick = function(){
alert('get el1')
}
div2.onClick = function(){
alert('get el12');
}
</script>
При нажатии на div2 появляются два всплывающих окна. В браузерах ie8/9/10 и chrome сначала появится цифра 2, а затем цифра 1. Это всплывающая подсказка событий: события всплывают из нижнего узла. Захват событий — это противоположность пузырьковому воспроизведению событий.
Стандарт W3C заключается в том, чтобы сначала захватывать, а затем всплывать Третий параметр addEventListener определяет, зарегистрировано ли событие в захвате (true) или всплытии (false).
3. Объект события
4. Блокировка потока событий
В некоторых случаях необходимо предотвратить распространение потока событий и предотвратить возникновение действий по умолчанию.
- event.preventDefault(): отменить действие объекта события по умолчанию и продолжить распространение.
- event.stopPropagation()/ event.cancelBubble = true: Остановить всплывающую подсказку события.
Блокировка событий обрабатывается по-разному в разных браузерах.
- Используйте event.returnValue= false в IE
- В не-IE используйте event.preventDefault() для блокировки
Разница между preventDefault и stopPropogation
-
preventDefaultСообщите браузеру, чтобы он не выполнял действие по умолчанию, связанное с событием (аналоговое представление браузера). -
stopPropagationЭто нужно, чтобы остановить событие и продолжить всплывать, но это недействительно для браузеров ниже IE9.
5. Делегация мероприятия
- Одна из основных идей оптимизации производительности в js — уменьшить количество операций dom.
- сохранить память
- Нет необходимости отменять регистрацию событий для дочерних узлов
Допустим, есть 100 li, и у каждого li есть одно и то же событие click. Если вы добавите событие для каждого Li, это вызовет слишком много посещений dom, заставит браузер слишком много раз перерисовывать и перекомпоновывать, а производительность снизится. Использование делегирования событий может решить такие проблемы
принцип
Реализация делегирования событий достигается за счет использования принципа всплытия событий. Когда мы добавим событие клика к самому внешнему узлу, события щелчка ul, li и a будут всплывать к самому внешнему узлу и делегировать ему выполнение события от его имени.
<ul id="ul">
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
window.onload = function(){
var ulEle = document.getElementById('ul');
ul.onclick = function(ev){
//兼容IE
ev = ev || window.event;
var target = ev.target || ev.srcElement;
if(target.nodeName.toLowerCase() == 'li'){
alert( target.innerHTML);
}
}
}
9: модульный
Существует четыре вида схем загрузки модулей, которые относительно хорошо разработаны в js:
- Первое — это решение CommonJS, которое вводит модули через require и определяет выходной интерфейс модуля через module.exports. Это решение для загрузки модулей является решением на стороне сервера. Оно вводит модули синхронно. Поскольку файлы хранятся на локальном диске на стороне сервера, чтение происходит очень быстро, поэтому с синхронной загрузкой проблем не возникает. Но если это на стороне браузера, так как модуль загружается с помощью сетевых запросов, целесообразнее использовать асинхронную загрузку.
- Второй — схема AMD, которая использует асинхронную загрузку для загрузки модулей. Загрузка модулей не влияет на выполнение последующих операторов. Все операторы, которые зависят от этого модуля, определены в функции обратного вызова, а обратный вызов выполняется после загрузки завершена функция. require.js реализует спецификацию AMD
- Третье — решение CMD, и это решение, и решение AMD предназначены для решения проблемы асинхронной загрузки модулей, sea.js реализует спецификацию CMD. Разница между ним и require.js заключается в том, что обработка зависимостей отличается, когда модуль определен, и время выполнения зависимого модуля отличается.
- Четвертая схема — это схема, предложенная ES6, которая использует форму импорта и экспорта для импорта и экспорта модулей.
Разница между спецификациями AMD и CMD?
- Первый аспект заключается в том, что зависимости обрабатываются по-разному во время определения модуля. AMD уважает предварительную зависимость и объявляет модули, от которых она зависит, при определении модулей. И CMD учитывает ближайшую зависимость и требует ее только при использовании модуля.
- Второй аспект заключается в том, что время выполнения зависимых модулей обрабатывается по-разному. Во-первых, AMD и CMD загружают модули асинхронно, но разница между ними заключается во времени выполнения модуля.AMD напрямую выполняет зависимый модуль после того, как зависимый модуль загружен, и порядок выполнения зависимого модуля не обязательно одинаков. как заказ мы написали. Однако CMD не выполняется после загрузки зависимых модулей, а просто загружает их.После того, как все зависимые модули загружены, он входит в логику функции обратного вызова и выполняет соответствующие модули только тогда, когда встречается оператор require, так что порядок выполнения модули такие же, как и порядок, в котором мы их писали, остается прежним.
10: Итератор-итератор
Iterator (итератор) — это интерфейс, или спецификация. Предоставьте унифицированный механизм доступа к множеству различных структур данных. Любая структура данных может завершить операцию обхода (то есть обработать все элементы структуры данных по очереди), пока развернут интерфейс Iterator.
Синтаксис итератора:
const obj = {
[Symbol.iterator]:function(){}
}
[Symbol.iterator] Имя атрибута является фиксированным способом записи. Пока объект с этим атрибутом принадлежит, его можно обойти с помощью итератора.
- Метод обхода итератора должен сначала получить указатель на итератор, изначально перед указателем на первые данные, за которыми следуют вызов следующего метода, чтобы изменить указатель, указывающий на следующие данные, разрешенные
- каждый раз
nextвернет объект с двумя свойствами- значение представляет данные, которые вы хотите получить
- done Логическое значение, false указывает, что данные, на которые указывает текущий указатель, имеют значение, а true указывает, что обход завершен
Итератор имеет три роли:
let arr = [{num:1},2,3]
let it = arr[Symbol.iterator]() // 获取数组中的迭代器
console.log(it.next()) // { value: Object { num: 1 }, done: false }
console.log(it.next()) // { value: 2, done: false }
console.log(it.next()) // { value: 3, done: false }
console.log(it.next()) // { value: undefined, done: true }
Объекты не имеют интерфейса Iterator компоновки и не могут быть пройдены с помощью for of. Следующее делает объект интерфейсом Iterator
- Структуру данных можно считать «проходимой», если она имеет свойство Symbol.iterator.
- Существует три типа структур данных, в которых прототип развертывает интерфейс Iterator, включая четыре типа, а именно массивы, массивоподобные объекты, структуры Set и Map.
Почему объект (Object) не развертывает интерфейс Iterator?
- Во-первых, неясно, какое свойство объекта просматривается первым, а какое — позже, и разработчику необходимо указать это вручную. Однако обход обходчика — это линейный процесс.Для нелинейных структур данных развертывание интерфейса обходчика эквивалентно развертыванию линейного преобразования.
- Не обязательно разворачивать на объект интерфейс Iterator, т.к. Map компенсирует его недостатки, а у него бывает интерфейс Iteraotr
let obj = {
id: '123',
name: '张三',
age: 18,
gender: '男',
hobbie: '睡觉'
}
obj[Symbol.iterator] = function () {
let keyArr = Object.keys(obj)
let index = 0
return {
next() {
return index < keyArr.length ? {
value: {
key: keyArr[index],
val: obj[keyArr[index++]]
}
} : {
done: true
}
}
}
}
for (let key of obj) {
console.log(key)
}
11: Генератор
Generator — это новый синтаксис в ES6, который, как и Promise, можно использовать для асинхронного программирования. Можно сказать, что функция Generator является конкретной реализацией интерфейса Iterator. Самая большая особенность Generator заключается в том, что он может контролировать выполнение функций.
- function* используется для объявления того, что функция является функцией-генератором.Он имеет на одну позицию *,* больше, чем обычное объявление функции.Он может быть рядом с ключевым словом function или рядом с именем функции.
- Yield означает, что это ключевое слово может появляться только в теле функции-генератора, но у генератора также может не быть ключевого слова yield.Когда функция встречает yield, она приостанавливается и возвращает результат выражения после yield.
- Роль next состоит в том, чтобы вернуть управление кодом функции-генератору.
function *foo(x) {
let y = 2 * (yield (x + 1))
let z = yield (y / 3)
return (x + y + z)
}
let it = foo(5)
console.log(it.next()) // => {value: 6, done: false}
console.log(it.next(12)) // => {value: 8, done: false}
console.log(it.next(13)) // => {value: 42, done: true}
12: асинхронно/ожидание
Синтаксический сахар для функций генератора. Имеет лучшую семантику, лучшую применимость, а возвращаемое значение — обещание.
- По сравнению с использованием Promise напрямую, await имеет преимущество обработки цепочки вызовов then, что позволяет писать код более четко и точно. Недостатком является то, что злоупотребление ожиданием может привести к проблемам с производительностью, поскольку ожидание блокирует код.Возможно, последующий асинхронный код не зависит от первого, но ему все равно нужно дождаться завершения первого, что приведет к потере параллелизма В этом случае следует использовать Promise.all.
- Функция. Если вы добавите асинхронность, функция вернет обещание.
- async => *
- await => yield
13: Обещания
Когда вы говорите здесь о промисах, в дополнение к болевым точкам, которые они решают, и часто используемым API, лучше всего расширить и ввести цикл обработки событий. Давайте поговорим о порядке выполнения микрозадачи (микрозадачи) и макрозадачи (задачи), если вы видели исходный код промисов, лучше рассказать о том, как реализован нативный промис. Ключевой момент Promise заключается в двух параметрах обратного вызова: resovle и reject. Существует также цепочка вызовов Promise (Promise.then(), каждый из которых является ответственным лицом)
- Промисы — это новый синтаксис в ES6, который решает проблему ада обратных вызовов.
- Вы можете думать о промисах как о машине состояний. Исходное состояние "ожидание", и состояние может быть изменено на разрешенное или отклоненное с помощью функций разрешения и отклонения. После изменения состояния его нельзя изменить снова.
- Функция then возвращает экземпляр Promise, а возвращаемое значение — новый экземпляр вместо предыдущего. Поскольку в спецификации Promise указано, что кроме состояния pending, другие состояния не могут быть изменены, если возвращается один и тот же экземпляр, то несколько вызовов then бессмысленны.
1. Основная ситуация промисов
- Ожидание: исходное состояние, ни завершено, ни отклонено.
- Завершено: операция успешно завершена.
- Отклонено: операция не удалась.
2. Статический метод Promise
все методы
- Синтаксис: Promise.all(итерируемый)
- Параметры: повторяемый объект, например Array.
- Описание: этот метод полезен для агрегирования результатов нескольких обещаний.В ES6 несколько асинхронных запросов Promise.all могут выполняться параллельно, и возвращаемые результаты обычно имеют следующие два случая.
- Когда все результаты возвращены успешно, успешные результаты возвращаются в запрошенном порядке.
- Когда в нем есть неудавшийся метод, введите неудавшийся метод
// 在一个页面中需要加载获取轮播列表、获取店铺列表、获取分类列表这三个操作,页面需要同时发出请求进行页面渲染,这样用 `Promise.all` 来实现,看起来更清晰、一目了然。
//1.获取轮播数据列表
function getBannerList(){
return new Promise((resolve,reject)=>{
setTimeout(function(){
resolve('轮播数据')
},300)
})
}
//2.获取店铺列表
function getStoreList(){
return new Promise((resolve,reject)=>{
setTimeout(function(){
resolve('店铺数据')
},500)
})
}
//3.获取分类列表
function getCategoryList(){
return new Promise((resolve,reject)=>{
setTimeout(function(){
resolve('分类数据')
},700)
})
}
function initLoad(){
Promise.all([getBannerList(),getStoreList(),getCategoryList()])
.then(res=>{
console.log(res)
}).catch(err=>{
console.log(err)
})
}
initLoad()
метод allSettled
- Синтаксис и параметры Promise.allSettled аналогичны Promise.all.Его параметры принимают массив промисов и возвращают новый промис. Единственная разница в том, что он не даст сбой после выполнения, то есть, когда Promise.allSettled полностью обработан, мы можем получить статус каждого промиса, независимо от того, успешно он обработан или нет.
const resolved = Promise.resolve(2);
const rejected = Promise.reject(-1);
const allSettledPromise = Promise.allSettled([resolved, rejected]);
allSettledPromise.then(function (results) {
console.log(results);
});
// 返回结果:
// [
// { status: 'fulfilled', value: 2 },
// { status: 'rejected', reason: -1 }
// ]
Как видно из приведенного выше кода, Promise.allSettled, наконец, возвращает массив, который записывает возвращаемое значение каждого промиса в переданных параметрах, что отличается от метода all.
любой метод
- Синтаксис: Promise.any(итерируемый)
- Параметры: итерируемый итерируемый объект, такой как Array.
- Описание: метод any возвращает промис. Пока один из экземпляров промиса параметра становится выполненным состоянием, экземпляр, возвращаемый любым, станет выполненным состоянием; если все экземпляры промиса параметра становятся отклоненным состоянием, экземпляр оболочки станет состояние отказа..
метод гонки
Синтаксис: Promise.race(итерируемый) Параметры: итерируемый итерируемый объект, такой как Array. Описание: метод гонки возвращает обещание.Поскольку один экземпляр параметра промис изменяет состояние первым, возвращаемое состояние метода гонки изменяется соответствующим образом. Возвращаемое значение экземпляра Promise, который изменился первым, передается функции обратного вызова метода гонки.
//请求某个图片资源
function requestImg(){
var p = new Promise(function(resolve, reject){
var img = new Image();
img.onload = function(){ resolve(img); }
img.src = 'http://www.baidu.com/img/flexible/logo/pc/result.png';
});
return p;
}
//延时函数,用于给请求计时
function timeout(){
var p = new Promise(function(resolve, reject){
setTimeout(function(){ reject('图片请求超时'); }, 5000);
});
return p;
}
Promise.race([requestImg(), timeout()])
.then(function(results){
console.log(results);
})
.catch(function(reason){
console.log(reason);
});
14: Цикл событий
- Код по умолчанию выполняется сверху вниз, а среда выполнения выполняется через скрипт (макрос-задачу).
- В процессе выполнения кода вызов Timer Promise нажмите событие ... не выполняется немедленно, нужно дождаться текущего кода выполненного полностью
- Асинхронный способ разделить очередь, были сохранены в микро-задании (немедленно депозит) и макрозащита (или время, и мы должны быть сохранены) в очередь
- После выполнения скрипта все микрозадачи будут очищены
- После выполнения микрозадачи страница будет отрисована (не вызывается каждый раз)
- Перейдите в очередь задач макроса, чтобы увидеть, есть ли время прибытия, и выньте один из них для выполнения.
- После завершения выполнения выполните описанные выше шаги, чтобы продолжить цикл.
1. Цикл событий браузера
Единый поток JavaScript в соответствии с его назначением. В качестве языка сценариев браузера JavaScript в основном используется для взаимодействия с пользователем и управления DOM. Это определяет, что это может быть только один поток, иначе возникнут сложные проблемы с синхронизацией. Например, если предположить, что в JavaScript есть два потока одновременно, один поток добавляет содержимое в узел DOM, а другой поток удаляет этот узел, какой поток должен выбрать браузер? Таким образом, чтобы избежать сложности, JavaScript с самого начала был однопоточным, что было основной особенностью языка и не изменится в будущем.
- Прежде всего, js работает в одном потоке, когда код выполняется, упорядоченное выполнение кода гарантируется путем помещения контекста выполнения различных функций в стек выполнения.
- При выполнении синхронного кода, если встречается асинхронное событие, движок js не будет ждать его возвращаемого результата, а приостановит событие и продолжит выполнение других задач в стеке выполнения.
- Когда синхронное событие выполняется, обратный вызов, соответствующий асинхронному событию, добавляется в другую очередь задач, отличную от текущего стека выполнения, для ожидания выполнения.
- Очередь задач можно разделить на выравнивание макрозадач и выравнивание микрозадач.Когда события в текущем стеке выполнения выполняются, механизм js сначала определяет, есть ли задачи в выравнивании микрозадач, которые могут быть выполнены, и если да, то очередь микрозадач помещается в начало очереди, а событие помещается в стек для выполнения.
- Когда все задачи в столбце пары микрозадач выполнены, оцениваются задачи в столбце пары макрозадач.
микрозадачи
- promise
- Object.observe
- MutationObserver
задача макроса
- script
- setTimeout
- setInterval
- UI renderin
- События взаимодействия с пользователем (например, щелчки мышью, прокрутка страниц, увеличение и уменьшение масштаба и т. д.)
Итак, правильная последовательность цикла событий выглядит так
- Выполнение синхронного кода, который является задачей макроса
- Стек выполнения пуст, проверьте, есть ли микрозадачи для выполнения
- Выполнить все микрозадачи
- Рендеринг пользовательского интерфейса, если это необходимо
- Затем запустите следующий раунд цикла событий и выполните асинхронный код в задаче макроса.
Из приведенной выше последовательности циклов событий, если асинхронный код в макрозадаче имеет много вычислений и нуждается в работе с DOM, чтобы быстрее реагировать на ответ интерфейса, мы можем поместить операцию DOM в микрозадачу.
2. Цикл событий в узле
При запуске Node.js будет инициализирован Eventloop для обработки сценариев входного кода, которые будут выполнять асинхронные вызовы API, а метод process.nextTick() начнет обработку цикла событий. Ниже приведен справочный процесс цикла событий Eventloop, предоставленный официальным сайтом Node.js.
- Цикл событий в Node не такой, как в браузере.
- Цикл событий Node разделен на 6 этапов, которые последовательно выполняются многократно.
- Каждый раз, когда выполняется макрозадача, микрозадача будет очищаться (порядок выполнения такой же, как и в браузере, в версии node11 или выше)
- Микрораздел в процессе. NextTick Узел, нижняя часть текущего стека выполнения имеет более высокий приоритет, чем обещание
15: Сбор мусора
Поскольку строки, объекты и массивы не имеют фиксированного размера, они могут быть динамически выделены только тогда, когда известен их размер. Каждый раз, когда программа JavaScript создает строку, массив или объект, интерпретатор должен выделить память для хранения этого объекта. Всякий раз, когда память динамически распределяется таким образом, она должна в конечном итоге быть освобождена, чтобы ее можно было использовать повторно, иначе интерпретатор JavaScript будет потреблять всю доступную память в системе, что приведет к сбою системы.
Существует два метода сбора мусора:标记清除,引用计数.
1. Отметить как очищенный
Это самый распространенный способ сборки мусора в javascript. Когда переменная входит в среду выполнения, пометьте переменную как «входящую в среду». Логически память, занимаемая входящими в среду переменными, никогда не может быть освобождена, потому что они могут быть использованы, как только поток выполнения войдет в соответствующую среду. Когда переменная покидает среду, она помечается как «выходящая из среды».
Когда сборщик мусора запускается, он помечает все переменные, хранящиеся в памяти. Затем он удаляет переменные в среде и теги, на которые ссылаются переменные в среде. Переменные, отмеченные после этого, будут рассматриваться как переменные, готовые к удалению, поскольку переменные в среде больше не доступны. наконец. Сборщик мусора завершает очистку памяти, уничтожает помеченные значения и освобождает место в памяти, которое они занимают.
2. Подсчет ссылок
Так называемый «счетчик ссылок» означает, что языковой движок имеет «справочную таблицу», которая сохраняет в памяти время обращения всех ресурсов (обычно различных значений). Если количество ссылок на значение равно 0, это означает, что значение больше не используется, поэтому память может быть освобождена. Но у подсчета ссылок есть самая большая проблема: циклические ссылки. Чтобы решить проблему циклических ссылок, лучше вручную установить для них значение null, когда они не используются.
16: Утечка памяти
Неожиданная глобальная переменная: не может быть переработана
- Таймер: неправильно закрыт, что приводит к тому, что указанная внешняя переменная не освобождается.
- Прослушиватель событий: неправильно уничтожен (может появиться в браузерах более ранних версий)
- Закрытие
- В первом случае мы случайно создаем глобальную переменную, используя необъявленную переменную, и эта переменная остается в памяти и не может быть повторно использована.
- Второй случай — мы устанавливаем таймер setInterval и забываем его отменить, если в функции цикла есть ссылка на внешнюю переменную, то эта переменная всегда останется в памяти и не может быть перезапущена.
- Третий случай — мы получаем ссылку на DOM-элемент, а последний элемент удаляется, так как мы сохраняем ссылку на этот элемент, он не может быть переработан.
- Четвертый случай — неразумное использование замыканий, в результате чего некоторые переменные остаются в памяти.
- ссылки на dom: ссылки в памяти не очищались должным образом при удалении элемента dom
- Что выводит консоль console.log
Вы можете использовать временную шкалу в Chrome, чтобы отметить память, визуализировать изменения в памяти и найти выбросы.
17: Глубокие массивы
1. Array.of
Array.of используется для поочередного преобразования аргумента в элемент массива, а затем возврата нового массива, независимо от того, является ли аргумент числом или нет. Это в основном то же самое, что и конструктор Array, единственное отличие заключается в обработке одного числового параметра.
Array.of(8.0); // [8]
Array(8.0); // [empty × 8]
Array.of(8.0, 5); // [8, 5]
Array(8.0, 5); // [8, 5]
Array.of('8'); // ["8"]
Array('8'); // ["8"]
2. Array.from
Синтаксически Array.from принимает 3 параметра:
- Подобно объекту массива, must;
- Функция обработки, для генерации нового массива будет обработана обратно к функции;
- this scope, который представляет значение this при выполнении функции обработки.
Первый параметр из этих трех параметров является обязательным, а последние два параметра являются необязательными. Давайте посмотрим на его использование через кусок кода.
var obj = {0: 'a', 1: 'b', 2:'c', length: 3};
Array.from(obj, function(value, index){
console.log(value, index, this, arguments.length);
return value.repeat(3); //必须指定返回值,否则返回 undefined
}, obj);
// return 的 value 重复了三遍,最后返回的数组为 ["aaa","bbb","ccc"]
// 如果这里不指定 this 的话,加工函数完全可以是一个箭头函数。上述代码可以简写为如下形式。
Array.from(obj, (value) => value.repeat(3));
// 控制台返回 (3) ["aaa", "bbb", "ccc"]
В дополнение к указанным выше объектам obj, объекты с итераторами также включают String, Set, Map и т. д. Array.from может обрабатывать их все, см. код ниже.
// String
Array.from('abc'); // ["a", "b", "c"]
// Set
Array.from(new Set(['abc', 'def'])); // ["abc", "def"]
// Map
Array.from(new Map([[1, 'ab'], [2, 'de']]));
// [[1, 'ab'], [2, 'de']]
3. Суждение массива
var a = [];
// 1.基于instanceof
a instanceof Array;
// 2.基于constructor
a.constructor === Array;
// 3.基于Object.prototype.isPrototypeOf
Array.prototype.isPrototypeOf(a);
// 4.基于getPrototypeOf
Object.getPrototypeOf(a) === Array.prototype;
// 5.基于Object.prototype.toString
Object.prototype.toString.apply(a) === '[object Array]';
После ES6 был добавлен метод Array.isArray, который может напрямую определить, является ли тип данных массивом, но если isArray не существует, полифил Array.isArray обычно можно записать так:
if (!Array.isArray){
Array.isArray = function(arg){
return Object.prototype.toString.call(arg) === '[object Array]';
};
}
4. Измените свой подход
На основе ES6 существует в общей сложности 9 методов, которые могут изменять свои собственные значения, а именно pop, push, reverse, shift, sort, splice, unshift и два новых метода ES6 copyWithin и fill.
// pop方法
var array = ["cat", "dog", "cow", "chicken", "mouse"];
var item = array.pop();
console.log(array); // ["cat", "dog", "cow", "chicken"]
console.log(item); // mouse
// push方法
var array = ["football", "basketball", "badminton"];
var i = array.push("golfball");
console.log(array);
// ["football", "basketball", "badminton", "golfball"]
console.log(i); // 4
// reverse方法
var array = [1,2,3,4,5];
var array2 = array.reverse();
console.log(array); // [5,4,3,2,1]
console.log(array2===array); // true
// shift方法
var array = [1,2,3,4,5];
var item = array.shift();
console.log(array); // [2,3,4,5]
console.log(item); // 1
// unshift方法
var array = ["red", "green", "blue"];
var length = array.unshift("yellow");
console.log(array); // ["yellow", "red", "green", "blue"]
console.log(length); // 4
// sort方法
var array = ["apple","Boy","Cat","dog"];
var array2 = array.sort();
console.log(array); // ["Boy", "Cat", "apple", "dog"]
console.log(array2 == array); // true
// splice方法
var array = ["apple","boy"];
var splices = array.splice(1,1);
console.log(array); // ["apple"]
console.log(splices); // ["boy"]
// copyWithin方法
var array = [1,2,3,4,5];
var array2 = array.copyWithin(0,3);
console.log(array===array2,array2); // true [4, 5, 3, 4, 5]
// fill方法
var array = [1,2,3,4,5];
var array2 = array.fill(10,0,3);
console.log(array===array2,array2);
5. Метод, который не меняет себя
На основе ES7 есть 9 методов, которые не меняют себя, а именно concat, join, slice, toString, toLocaleString, indexOf, lastIndexOf, toSource, которые не образуют стандарта, а новый метод включает в себя ES7.
// concat方法
var array = [1, 2, 3];
var array2 = array.concat(4,[5,6],[7,8,9]);
console.log(array2); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(array); // [1, 2, 3], 可见原数组并未被修改
// join方法
var array = ['We', 'are', 'Chinese'];
console.log(array.join()); // "We,are,Chinese"
console.log(array.join('+')); // "We+are+Chinese"
// slice方法
var array = ["one", "two", "three","four", "five"];
console.log(array.slice()); // ["one", "two", "three","four", "five"]
console.log(array.slice(2,3)); // ["three"]
// toString方法
var array = ['Jan', 'Feb', 'Mar', 'Apr'];
var str = array.toString();
console.log(str); // Jan,Feb,Mar,Apr
// tolocalString方法
var array= [{name:'zz'}, 123, "abc", new Date()];
var str = array.toLocaleString();
console.log(str); // [object Object],123,abc,2016/1/5 下午1:06:23
// indexOf方法
var array = ['abc', 'def', 'ghi','123'];
console.log(array.indexOf('def')); // 1
// includes方法
var array = [-0, 1, 2];
console.log(array.includes(+0)); // true
console.log(array.includes(1)); // true
var array = [NaN];
console.log(array.includes(NaN)); // true
Метод включения следует отметить, что если в элементе есть 0, то в процессе оценки, будь то +0 или -0, будет оцениваться как Истина, включение здесь игнорирует +0 и -0
6. Метод обхода массива
На основе ES6 существует в общей сложности 12 методов обхода, которые не меняют себя, а именно: forEach, every, some, filter, map, reduce, reduceRight и ES6 новые записи методов, find, findIndex, keys, values
// forEach方法
var array = [1, 3, 5];
var obj = {name:'cc'};
var sReturn = array.forEach(function(value, index, array){
array[index] = value;
console.log(this.name); // cc被打印了三次, this指向obj
},obj);
console.log(array); // [1, 3, 5]
console.log(sReturn); // undefined, 可见返回值为undefined
// every方法
var o = {0:10, 1:8, 2:25, length:3};
var bool = Array.prototype.every.call(o,function(value, index, obj){
return value >= 8;
},o);
console.log(bool); // true
// some方法
var array = [18, 9, 10, 35, 80];
var isExist = array.some(function(value, index, array){
return value > 20;
});
console.log(isExist); // true
// map 方法
var array = [18, 9, 10, 35, 80];
array.map(item => item + 1);
console.log(array); // [19, 10, 11, 36, 81]
// filter 方法
var array = [18, 9, 10, 35, 80];
var array2 = array.filter(function(value, index, array){
return value > 20;
});
console.log(array2); // [35, 80]
// reduce方法
var array = [1, 2, 3, 4];
var s = array.reduce(function(previousValue, value, index, array){
return previousValue * value;
},1);
console.log(s); // 24
// ES6写法更加简洁
array.reduce((p, v) => p * v); // 24
// reduceRight方法 (和reduce的区别就是从后往前累计)
var array = [1, 2, 3, 4];
array.reduceRight((p, v) => p * v); // 24
// entries方法
var array = ["a", "b", "c"];
var iterator = array.entries();
console.log(iterator.next().value); // [0, "a"]
console.log(iterator.next().value); // [1, "b"]
console.log(iterator.next().value); // [2, "c"]
console.log(iterator.next().value); // undefined, 迭代器处于数组末尾时, 再迭代就会返回undefined
// find & findIndex方法
var array = [1, 3, 5, 7, 8, 9, 10];
function f(value, index, array){
return value%2==0; // 返回偶数
}
function f2(value, index, array){
return value > 20; // 返回大于20的数
}
console.log(array.find(f)); // 8
console.log(array.find(f2)); // undefined
console.log(array.findIndex(f)); // 4
console.log(array.findIndex(f2)); // -1
// keys方法
[...Array(10).keys()]; // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[...new Array(10).keys()]; // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
// values方法
var array = ["abc", "xyz"];
var iterator = array.values();
console.log(iterator.next().value);//abc
console.log(iterator.next().value);//xyz
7. Резюме
Между этими методами есть много общего, а именно:
- Все методы вставки элементов, такие как push и unshift, возвращают новую длину массива;
- Все методы удаления элементов, такие как pop, shift, splice, все возвращают удаленный элемент или возвращают массив удаленных элементов;
- Некоторые методы обхода, такие как forEach, every, some, filter, map, find, findIndex, содержат два параметра: function(value,index,array){} и thisArg.
Методы массива и строки