введение
Javascript находится в центре внимания фронтенд-интервью.Эта статья посвящена сортировке общеизвестных моментов в Javascript, а затем анализу некоторых простых тем. Ограниченный объемом статьи, невозможно объяснить все точки знаний, в этой статье перечислены только некоторые важные и трудные моменты.Если вы хотите узнать больше, пожалуйста, нажмитемой блог.
Во-первых, тип переменной
1. Классификация типов данных JS
По способу передачи типов переменных в JavaScript он делится на базовые типы данных и ссылочные типы данных. К базовым типам данных относятся Undefined, Null, Boolean, Number, String и Symbol (новое в ES6, представляющее уникальные значения), в то время как ссылочные типы данных в совокупности называются объектными объектами, включая объекты, массивы и функции.
Существуют различия в способе передачи параметров:.
-
Если параметр функции является простым типом, копия типа значения будет передана внутрь функции, и внутренняя часть функции не повлияет на переменные параметра, переданные вне функции.
-
Если параметр является ссылочным типом, значение адреса ссылочного типа будет скопировано в параметр, переданный в функцию, и внутренняя модификация функции повлияет на передачу.
Тема: Разница между примитивными типами и ссылочными типами
Базовые типы и ссылочные типы хранятся в разных местах памяти.Базовые типы хранятся непосредственно в стеке, а объекты ссылочных типов хранятся в куче.В то же время в стеке хранится указатель, и этот указатель указывает к объекту в куче.начальная позиция. Давайте рассмотрим основные различия между ними в небольшой теме:
// 基本类型
var a = 10
var b = a
b = 20
console.log(a) // 10
console.log(b) // 20
В приведенном выше коде a и b являются типами значений, и они изменяют присваивание соответственно, не влияя друг на друга. Посмотрите еще раз на пример ссылочного типа:
// 引用类型
var a = {x: 10, y: 20}
var b = a
b.x = 100
b.y = 200
console.log(a) // {x: 100, y: 200}
console.log(b) // {x: 100, y: 200}
В приведенном выше коде и a, и b являются ссылочными типами. После выполнения b = a измените значение атрибута b, и значение a также изменится. Поскольку a и b являются ссылочными типами и указывают на один и тот же адрес памяти, то есть оба ссылаются на одно и то же значение, поэтому, когда b изменяет атрибут, значение a изменяется соответственно.
2. Оценка типа данных
1) тип
typeof возвращает строку, представляющую тип данных, возвращаемые результаты включают в себя: число, логическое значение, строку, символ, объект, неопределенный, функцию и другие 7 типов данных, но не могут оценивать нуль, массив и т. д.
typeof Symbol(); // symbol 有效
typeof ''; // string 有效
typeof 1; // number 有效
typeof true; //boolean 有效
typeof undefined; //undefined 有效
typeof new Function(); // function 有效
typeof null; //object 无效
typeof [] ; //object 无效
typeof new Date(); //object 无效
typeof new RegExp(); //object 无效
2) пример
instanceof используется, чтобы определить, является ли A экземпляром B. Выражение: A instanceof B, если A является экземпляром B, он возвращает true, в противном случае он возвращает false.Оператор instanceof используется для проверки того, имеет ли объект свойство прототипа конструктора в своей цепочке прототипов, но он не может обнаружить null и undefined.
[] instanceof Array; //true
{} instanceof Object;//true
new Date() instanceof Date;//true
new RegExp() instanceof RegExp//true
null instanceof Null//报错
undefined instanceof undefined//报错
3) конструктор
Функция конструктора очень похожа на instanceof.Но объект обнаружения конструктора отличается от instanceof и также может обрабатывать обнаружение базовых типов данных.Однако конструктор функции нестабилен, в основном это проявляется в перезаписи прототипа класса, в процессе перезаписи велика вероятность того, что предыдущий конструктор будет перезаписан, поэтому обнаруженный результат будет неточным.
4) Object.prototype.toString.call()
Object.prototype.toString.call() — самый точный и распространенный способ.
Object.prototype.toString.call('') ; // [object String]
Object.prototype.toString.call(1) ; // [object Number]
Object.prototype.toString.call(true) ; // [object Boolean]
Object.prototype.toString.call(undefined) ; // [object Undefined]
Object.prototype.toString.call(null) ; // [object Null]
Object.prototype.toString.call(new Function()) ; // [object Function]
Object.prototype.toString.call(new Date()) ; // [object Date]
Object.prototype.toString.call([]) ; // [object Array]
Object.prototype.toString.call(new RegExp()) ; // [object RegExp]
Object.prototype.toString.call(new Error()) ; // [object Error]
3. Поверхностное копирование и глубокое копирование
Поверхностная копия копирует только указатель на объект, а не сам объект, старый и новый объекты по-прежнему используют одну и ту же память..
Реализация поверхностного копирования (см.Поверхностная копия и глубокая копия):
- Object.assign(): следует отметить, что когда целевой объект имеет только один слой, это глубокая копия.
- Array.prototype.concat()
- Array.prototype.slice()
Глубокая копия — это копирование всех ссылочных структур данных при копировании данных.. Проще говоря, в памяти есть две структуры данных, идентичные и независимые друг от друга, и ссылочный тип копируется, а не просто копируется его ссылочное отношение.
Реализация глубокой копии:
- Популярная библиотека функций Lodash также предоставляет _.clonedeep для глубокого копирования.
- jQuery предоставляет $.extend, который можно использовать для глубокого копирования.
- JSON.parse(JSON.stringify())
- Рукописный рекурсивный метод
Принцип рекурсивной реализации глубокого копирования: чтобы скопировать часть данных, мы должны пройти по его свойствам.Если свойства объекта все еще являются объектами, продолжайте использовать этот метод и так далее.
//定义检测数据类型的功能函数
function checkedType(target) {
return Object.prototype.toString.call(target).slice(8, -1)
}
//实现深度克隆---对象/数组
function clone(target) {
//判断拷贝的数据类型
//初始化变量result 成为最终克隆的数据
let result,
targetType = checkedType(target)
if (targetType === 'Object') {
result = {}
} else if (targetType === 'Array') {
result = []
} else {
return target
}
//遍历目标数据
for (let i in target) {
//获取遍历数据结构的每一项值。
let value = target[i]
//判断目标结构里的每一值是否存在对象/数组
if (checkedType(value) === 'Object' || checkedType(value) === 'Array') {
//对象/数组里嵌套了对象/数组
//继续遍历获取到value值
result[i] = clone(value)
} else {
//获取到value值是基本的数据类型或者是函数。
result[i] = value
}
}
return result
}
2. Область действия и замыкания
1. Контекст выполнения и стек выполнения
Контекст выполнения — это абстрактное понятие среды, в которой анализируется и выполняется текущий код JavaScript.Любой код, работающий в JavaScript, выполняется в контексте выполнения. Жизненный цикл контекста выполнения состоит из трех фаз: фаза создания → фаза выполнения → фаза повторного использования, и мы сосредоточимся на фазе создания.
Фаза создания (когда функция вызывается, но до выполнения любого ее внутреннего кода) делает три вещи:
- Создайте объект переменной: сначала инициализируйте аргументы аргумента функции, поднимите объявление функции и объявление переменной.
- Создайте цепочку областей: описано ниже
- Убедитесь, что это указывает на: это будет представлено ниже
function test(arg){
// 1. 形参 arg 是 "hi"
// 2. 因为函数声明比变量声明优先级高,所以此时 arg 是 function
console.log(arg);
var arg = 'hello'; // 3.var arg 变量声明被忽略, arg = 'hello'被执行
function arg(){
console.log('hello world')
}
console.log(arg);
}
test('hi');
/* 输出:
function arg() {
console.log('hello world');
}
hello
*/
Это связано с тем, что при выполнении функции сначала формируется новая частная область, а затем выполняются следующие шаги:
- Если есть формальный параметр, сначала присвойте значение формальному параметру
- Выполните предварительную интерпретацию в приватной области, объявление функции имеет более высокий приоритет, чем объявление переменной, и, наконец, последнее будет перезаписано первым, но может быть переназначено
- Код в приватной области выполняется сверху вниз
Существует много функций и несколько контекстов выполнения функций.Каждый раз при вызове функции создается новый контекст выполнения.Как управлять таким количеством созданных контекстов выполнения?
Механизм JavaScript создает стек выполнения для управления контекстом выполнения.Стек выполнения можно рассматривать как структуру стека, в которой хранятся вызовы функций в соответствии с принципом «первым поступил — последним обслужен»..
Из приведенной выше блок-схемы нам нужно запомнить несколько ключевых моментов:- JavaScript выполняется в одном потоке, и весь код ставится в очередь на выполнение.
- Когда браузер начинает выполнять глобальный код, он сначала создает глобальный контекст выполнения и помещает его на вершину стека выполнения.
- Всякий раз, когда начинается выполнение функции, контекст выполнения функции создается и помещается на вершину стека выполнения. После завершения выполнения текущей функции контекст выполнения текущей функции извлекается из стека и ожидает сборки мусора.
- Механизм выполнения JS браузера всегда обращается к контексту выполнения в верхней части стека.
- Существует только один глобальный контекст, и он извлекается из стека при закрытии браузера.
2. Объем и цепочка объемов
ES6 поставляется с JavaScript с глобальной областью действия, областью действия и областью действия блока (новое в ES6). Мы можем понять это так:Scope — это независимый сайт, поэтому переменные не будут раскрыты. Другими словами, область видимости чаще всего используется для изоляции переменных. Переменные с одним и тем же именем в разных областях видимости не будут конфликтовать.. Прежде чем вводить цепочку областей видимости, мы должны сначала понять свободные переменные.В следующем коде console.log(a) должен получить переменную a, но a не определена в текущей области видимости (сравните b). Переменные, не определенные в текущей области видимости, становятся свободными переменными.
var a = 100
function fn() {
var b = 200
console.log(a) // 这里的a在这里就是一个自由变量
console.log(b)
}
fn()
Как получить значение свободной переменной - посмотрите на родительскую область (родительскую область, которая создала функцию). А если у родителя его нет? Ищите слой за слоем, пока не найдете глобальную область видимости и все еще не найдете ее, а затем сдайтесь. Эта послойная связь представляет собой цепочку областей видимости.
function F1() {
var a = 100
return function () {
console.log(a)
}
}
function F2(f1) {
var a = 200
console.log(f1())
}
var f1 = F1()
F2(f1) // 100
В приведенном выше коде значение свободной переменной a ищется из функции F1 вместо F2, потому чтоКогда свободные переменные ищутся в цепочке областей видимости, он основывается на цепочке областей видимости, когда функция была определена, а не когда функция выполнялась.
3. Что закрыто
Понятие замыкания также является относительно абстрактным понятием в JavaScript, лично я понимаю, что замыкание — это функция в функции (другие языки не могут этого сделать), функция внутри может обращаться к переменным внешней функции, а внешняя переменные принадлежат внутренней функции part.
Роль замыканий:
- Используйте замыкания для доступа к переменным в функциях.
- Переменные могут долго храниться в памяти, а жизненный цикл относительно долог..
Нельзя злоупотреблять замыканиями, иначе это вызовет утечку памяти и повлияет на производительность веб-страниц. После того, как закрытие израсходовано, чтобы немедленно освободить ресурс, укажите для ссылочной переменной значение null.
Закрытие Есть два основных сценария:
- Функции передаются как параметры (см. пример в разделе Scope).
- функция как возвращаемое значение (пример ниже)
function outer() {
var num = 0 //内部变量
return function add() {
//通过return返回add函数,就可以在outer函数外访问了。
num++ //内部函数有引用,作为add函数的一部分了
console.log(num)
}
}
var func1 = outer() //
func1() //实际上是调用add函数, 输出1
func1() //输出2
var func2 = outer()
func2() // 输出1
func2() // 输出2
4. Этот всесторонний анализ
Сначала поймите очень важную концепцию -Значение this может быть подтверждено только при его выполнении, но не может быть подтверждено при его определении!Почему — потому что это часть контекста выполнения, а контекст выполнения нужно определять до выполнения кода, а не когда он определен. См. следующий пример:
// 情况1
function foo() {
console.log(this.a) //1
}
var a = 1
foo()
// 情况2
function fn(){
console.log(this);
}
var obj={fn:fn};
obj.fn(); //this->obj
// 情况3
function CreateJsPerson(name,age){
//this是当前类的一个实例p1
this.name=name; //=>p1.name=name
this.age=age; //=>p1.age=age
}
var p1=new CreateJsPerson("尹华芝",48);
// 情况4
function add(c, d){
return this.a + this.b + c + d;
}
var o = {a:1, b:3};
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16
add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34
// 情况5
<button id="btn1">箭头函数this</button>
<script type="text/javascript">
let btn1 = document.getElementById('btn1');
let obj = {
name: 'kobe',
age: 39,
getName: function () {
btn1.onclick = () => {
console.log(this);//obj
};
}
};
obj.getName();
</script>
Далее мы объясним вышеуказанную ситуацию один за другим.
- Для прямого вызова foo, независимо от того, где находится функция foo, это должно быть окно
- Для obj.foo() нам просто нужно помнить, что кто бы ни вызывал функцию, это это, поэтому в этом сценарии это в функции foo является объектом obj
- В режиме конструктора это в this.xxx=xxx, которое появляется в классе (в теле функции), является экземпляром текущего класса.
- call, apply и bind: это первый параметр
- Стрелочная функция this указывает на: стрелочная функция не имеет собственного this, чтобы увидеть, есть ли функция во внешнем слое, если есть, то this внешней функции - это this внутренней стрелочной функции, если нет , то это окно.
3. Асинхронный
1. Синхронный против асинхронного
Синхронизация, насколько я понимаю, является способом линейного выполнения, поток выполнения не может быть охвачен. Например, когда вы едите после разговора и смотрите в свой телефон после еды, вам нужно дождаться окончания последнего действия, прежде чем выполнять следующее.
Асинхронный — это способ параллельной обработки, вам не нужно ждать завершения выполнения программы, и вы можете выполнять другие задачи. Например, когда человек ест, смотрит в мобильный телефон и разговаривает, это способ асинхронной обработки. Результаты, которые обрабатываются асинхронно в программе, обычно обрабатываются с помощью функций обратного вызова.
// 同步
console.log(100)
alert(200);
console.log(300) //100 200 300
// 异步
console.log(100)
setTimeout(function(){
console.log(200)
})
console.log(300) //100 300 200
2. Асинхронный и однопоточный
Фундаментальная причина, по которой JS должен быть асинхронным, заключается в том, что JS работает в одном потоке, то есть он может делать только одну вещь одновременно и не может использоваться для двух целей. Чтобы воспользоваться вычислительной мощностью многоядерных процессоров, HTML5 предлагает стандарт Web Worker, который позволяет сценариям JavaScript создавать несколько потоков, но подпотоки полностью контролируются основным потоком и не должны работать с DOM. Таким образом, этот новый стандарт не меняет однопоточной природы JavaScript.
Запрос Ajax занимает 5 секунд из-за медленной сети. Если это синхронно, страница застрянет здесь на 5 секунд и ничего не сможет сделать. Если он асинхронный, то намного лучше.Подождите 5 секунд, и делайте другие дела без задержки.Что касается 5-секундного ожидания, то скорость сети слишком низкая, не из-за JS.
3. Интерфейсные асинхронные сценарии
Внешний интерфейс с использованием асинхронных сценариев
- Временные задачи: setTimeout, setInterval
- Сетевой запрос: запрос ajax, динамическая загрузка
- привязка события
4.Event Loop
Полный цикл обработки событий можно разделить на следующие этапы:
-
В начале стек выполнения пустой, можно поставитьСтек выполнения считается структурой стека, в которой хранятся вызовы функций в соответствии с принципом «первым поступил — последним обслужен».. Микро-очередь пуста, а в макро-очереди находится только один сценарий (весь код).
-
Глобальный контекст (тег скрипта) помещается в стек выполнения, синхронизируя выполнение кода. В процессе выполнения он определит, является ли это синхронной задачей или асинхронной задачей.При вызове некоторых интерфейсов могут быть сгенерированы новые макрозадачи и микрозадачи, и они будут помещены в соответствующие очереди задач. После выполнения синхронного кода сценарий сценария будет удален из очереди макросов.Этот процесс, по сути, представляет собой процесс выполнения и исключения из очереди макрозадачи очереди.
-
На предыдущем шаге мы удалили из очереди макрозадачу, а на этом шаге мы рассмотрели микрозадачу. Но будьте осторожны: когда макрозадача удаляется из очереди, задачапо одномувыполняется; в то время как микрозадача удалена из очереди, задачакоманда за командойреализовано. Поэтому мы обрабатываем шаг микроочереди, который будет выполнять задачи в очереди одну за другой и удалять ее из очереди до тех пор, пока очередь не будет очищена.
-
Шаги рендеринга, обновленный интерфейс
-
Проверьте, есть ли задача веб-воркера, если да, обработайте ее.
-
Описанный выше процесс повторяется до тех пор, пока обе очереди не будут опустошены.
Далее, давайте рассмотрим пример, чтобы представить описанный выше процесс:
Promise.resolve().then(()=>{
console.log('Promise1')
setTimeout(()=>{
console.log('setTimeout2')
},0)
})
setTimeout(()=>{
console.log('setTimeout1')
Promise.resolve().then(()=>{
console.log('Promise2')
})
},0)
Окончательный вывод: Promise1, setTimeout1, Promise2, setTimeout2.
- После того, как задача синхронизации (которая относится к задаче макроса) исходного стека выполнения будет завершена, она проверит, существует ли очередь микрозадач, которая существует в вышеуказанном вопросе (есть только одна), а затем выполнит все задачи. в очередь микрозадач выводить Promise1, и в то же время она будет генерировать макро-задачу setTimeout2
- Затем перейдите к проверке очереди задач макроса, задача макроса setTimeout1 выполняет задачу макроса setTimeout1 до setTimeout2 и выводит setTimeout1
- При выполнении макрозадачи setTimeout1 будет сгенерирована микрозадача Promise2 и помещена в очередь микрозадач, затем все задачи в очереди микрозадач будут сначала очищены, и будет выведен Promise2.
- После очистки всех задач в очереди микрозадач она перейдет в очередь задач макросов, чтобы получить еще одну На этот раз выполняется setTimeout2.
4. Цепочка прототипов и наследование
1. Прототипы и цепочки прототипов
Прототип: в JavaScript исходный тип — это объект-прототип, который используется для представления отношений между типами.
Цепочка прототипов: все в JavaScript является объектом, и между объектами и объектами существуют отношения, и они не существуют изолированно. Отношения наследования между объектами в JavaScript указывают на объект родительского класса через объект-прототип, пока он не укажет на объект Object, который формирует цепочку, на которую указывает прототип, которая в профессиональных терминах называется цепочкой прототипов.
var Person = function() {
this.age = 18
this.name = '匿名'
}
var Student = function() {}
//创建继承关系,父类实例作为子类原型
Student.prototype = new Person()
var s1 = new Student()
console.log(s1)
Схема прототипа:
При попытке получить атрибут объекта, если сам объект не имеет этого атрибута, он перейдет к своему__proto__
(т.е. прототип его конструктора). Если верхний слой не будет найден все время, произойдет сбой и будет возвращено значение undefined. Что такое верхний слой?Object.prototype.__proto__ === null
2. Наследование
Представьте несколько распространенных методов наследования (для получения дополнительной информации, пожалуйста, нажмитеШесть распространенных методов наследования в JavaScript):
- Комбинированное наследование цепочки прототипов + заимствованный конструктор
function Parent(value) {
this.val = value
}
Parent.prototype.getValue = function() {
console.log(this.val)
}
function Child(value) {
Parent.call(this, value)
}
Child.prototype = new Parent()
const child = new Child(1)
child.getValue() // 1
child instanceof Parent // true
Суть вышеуказанного метода наследования заключается в передаче конструктора подклассаParent.call(this)
Наследовать свойства родительского класса, а затем изменить прототип дочернего класса наnew Parent()
наследовать функции родительского класса.
Преимущество этого метода наследования в том, что конструктор может передавать параметры, он не будет делиться с родительским классом ссылочным свойством, и функции родительского класса можно использовать повторно, но есть и недостаток в том, что конструктор родительского класса вызывается при наследовании функции родительского класса, в результате чего прототип подкласса имеет больше ненужных свойств родительского класса, что является пустой тратой памяти.
- Паразитическое наследование композиции: этот метод наследования оптимизирует предыдущее наследование композиции.
function Parent(value) {
this.val = value
}
Parent.prototype.getValue = function() {
console.log(this.val)
}
function Child(value) {
Parent.call(this, value)
}
Child.prototype = Object.create(Parent.prototype, {
constructor: {
value: Child,
enumerable: false,
writable: true,
configurable: true
}
})
const child = new Child(1)
child.getValue() // 1
child instanceof Parent // true
Суть приведенной выше реализации наследования состоит в том, чтобы присвоить прототип родительского класса подклассу и установить конструктор в подкласс, что не только решает проблему бесполезных атрибутов родительского класса, но и корректно находит конструктор подкласса.
- ES6 в наследовании классов
Ключевое слово class было введено в ES6. Класс может реализовывать наследование через ключевое слово extends, а также может определять статические методы класса через ключевое слово static. Это намного понятнее и удобнее, чем реализация наследования в ES5 путем изменения цепочки прототипов. должны знать о том,Ключевое слово class — это просто синтаксический сахар для прототипов, наследование JavaScript по-прежнему реализуется на основе прототипов..
class Parent {
constructor(value) {
this.val = value
}
getValue() {
console.log(this.val)
}
}
class Child extends Parent {
constructor(value) {
super(value)
this.val = value
}
}
let child = new Child(1)
child.getValue() // 1
child instanceof Parent // true
Ядром наследования реализации класса является использование расширений, чтобы указать, от какого родительского класса следует наследоваться, а super должен вызываться в конструкторе подкласса, потому что этот код можно рассматривать какParent.call(this, value)
.
Пять, операция DOM и операция спецификации
1. Манипуляции с DOM
Когда веб-страница загружается, браузер создает объектную модель документа (DOM) страницы, Мы можем думать, что DOM — это структура HTML, распознаваемая JS, общий объект JS или массив. Далее мы вводим общие операции DOM:
- Добавление узлов и перемещение узлов
var div1 = document.getElementById('div1')
// 添加新节点
var p1 = document.createElement('p')
p1.innerHTML = 'this is p1'
div1.appendChild(p1) // 添加新创建的元素
// 移动已有节点。注意,这里是“移动”,并不是拷贝
var p2 = document.getElementById('p2')
div1.appendChild(p2)
- получить родительский элемент
var div1 = document.getElementById('div1')
var parent = div1.parentElement
- получить дочерний элемент
var div1 = document.getElementById('div1')
var child = div1.childNodes
- удалить узел
var div1 = document.getElementById('div1')
var child = div1.childNodes
div1.removeChild(child[0])
2. Модель событий DOM и поток событий
Модель событий DOM в захват и всплытие. Когда происходит событие, оно распространяется между дочерними и родительскими элементами. Это распространение делится на три этапа.
(1) Фаза захвата: фаза, на которой события распространяются от оконного объекта к целевому узлу сверху вниз;
(2) Целевой этап: этап, на котором реальный целевой узел обрабатывает событие;
(3) Стадия всплытия: стадия, на которой события распространяются от целевого узла к оконному объекту снизу вверх.
Конкретный процесс захвата событий DOM
Захват идет сверху вниз, события сначала идут от оконного объекта, затем к документу (объекту), затем к html-тегу (получение html-тега через document.documentElement), затем к тегу body (получение тега body через document.body), затем он передается слой за слоем в соответствии с обычной структурой html и, наконец, достигает целевого элемента.
Далее, давайте рассмотрим пример всплытия событий:
// 事件冒泡
<div id="outer">
<div id="inner"></div>
</div>
......
window.onclick = function() {
console.log('window');
};
document.onclick = function() {
console.log('document');
};
document.documentElement.onclick = function() {
console.log('html');
};
document.body.onclick = function() {
console.log('body');
}
outer.onclick = function(ev) {
console.log('outer');
};
inner.onclick = function(ev) {
console.log('inner');
};
Как перестать булькать?
пройти черезevent.stopPropagation()
Этот метод предотвращает всплытие события к родительскому элементу, предотвращая выполнение любых обработчиков родительских событий.
Мы можем добавить событие щелчка внутреннего элемента в приведенном выше примере.event.stopPropagation()
После этого предложения выполнение родительского события блокируется, и в конце печатается только «внутреннее».
inner.onclick = function(ev) {
console.log('inner')
ev.stopPropagation()
}
3. Делегирование мероприятия (делегирование мероприятия)
Поскольку событие будет распространяться до родительского узла на этапе всплытия, функция прослушивателя дочернего узла может быть определена на родительском узле, а функция прослушивателя родительского узла может единообразно обрабатывать события нескольких дочерних элементов. Этот метод называется делегированием событий.
Мы устанавливаем сцену, следующий код,<div>
содержит несколько<a>
, и будет продолжать увеличиваться. что как быстро и легко для всех<a>
Как насчет связывающих событий?
<div id="div1">
<a href="#">a1</a>
<a href="#">a2</a>
<a href="#">a3</a>
<a href="#">a4</a>
</div>
<button>点击增加一个 a 标签</button>
Если каждый<a>
Каждый тег привязан к событию, которое потребляет много памяти. С помощью прокси-сервера событий нам нужно только привязать метод к div родительского контейнера, чтобы независимо от того, какой элемент-потомок был нажат, поведение щелчка родительского контейнера будет запускаться в соответствии с механизмом передачи пузырькового распространения, и то будет выполнен соответствующий метод. , в зависимости от источника события мы можем знать кто нажал и делать разные вещи.
var div1 = document.getElementById('div1')
div1.addEventListener('click', function (e) {
// e.target 可以监听到触发点击事件的元素是哪一个
var target = e.target
if (e.nodeName === 'A') {
// 点击的是 <a> 元素
alert(target.innerHTML)
}
})
Наконец, преимущества использования прокси заключаются в следующем:
- сделать код кратким
- Уменьшите использование памяти браузера
4.Операция со спецификацией
BOM (Объектная модель браузера) — это установка и получение некоторой информации о самом браузере, например, получение ширины и высоты браузера, а также установка адреса, на который браузер может перейти.
- Объект window.screen: содержит информацию об экране пользователя.
- Объект window.location: используется для получения адреса (URL) текущей страницы и перенаправления браузера на новую страницу.
- объект window.history: история просмотров вперед и назад и т. д.
- объект window.navigator: часто используется для получения информации о браузере, мобильного доступа и т. д.
Получить ширину и высоту экрана
console.log(screen.width)
console.log(screen.height)
Получить URL, протокол, путь, параметры, хэш и т. д.
// 例如当前网址是 https://juejin.im/timeline/frontend?a=10&b=10#some
console.log(location.href) // https://juejin.im/timeline/frontend?a=10&b=10#some
console.log(location.protocol) // https:
console.log(location.pathname) // /timeline/frontend
console.log(location.search) // ?a=10&b=10
console.log(location.hash) // #some
Кроме того, есть также вызовы функций браузера вперед и назад и т. д.
history.back()
history.forward()
Получите характеристики браузера (известные как UA), а затем идентифицируйте клиента, например, определите, является ли он браузером Chrome.
var ua = navigator.userAgent
var isChrome = ua.indexOf('Chrome')
console.log(isChrome)
5. Ajax и перекрестный домен
Ajax — это технология асинхронного запроса данных, которая очень полезна для улучшения взаимодействия с пользователем и производительности программы. Проще говоря, Ajax загружает фоновые данные через асинхронные запросы и отображает их на веб-странице без необходимости обновления страницы. Общие сценарии приложений включают проверку формы, успешность входа в систему, подсказки в раскрывающемся списке поиска Baidu и экспресс-запрос номера отслеживания.Цель Ajax — улучшить взаимодействие с пользователем и уменьшить объем передаваемых по сети данных..
Как написать XMLHttpRequest без какой-либо библиотеки
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
// 这里的函数异步执行
if (xhr.readyState == 4) {
if (xhr.status == 200) {
alert(xhr.responseText)
}
}
}
xhr.open("GET", "/api", false)
xhr.send(null)
Потому что браузеры имеют политику одного и того же происхождения из соображений безопасности. То есть, если есть разница в протоколе, доменном имени или порте, это междоменный запрос, и запрос Ajax завершится ошибкой.
тогда даПочему этот механизм введен из соображений безопасности?? Фактически, он в основном используется для предотвращения атак CSRF. Проще говоря, CSRF-атаки используют состояние входа пользователя для инициирования вредоносных запросов.
Тогда давайте рассмотрим вопрос,Запрос является междоменным, поэтому запрос отправлен?? Запрос должен был быть отправлен, но браузер перехватил ответ.
Несколько общих перекрестных решений (для получения подробной информации см.Принципы реализации девяти междоменных методов (полная версия)):
- JSONP: использование одной и той же пары политик происхождения
<script>
Теги не ограничены, но поддерживаются только GET-запросы - CORS: ключом к реализации связи CORS являются внутренние и серверные настройки.
Access-Control-Allow-Origin
Вы можете открыть его, высоко оцененное междоменное решение, намного проще, чем JSONP. - Прокси-сервер промежуточного программного обеспечения узла или обратный прокси-сервер nginx: в основном из-за политики одного и того же происхождения сервер не ограничен
6. Хранение
Разница между sessionStorage, localStorage и куки
- Общая основа: все они сохраняются на стороне браузера, и все они следуют политике одного и того же источника.
- Разница: разница между жизненным циклом и областью применения
Область действия: localStorage может читать/изменять одни и те же данные localStorage по тому же протоколу, тому же имени хоста и тому же порту. sessionStorage немного строже, чем localStorage, кроме протокола, имени хоста, порта, требует еще такое же окно (то есть вкладку браузера)
Жизненный цикл: localStorage — это постоянное локальное хранилище, хранящиеся в нем данные никогда не устареют, и единственный способ заставить его исчезнуть — это удалить его вручную; в то время как sessionStorage — это временное локальное хранилище, это хранилище уровня сеанса, когда Когда сеанс заканчивается (страница закрывается), сохраненный контент также освобождается.6. Модульность
Введение в несколько общих модульных спецификаций (пожалуйста, нажмите для получения подробной информации)Интерфейсное модульное объяснение (полная версия)):
- Спецификация CommonJS в основном используется для программирования на стороне сервера.Загрузка модулей является синхронной, что не подходит для браузерных сред, поскольку синхронность означает блокировку загрузки, а ресурсы браузера загружаются асинхронно, поэтому существует решение AMD CMD.
- Спецификация AMD загружает модули асинхронно в среде браузера, и несколько модулей могут загружаться параллельно. Однако стоимость разработки спецификации AMD высока, код трудно читать и писать, а семантика метода определения модуля не является гладкой.
- Спецификация CMD очень похожа на спецификацию AMD, обе используются для браузерного программирования, опираясь на близость, отложенное выполнение и могут быть легко запущены в Node.js. Однако, в зависимости от упаковки СЗМ, логика загрузки модуля смещена.
- На уровне языковых стандартов ES6 реализует модульные функции, и реализация достаточно проста, она может полностью заменить спецификации CommonJS и AMD и стать общим модульным решением для браузеров и серверов.
Добро пожаловать в публичный аккаунт:Мастер по фронтенду, мы будем свидетелями вашего роста вместе!