Всем привет, я front-end стажер, занимаюсь полтора года, люблю петь, танцевать, читать рэп и программировать. Эта статья является авторским подведением итогов и размышлениями о базовых знаниях фронтенда за более чем год.Эти темы являются подведением итогов для меня и немного скудной информации для всех.Я надеюсь принести вам некоторую помощь и вдохновение. В процессе написания мне помогали многие старшие братья, и я хотел бы поблагодарить брата Кая за его помощь.буклет, ученики Shen SanyuanЕжедневный фронтальный вопросИ многие друзья, которых я никогда не встречал, позвольте мне и другим Мэнсинам также иметь возможность почерпнуть мудрость богатства предшественников и сделать топорThanks♪(・ω・)ノ
В этой статье будут обобщены базовые знания о внешнем интерфейсе для читателей из следующих одиннадцати измерений.
Основы JS
1. Как реализовать let в среде ES5
Вопрос по существу отвечает
letа такжеvarВ чем разница, для этого вопроса мы можем непосредственно посмотреть наbabelРезультаты до и после конвертации смотрите в циклеletКак определяемая переменная решает проблему продвижения переменной
(function(){
for(var i = 0; i < 5; i ++){
console.log(i) // 0 1 2 3 4
}
})();
console.log(i) // Uncaught ReferenceError: i is not defined
Но вопрос не исчерпан, мы возвращаемся кvarа такжеlet/constпо разнице:
-
varОбъявленная переменная будет висеть на окне, иletа такжеconstНе будет -
varОбъявленная переменная имеет подъем переменной, иletа такжеconstНе будет -
letа такжеconstОбъявление формирует область блока и может быть доступно только в пределах области блока, а не между блоками или функциями. - в том же объеме
letа такжеconstПеременная с таким же именем не может быть объявлена, иvarМогу - Временная мертвая зона,
letа такжеconstОбъявленная переменная не может использоваться до объявления
Преобразование babel на самом деле достигает только пунктов 2, 3 и 5.
2. Как реализовать const в среде ES5
Ключом к реализации const являетсяObject.defineProperty()Этот API, этот API используется для добавления или изменения свойств объекта. Настраивая дескрипторы свойств, вы можете точно контролировать поведение свойств.Object.defineProperty()Принимает три параметра:
Object.defineProperty(obj, prop, desc)
| параметр | иллюстрировать |
|---|---|
| obj | объект, на котором определяется свойство |
| prop | Имя свойства для определения или изменения |
| descriptor | дескриптор свойства, который необходимо определить или изменить |
| дескриптор свойства | иллюстрировать | По умолчанию |
|---|---|---|
| value | Значение, соответствующее этому свойству. Может быть любым допустимым значением JavaScript (число, объект, функция и т. д.). По умолчанию не определено | undefined |
| get | Метод, предоставляющий геттер для свойства, или undefined, если геттер отсутствует. | undefined |
| set | Метод, предоставляющий установщик для свойства, или undefined, если установщика нет. Когда значение свойства изменяется, инициируйте выполнение этого метода. | undefined |
| writable | Значение может быть изменено оператором присваивания тогда и только тогда, когда свойство имеет значение true. Значение по умолчанию — ложь | false |
| enumerable | enumerable определяет, могут ли свойства объекта быть перечислены в циклах for...in и Object.keys() | false |
| Configurable | Настраиваемый атрибут указывает, можно ли удалить свойства объекта и можно ли изменить другие атрибуты, кроме значения и атрибутов с возможностью записи. | false |
Для константных неизменяемых функций мы делаем это, устанавливая свойство с возможностью записи
function _const(key, value) {
const desc = {
value,
writable: false
}
Object.defineProperty(window, key, desc)
}
_const('obj', {a: 1}) //定义obj
obj.b = 2 //可以正常给obj的属性赋值
obj = {} //无法赋值新对象
Использованная литература:Как реализовать константу в среде ES5?
3. Рукописный звонок()
call() 方法Вызывает функцию с указанным значением this и одним или несколькими аргументами, заданными отдельно
грамматика:function.call(thisArg, arg1, arg2, ...)
call()Принцип относительно прост.Поскольку this функции указывает на ее прямой вызывающий код, мы меняем вызывающий объект, чтобы завершить изменение, на которое указывает this:
//变更函数调用者示例
function foo() {
console.log(this.name)
}
// 测试
const obj = {
name: '写代码像蔡徐抻'
}
obj.foo = foo // 变更foo的调用者
obj.foo() // '写代码像蔡徐抻'
Основываясь на вышеуказанных принципах, мы можем реализовать call() с помощью двух строк кода.
Function.prototype.myCall = function(thisArg, ...args) {
thisArg.fn = this // this指向调用call的对象,即我们要改变this指向的函数
return thisArg.fn(...args) // 执行函数并return其执行结果
}
Но у нас есть некоторые детали для работы:
Function.prototype.myCall = function(thisArg, ...args) {
const fn = Symbol('fn') // 声明一个独有的Symbol属性, 防止fn覆盖已有属性
thisArg = thisArg || window // 若没有传入this, 默认绑定window对象
thisArg[fn] = this // this指向调用call的对象,即我们要改变this指向的函数
const result = thisArg[fn](...args) // 执行当前函数
delete thisArg[fn] // 删除我们声明的fn属性
return result // 返回函数执行结果
}
//测试
foo.myCall(obj) // 输出'写代码像蔡徐抻'
4. Рукописное применение()
Метод apply() вызывает функцию с заданным значением this и аргументами, представленными в виде массива (или объекта, подобного массиву).
Синтаксис: func.apply(thisArg, [argsArray])
apply()а такжеcall()Аналогично, разница в том, что call() принимает список параметров, а apply() принимает массив параметров, поэтому мы можем просто изменить форму входного параметра в реализации call()
Function.prototype.myApply = function(thisArg, args) {
const fn = Symbol('fn') // 声明一个独有的Symbol属性, 防止fn覆盖已有属性
thisArg = thisArg || window // 若没有传入this, 默认绑定window对象
thisArg[fn] = this // this指向调用call的对象,即我们要改变this指向的函数
const result = thisArg[fn](...args) // 执行当前函数(此处说明一下:虽然apply()接收的是一个数组,但在调用原函数时,依然要展开参数数组。可以对照原生apply(),原函数接收到展开的参数数组)
delete thisArg[fn] // 删除我们声明的fn属性
return result // 返回函数执行结果
}
//测试
foo.myApply(obj, []) // 输出'写代码像蔡徐抻'
5. Рукописная привязка()
bind()Метод создает новую функцию.При вызове bind() this этой новой функции указывается в качестве первого параметра bind(), а остальные параметры будут использоваться как параметры новой функции для использования при вызов.
Синтаксис: function.bind(thisArg, arg1, arg2, ...)
С точки зрения использования кажется, что оболочка слоя функции для вызова/применения реализует bind():
Function.prototype.myBind = function(thisArg, ...args) {
return () => {
this.apply(thisArg, args)
}
}
Но мы упустили из виду три момента:
- В дополнение к этому, bind() также принимает другие параметры.Функция, возвращаемая bind(), также принимает параметры.Обе части параметров должны быть переданы в возвращаемую функцию.
- new изменит эту точку: если функция, связанная с привязкой, новая, то эта точка изменится, указывая на экземпляр текущей функции.
- Свойства и методы исходной функции в цепочке прототипов не сохраняются.
Function.prototype.myBind = function (thisArg, ...args) {
var self = this
// new优先级
var fbound = function () {
self.apply(this instanceof self ? this : thisArg, args.concat(Array.prototype.slice.call(arguments)))
}
// 继承原型上的属性和方法
fbound.prototype = Object.create(self.prototype);
return fbound;
}
//测试
const obj = { name: '写代码像蔡徐抻' }
function foo() {
console.log(this.name)
console.log(arguments)
}
foo.myBind(obj, 'a', 'b', 'c')() //输出写代码像蔡徐抻 ['a', 'b', 'c']
6. Напишите вручную антивибрационную функцию
Понятия anti-shake и throttling относительно просты, поэтому мы не будем тратить слишком много места на вопрос «что такое anti-shake throttling», просто нажмите:
антивибрационный, т.е.
短时间内大量触发同一事件,只会执行一次函数, принцип реализации设置一个定时器,约定在xx毫秒后再触发事件处理,每次触发事件都会重新设置计时器,直到xx毫秒内无第二次操作, Защита от сотрясений часто используется для отслеживания обработки событий в полях поиска/полосах прокрутки. Если защита от сотрясений не реализована, обработка событий будет запускаться каждый раз, когда вы вводите слово или прокручиваете экран, что приводит к потере производительности.
function debounce(func, wait) {
let timeout = null
return function() {
let context = this
let args = arguments
if (timeout) clearTimeout(timeout)
timeout = setTimeout(() => {
func.apply(context, args)
}, wait)
}
}
7. Напишите функцию дросселирования вручную
Защита от сотрясений да
延迟执行, в то время как дросселирование间隔执行, дросселирование функции есть每隔一段时间就执行一次, принцип реализации设置一个定时器,约定xx毫秒后执行事件,如果时间到了,那么执行函数并重置定时器, Отличие от защиты от сотрясений заключается в том, что при защите от сотрясений таймер сбрасывается каждый раз, когда инициируется событие, а при регулировании таймер сбрасывается по истечении времени его действия.
function throttle(func, wait) {
let timeout = null
return function() {
let context = this
let args = arguments
if (!timeout) {
timeout = setTimeout(() => {
timeout = null
func.apply(context, args)
}, wait)
}
}
}
Реализация 2: Используйте две метки времени
prev旧时间戳а такжеnow新时间戳, каждый раз, когда событие запускается, оценивается разница во времени между ними.Если указанное время достигнуто, функция выполняется, и старая метка времени сбрасывается
function throttle(func, wait) {
var prev = 0;
return function() {
let now = Date.now();
let context = this;
let args = arguments;
if (now - prev > wait) {
func.apply(context, args);
prev = now;
}
}
}
8. Сглаживание массива
для
[1, [1,2], [1,2,3]]Такой многоуровневый вложенный массив, как мы можем сгладить его в[1, 1, 2, 1, 2, 3]Как насчет такого одномерного массива:
1. Плоский ES6 ()
const arr = [1, [1,2], [1,2,3]]
arr.flat(Infinity) // [1, 1, 2, 1, 2, 3]
2. Регуляризация после сериализации
const arr = [1, [1,2], [1,2,3]]
const str = `[${JSON.stringify(arr).replace(/(\[|\])/g, '')}]`
JSON.parse(str) // [1, 1, 2, 1, 2, 3]
3. Рекурсия
Для данных с древовидной структурой наиболее прямым способом работы с ними является рекурсия.
const arr = [1, [1,2], [1,2,3]]
function flat(arr) {
let result = []
for (const item of arr) {
item instanceof Array ? result = result.concat(flat(item)) : result.push(item)
}
return result
}
flat(arr) // [1, 1, 2, 1, 2, 3]
4.уменьшить() рекурсия
const arr = [1, [1,2], [1,2,3]]
function flat(arr) {
return arr.reduce((prev, cur) => {
return prev.concat(cur instanceof Array ? flat(cur) : cur)
}, [])
}
flat(arr) // [1, 1, 2, 1, 2, 3]
5. Итерация + оператор спреда
// 每次while都会合并一层的元素,这里第一次合并结果为[1, 1, 2, 1, 2, 3, [4,4,4]]
// 然后arr.some判定数组中是否存在数组,因为存在[4,4,4],继续进入第二次循环进行合并
let arr = [1, [1,2], [1,2,3,[4,4,4]]]
while (arr.some(Array.isArray)) {
arr = [].concat(...arr);
}
console.log(arr) // [1, 1, 2, 1, 2, 3, 4, 4, 4]
9. Напишите обещание от руки
Реализация промиса, соответствующего спецификации, относительно долгая, рекомендуется прочитать предыдущую статью автора:Асинхронное программирование две-три вещи | Анализ принципа реализации Promise/async/Generator | 9k слов
JS объектно-ориентированный
Все является объектом в JS, но JS на самом деле не является объектно-ориентированным (ООП) языком, потому что ему не хватает类(class)Концепция чего-либо. Хотя ES6 представилclassа такжеextends, что позволяет нам легко реализовывать классы и наследование. Но в JS нет реальных классов. Классы JS моделируются функциями и механизмами цепочки прототипов. В этом разделе мы рассмотрим, как использовать функции и цепочки прототипов для реализации объектно-ориентированных функций JS в среде ES5.
Прежде чем начать, давайте повторим знание цепочки прототипов,newа также继承Другие реализации основаны на механизме цепочки прототипов. Много информации о цепочке прототипов можно написать тысячами слов, но я не думаю, что читатели должны думать, что цепочка прототипов слишком сложна, в нее легко вникнуть. ядру цепочки прототипов нужно помнить только три вещи.
- Каждый объект имеет
__proto__属性, это свойство указывает на его объект-прототип.При вызове методов и свойств экземпляра, если он не найден в объекте-экземпляре, он будет искать объект-прототип. - конструктор
prototype属性также указывает на объект-прототип экземпляра - прототип объекта
constructor属性указать на конструктор
1. Смоделируйте внедрение новых
Сначала нам нужно знатьnewЧто вы наделали
-
Создайте новый объект и наследуйте его конструктор
prototype, этот шаг заключается в наследовании свойств и методов прототипа конструктора. -
Выполнить конструктор внутри метода
thisобозначается как этот новый экземпляр, этот шаг заключается в выполнении операции присваивания внутри конструктора - вернуть новый экземпляр(В спецификации указано, что если конструктор возвращает объект, то вернуть объект, в противном случае вернуть новый объект, созданный на первом шаге)
// new是关键字,这里我们用函数来模拟,new Foo(args) <=> myNew(Foo, args)
function myNew(foo, ...args) {
// 创建新对象,并继承构造方法的prototype属性, 这一步是为了把obj挂原型链上, 相当于obj.__proto__ = Foo.prototype
let obj = Object.create(foo.prototype)
// 执行构造方法, 并为其绑定新this, 这一步是为了让构造方法能进行this.name = name之类的操作, args是构造方法的入参, 因为这里用myNew模拟, 所以入参从myNew传入
let result = foo.apply(obj, args)
// 如果构造方法已经return了一个对象,那么就返回该对象,否则返回myNew创建的新对象(一般情况下,构造方法不会返回新实例,但使用者可以选择返回新实例来覆盖new创建的对象)
return Object.prototype.toString.call(result) === '[object Object]' ? result : obj
}
// 测试:
function Foo(name) {
this.name = name
}
const newObj = myNew(Foo, 'zhangsan')
console.log(newObj) // Foo {name: "zhangsan"}
console.log(newObj instanceof Foo) // true
2. Как в ES5 реализовано наследование
Когда дело доходит до наследования, проще всего подумать о ES6.extends, конечно, если только ответ на это определенно неквалифицированный, мы должны реализовать наследование с точки зрения цепочки функций и прототипов, Далее мы реализуем квалифицированное наследование шаг за шагом и постепенно.
1. Наследование цепочки прототипов
Принцип наследования по цепочке прототипов очень прост: пусть объект-прототип подкласса напрямую указывает на экземпляр родительского класса.Когда экземпляр подкласса не может найти соответствующие свойства и методы, он будет искать свой объект-прототип, то есть родительский экземпляр класса, чтобы реализовать наследование свойств и методов родительского класса
// 父类
function Parent() {
this.name = '写代码像蔡徐抻'
}
// 父类的原型方法
Parent.prototype.getName = function() {
return this.name
}
// 子类
function Child() {}
// 让子类的原型对象指向父类实例, 这样一来在Child实例中找不到的属性和方法就会到原型对象(父类实例)上寻找
Child.prototype = new Parent()
Child.prototype.constructor = Child // 根据原型链的规则,顺便绑定一下constructor, 这一步不影响继承, 只是在用到constructor时会需要
// 然后Child实例就能访问到父类及其原型上的name属性和getName()方法
const child = new Child()
child.name // '写代码像蔡徐抻'
child.getName() // '写代码像蔡徐抻'
Недостатки прототипного наследования:
- Поскольку все прототипы дочерних экземпляров указывают на один и тот же родительский экземпляр, изменение переменной типа ссылки родительского класса дочернего экземпляра повлияет на все дочерние экземпляры.
- При создании экземпляра подкласса нет возможности передать параметры в конструктор родительского класса, то есть нет реализации
super()функция
// 示例:
function Parent() {
this.name = ['写代码像蔡徐抻']
}
Parent.prototype.getName = function() {
return this.name
}
function Child() {}
Child.prototype = new Parent()
Child.prototype.constructor = Child
// 测试
const child1 = new Child()
const child2 = new Child()
child1.name[0] = 'foo'
console.log(child1.name) // ['foo']
console.log(child2.name) // ['foo'] (预期是['写代码像蔡徐抻'], 对child1.name的修改引起了所有child实例的变化)
2. Наследование конструктора
Наследование конструктора, то есть выполнение конструктора родительского класса в конструкторе подкласса и привязка к нему конструктора подклассаthis, пусть конструктор родительского класса подключает как свойства-члены, так и методы к子类的thisUp, это может не только избежать совместного использования экземпляра прототипа между экземплярами, но и передать параметры конструктору родительского класса.
function Parent(name) {
this.name = [name]
}
Parent.prototype.getName = function() {
return this.name
}
function Child() {
Parent.call(this, 'zhangsan') // 执行父类构造方法并绑定子类的this, 使得父类中的属性能够赋到子类的this上
}
//测试
const child1 = new Child()
const child2 = new Child()
child1.name[0] = 'foo'
console.log(child1.name) // ['foo']
console.log(child2.name) // ['zhangsan']
child2.getName() // 报错,找不到getName(), 构造函数继承的方式继承不到父类原型上的属性和方法
Недостатки наследования конструктора:
- Невозможно наследовать свойства и методы прототипа родительского класса.
3. Композиционное наследование
Поскольку наследование по цепочке прототипов и наследование по конструктору имеют дополнительные преимущества и недостатки, почему бы нам не использовать их в комбинации, чтобы получить комбинированное наследование, объединяющее эти два понятия?
function Parent(name) {
this.name = [name]
}
Parent.prototype.getName = function() {
return this.name
}
function Child() {
// 构造函数继承
Parent.call(this, 'zhangsan')
}
//原型链继承
Child.prototype = new Parent()
Child.prototype.constructor = Child
//测试
const child1 = new Child()
const child2 = new Child()
child1.name[0] = 'foo'
console.log(child1.name) // ['foo']
console.log(child2.name) // ['zhangsan']
child2.getName() // ['zhangsan']
Недостатки наследования композиции:
- Каждый раз, когда создается экземпляр подкласса, конструктор выполняется дважды (
Parent.call()а такжеnew Parent()), хотя это не влияет на наследование родительского класса, при создании экземпляра подкласса в прототипе будет два одинаковых свойства и метода, что не элегантно
4. Наследование паразитарного состава
Чтобы решить проблему двукратного выполнения конструктора, мы指向父类实例изменить на指向父类原型, минус одно выполнение конструктора
function Parent(name) {
this.name = [name]
}
Parent.prototype.getName = function() {
return this.name
}
function Child() {
// 构造函数继承
Parent.call(this, 'zhangsan')
}
//原型链继承
// Child.prototype = new Parent()
Child.prototype = Parent.prototype //将`指向父类实例`改为`指向父类原型`
Child.prototype.constructor = Child
//测试
const child1 = new Child()
const child2 = new Child()
child1.name[0] = 'foo'
console.log(child1.name) // ['foo']
console.log(child2.name) // ['zhangsan']
child2.getName() // ['zhangsan']
Но с этим методом есть проблема: поскольку прототип подкласса и прототип родительского класса указывают на один и тот же объект, наши операции над прототипом подкласса будут влиять на прототип родительского класса, например, присвоивChild.prototypeДобавление метода getName() приведет кParent.prototypeТакже добавлен или переопределен метод getName(), чтобы решить эту проблему, мы даемParent.prototypeсделать мелкую копию
function Parent(name) {
this.name = [name]
}
Parent.prototype.getName = function() {
return this.name
}
function Child() {
// 构造函数继承
Parent.call(this, 'zhangsan')
}
//原型链继承
// Child.prototype = new Parent()
Child.prototype = Object.create(Parent.prototype) //将`指向父类实例`改为`指向父类原型`
Child.prototype.constructor = Child
//测试
const child = new Child()
const parent = new Parent()
child.getName() // ['zhangsan']
parent.getName() // 报错, 找不到getName()
На этом мы завершили реализацию наследования в среде ES5, этот метод наследования называется寄生组合式继承, является наиболее зрелым методом наследования в настоящее время.Babel также использует паразитное комбинированное наследование для преобразования наследования ES6.
Рассмотрим процесс реализации:
Сначала легче всего подумать о том,原型链继承, наследуют свойства и методы родительского класса, указывая прототип экземпляра дочернего класса на экземпляр родительского класса, но дефект наследования цепочки прототипов заключается в том, что对子类实例继承的引用类型的修改会影响到所有的实例对象так же как无法向父类的构造方法传参.
Поэтому мы представили构造函数继承, вызывая конструктор родительского класса в конструкторе подкласса и передавая в подклассе this, чтобы получить свойства и методы родительского класса, но наследование конструктора также имеет дефекты, наследование конструктора不能继承到父类原型链上的属性和方法.
Поэтому мы объединили преимущества двух наследств и предложили组合式继承, но композиционное наследование также создает новые проблемы.每次创建子类实例都执行了两次父类构造方法, мы проходим子类原型指向父类实例изменить на子类原型指向父类原型的浅拷贝Решить эту проблему, то есть осознать наконец -寄生组合式继承
Механизм двигателя V8
1. Как выполнить кусок кода JS в V8
- готовить: Проверять наличие синтаксических ошибок, но не создавать AST.
- Сгенерировать АСТ: Создание абстрактного синтаксического дерева после лексического/синтаксического анализа.
- генерировать байт-код: Базовый компилятор (Ignition) преобразует AST в байт-код.
- Сгенерировать машинный код: оптимизирующий компилятор (Turbofan) преобразует байт-код в оптимизированный машинный код. Кроме того, в процессе выполнения байт-кода построчно, если фрагмент кода выполняется часто, V8 будет напрямую преобразовывать этот код в машинный код. Сохраните его. , следующее выполнение не должно проходить через байт-код, что оптимизирует скорость выполнения
Вышеприведенные пункты являются лишь минималистским изложением механизма исполнения V8.Рекомендуется ознакомиться со справочными материалами:
1.Как работает V8 — конвейер выполнения JavaScript в V8
2.Обзор процесса выполнения JavaScript Engine V8
2. Введение в подсчет ссылок и очистку меток
- подсчет ссылок: Назначить переменной ссылочный тип, количество ссылок на объект равно +1, если переменная становится другим значением, то количество ссылок на объект равно -1, и сборщик мусора переработает объект, количество ссылок 0. Однако, когда на объект ссылаются циклически, количество ссылок никогда не обнуляется, что приводит к невозможности освобождения памяти.
- пометить как очищенный: Сборщик мусора сначала помечает все объекты в памяти, затем проходит от корневого узла, удаляет пометки ссылочных объектов и объектов в работающей среде, а оставшиеся помеченные объекты являются недоступными объектами, ожидающими повторного использования.
3. Как V8 выполняет сборку мусора
В движке JS есть два основных места хранения переменных: память стека и память кучи.В памяти стека хранится адрес памяти данных базового типа и данных ссылочного типа, а в памяти кучи хранятся данные ссылочного типа.
Переработка памяти стека:
Память стека перерабатывается после переключения контекста стека вызовов, что относительно просто.
Восстановление кучи памяти:
Куча памяти V8 разделена на память нового поколения и память старого поколения.Память нового поколения является временно выделенной памятью, и время ее существования короткое, а память старого поколения существует долгое время.
- Механизм рециркуляции памяти нового поколения:
- Новое поколение имеет небольшой объем памяти, всего 32 Мб в 64-битной системе. Память нового поколения делится наОт доДве части: при сборке мусора сначала сканируйте From, перерабатывайте невыжившие объекты, последовательно копируйте уцелевшие объекты в To, затем меняйте местами From/To и ждите следующей перезаписи.
- Механизм рециркуляции памяти старого поколения
- повышение: Если переменные нового поколения все еще существуют после нескольких коллекций, они будут помещены в память старого поколения.
- пометить как очищенный: Память старого поколения сначала просматривает все объекты и помечает их, затем снимает пометки с объектов, которые используются или на которые строго ссылаются, и перерабатывает помеченные объекты.
- дефрагментация памяти: переместить объект в один конец памяти
Использованная литература:Разговор о сборке мусора двигателя V8
4. Почему JS медленнее, чем C++ и другие языки, и какие оптимизации были сделаны в V8?
- Проблемы с JS:
- динамический тип: В результате каждый раз, когда вы обращаетесь к методам properties/seek, вам нужно сначала проверить тип, кроме того, динамические типы также сложно оптимизировать на этапе компиляции.
- доступ к собственности: Методы и свойства в таких языках, как C++/Java, хранятся в массивах, которые можно получить только путем смещения массива, тогда как JS хранится в объектах, и хеш-запросы выполняются каждый раз при их получении.
- Оптимизации для V8:
- Оптимизация JIT (компиляция точно в срок): по сравнению с компилируемыми языками, такими как C++/Java, JS интерпретируется и выполняется одновременно, что неэффективно. V8 оптимизирует этот процесс: если фрагмент кода выполняется несколько раз, V8 преобразует этот код в машинный код и кэширует его, а при следующем запуске использует машинный код напрямую.
- скрытый класс: Для таких языков, как C++, информацию о переменных можно получить через смещения с помощью всего нескольких инструкций, в то время как JS необходимо выполнять сопоставление строк, что неэффективно.V8 заимствует идею класса и позиции смещения для разделения объектов на разные группы, т.е. скрытые классы
- Встроенный кеш: то есть результат запроса кешированного объекта. Общий процесс запроса: получить адрес скрытого класса -> найти значение смещения в соответствии с именем атрибута -> вычислить адрес атрибута, встроенный кеш - это кеш результата этого процесса.
- Управление сбором мусора: описано выше
Использованная литература:Почему двигатель V8 такой быстрый?
Механизм рендеринга в браузере
1. Каков процесс рендеринга в браузере?
- HTML и CSS анализируются отдельно для создания дерева DOM и дерева CSSOM.
- объединить в дерево рендеринга
- Вёрстка по дереву рендеринга
- Наконец, вызовите графический процессор, чтобы отрисовать и отобразить его на экране.
2. Как ускорить скорость первого экрана согласно механизму рендеринга браузера
- Оптимизировать размер файла: загрузка и синтаксический анализ HTML и CSS блокирует создание дерева рендеринга, что влияет на скорость отображения первого экрана, поэтому мы можем ускорить скорость первого экрана, оптимизировав размер файла и уменьшив уровень файлов CSS.
- Избегайте загрузки ресурсов, блокирующих синтаксический анализ документов: когда браузер анализирует тег
3. Что такое рефлоу (перестановка) и при каких обстоятельствах сработает рефлоу
- При изменении размера или положения элемента дерево рендеринга необходимо пересчитывать, то есть перекомпоновывать.
- Геометрические свойства элементов DOM (
width/height/padding/margin/border) изменения вызовут перекомпоновку - Перемещение или увеличение элемента DOM вызывает перекомпоновку
- прочти и напиши
offset/scroll/clientПерекомпоновка будет запущена, когда свойства ожидаются - передача
window.getComputedStyleвызовет перекомпоновку
4. Что такое перерисовка и при каких обстоятельствах она вызывает перерисовку
- Когда стиль DOM изменился, не повлияв на геометрию DOM, будет запущена перерисовка, но перекомпоновка не будет запущена. Перерисовка лучше, чем перекомпоновка по производительности, потому что информацию о положении DOM не нужно обновлять, а процесс компоновки опускается.
5. Что такое GPU-ускорение, как использовать GPU-ускорение, недостатки GPU-ускорения
- преимущество: При использовании таких атрибутов, как трансформация, непрозрачность, фильтры и т. д., обработка будет производиться непосредственно в графическом процессоре, и изменения этих атрибутов не вызовут перекомпоновку и перерисовку
- недостаток: Шрифты рендеринга графическим процессором могут привести к размытию шрифтов, а слишком интенсивная обработка графическим процессором может вызвать проблемы с памятью.
6. Как уменьшить обратный поток
- использовать
classзаменятьstyle, сократить использование стиля - использовать
resize、scrollОбработка против сотрясения и дросселирования, обе из которых напрямую приведут к обратному потоку. - использовать
visibilityзаменятьdisplay: none, потому что первое вызовет только перерисовку, второе вызовет перекомпоновку - При пакетном изменении элементов можно сначала удалить элементы из потока документов, а затем поместить их в поток документов после завершения модификации.
- Чтобы избежать запуска синхронных событий макета, мы получаем
offsetWidthКогда используется значение этого типа атрибута, вы можете использовать переменную для хранения результата запроса, чтобы избежать множественных запросов.offset/scroll/clientПерекомпоновка будет запущена при запросе свойств - Для сложных анимационных эффектов используйте абсолютное позиционирование, чтобы они не попадали в поток документа. Сложные анимационные эффекты часто вызывают перекомпоновку и перерисовку. Мы можем установить абсолютное позиционирование элементов анимации, чтобы отделить их от потока документа, чтобы избежать повторной перекомпоновки и перерисовки .
Использованная литература:Механизмы рендеринга в браузере, которые вы должны понимать
Политика кэширования браузера
1. Введите расположение и приоритет кеша браузера
- Service Worker
- Кэш памяти
- Дисковый кэш
- Нажмите кэш
- Если вышеуказанный кеш не попал, будет сделан сетевой запрос
2. Расскажите о разнице между разными кэшами
- Service Worker
Подобно Web Worker, это независимый поток. Мы можем кэшировать файлы в этом потоке и читать файлы здесь, когда они нужны основному потоку. Service Worker позволяет нам свободно выбирать, какие файлы кэшировать, а также правила сопоставления и чтения файлов. и кеш постоянный
- Memory Cache
То есть кеш памяти, кеш памяти не персистентный, кеш будет освобождаться по мере освобождения процесса
- Disk Cache
То есть кеш жесткого диска. По сравнению с кешем памяти, кеш жесткого диска имеет лучшую устойчивость и емкость. Он будет судить, какие ресурсы необходимо кэшировать, в соответствии с полями HTTP-заголовка.
- Push Cache
То есть push-кеш, который является содержимым HTTP/2 и в настоящее время используется меньше.
3. Представьте стратегию кэширования браузера
Сильный кеш (не спрашивайте кеш у сервера)
Установить истекает
- то есть время истечения, например.
「Expires: Thu, 26 Dec 2019 10:30:42 GMT」Указывает, что срок действия кеша истечет по истечении этого времени. Дата истечения срока действия является абсолютной датой. Если локальная дата изменена или локальная дата не соответствует дате сервера, время истечения срока действия кеша будет неправильным.
Установить контроль кэша
- Новое поле HTTP/1.1, Cache-Control может пройти
max-ageполе для установки времени истечения срока действия, например.「Cache-Control:max-age=3600」Кроме того, можно настроить Cache-Control.private/no-cacheи другие поля
Согласовать кеш (необходимо спросить сервер, истек ли срок действия кеша)
Last-Modified
- То есть время последней модификации.Когда браузер запрашивает ресурс в первый раз, сервер добавит заголовок ответа
Last-Modified, когда браузер снова запрашивает ресурс, браузер выводит его в заголовке запросаIf-Modified-SinceПоле, значение поля — это время последней модификации, возвращенное предыдущим сервером.Сервер сравнивает два раза и возвращает 304, если они совпадают, в противном случае возвращает новый ресурс и обновляет Last-Modified
ETag
- Новое поле в HTTP/1.1 представляет собой уникальный идентификатор файла.Поскольку содержимое файла изменяется, ETag будет пересчитываться. Процесс кэширования аналогичен Last-Modified: сервер отправляет поле ETag -> браузер отправляет If-None-Match при повторном запросе -> Если значение ETag не совпадает, файл изменился, вернуть новый ресурс и обновите ETag, если он совпадает, верните 304
Сравните два
- ETag более точен, чем Last-Modified: если мы откроем файл без изменений, Last-Modified также изменится, а единица времени Last-Modified равна одной секунде.Если файл был изменен в течение одной секунды, он все равно попадет в тайник
- Если политика кэширования не задана, браузер будет использовать дату в заголовке ответа минус 10% от значения Last-Modified в качестве времени кэширования.
Использованная литература:Анализ механизма кэширования браузера
Связанные с сетью
1. Расскажите о семиуровневой сетевой модели OSI, на каком уровне находятся TCP/IP и HTTP.
| Модель | Обзор | единица измерения |
|---|---|---|
| физический слой | Средство сетевого соединения, такое как сетевой кабель или оптоволоконный кабель, по которому данные передаются в битах. | bit |
| канальный уровень | Канальный уровень инкапсулирует биты в кадры данных и передает их | Рамка |
| Сетевой уровень | Определите IP-адреса, определите функции маршрутизации, установите связь между хостами | пакет данных |
| транспортный уровень | Отвечает за надежную или ненадежную доставку данных и устанавливает связь между портами. | сегмент данных |
| сеансовый уровень | Управляйте возможностями сеанса между приложениями, различайте разные процессы | |
| уровень представления | Идентификация формата данных, базовые функции сжатия и шифрования | |
| прикладной уровень | Различные прикладные программы |
2. Каковы общие коды состояния HTTP
Начинается с 2xx (успешный запрос)
200 OK: запрос, отправленный клиентом на сервер, обрабатывается нормально и возвращается
Начинается с 3xx (перенаправление)
301 Moved Permanently: Постоянная переадресация, запрошенная веб-страница была постоянно перемещена в новое место. Когда сервер возвращает этот ответ, он автоматически перенаправляет запрашивающую сторону в новое место.
302 Moved Permanently: временное перенаправление, запрошенная веб-страница была временно перемещена в новое место. В настоящее время сервер отвечает на запросы с веб-страницы в другом месте, но запрашивающая сторона должна продолжать использовать исходное местоположение для будущих запросов.
304 Not Modified: Не изменяется, поскольку последний запрос, запрошенная веб-страница не была изменена. Когда сервер возвращает этот ответ, он не вернется к веб-контенту
Начинается с 4xx (ошибка клиента)
400 Bad Request: Неверный запрос, сервер не понимает синтаксис запроса, частая ошибка при передаче параметров клиентом
401 Unauthorized: неавторизованный, указывающий, что для отправленного запроса требуется аутентификационная информация, прошедшая HTTP-аутентификацию, что является обычным явлением, когда клиент не вошел в систему.
403 Forbidden: Запрещено, сервер отклоняет запрос, обычно из-за недостаточных прав клиента
404 Not Found: не найден, сервер не может найти соответствующий ресурс
Начинается с 5xx (ошибка сервера)
500 Inter Server Error: Внутренняя ошибка сервера, сервер обнаружил ошибку и не смог выполнить запрос
501 Not Implemented: Еще не реализовано, сервер не имеет возможности выполнить запрос
502 Bad Gateway: от вышестоящего сервера получен неверный ответ, когда сервер, работающий в качестве шлюза или прокси, попытался выполнить запрос.
503 service unavailable: Услуга недоступна, сервер в данный момент недоступен (перегружен или отключен на техническое обслуживание). Обычно временное состояние.
3. В чем разница между GET-запросом и POST-запросом
стандартный ответ:
- Параметры запроса GET помещаются в URL-адрес, а параметры запроса POST помещаются в тело запроса.
- Длина параметра запроса GET ограничена, длина параметра запроса POST может быть очень большой
- Запросы POST немного безопаснее, чем запросы GET, потому что параметры запроса GET находятся в URL-адресе и имеют историю.
- Запросы GET можно кэшировать, POST нельзя.
Идем дальше:
На самом деле протокол HTTP не требует, чтобы параметры запроса GET/POST были помещены в URL-адрес или в тело запроса, а также не указывает длину запроса GET. каждым браузером. Принципиальное различие между GET и POST заключается в том, что:Запросы GET являются идемпотентными, а запросы POST — нет.
Идемпотентность означает, что один или несколько запросов к ресурсу имеют одинаковые побочные эффекты. Например, поиск — это идемпотентная операция, а удаление и добавление — не идемпотентные операции.
Поскольку запрос GET является идемпотентным, в плохой сетевой среде запрос GET может повторяться, что приводит к риску дублирования операций с данными, поэтому запрос GET используется для операций без побочных эффектов (таких как поиск, добавление/удаление и т.д. Операция подходит для POST
Использованная литература:HTTP | Разница между GET и POST? Большинство ответов в Интернете неверны
4. Из каких частей состоит сообщение HTTP-запроса?
Сообщение HTTP-запроса состоит из четырех частей: строки запроса, заголовка запроса, пустой строки и данных запроса.
5. Общие заголовки запросов/ответов HTTP и их значения
Общие заголовки (заголовки, которые имеют как заголовки запросов, так и заголовки ответов)
| поле | эффект | стоимость |
|---|---|---|
| Cache-Control | кэш управления | общедоступный: указывает, что ответ может быть кэширован любым объектом (включая клиентские/прокси-серверы) private (по умолчанию): ответы могут кэшироваться только одним клиентом, а не прокси-серверами. no-cache: кеш должен быть проверен сервером. Прежде чем браузер использует кеш, он сравнит ETag. Если он не изменился, он вернет 304 и будет использовать кеш. no-store: отключить любое кэширование |
| Connection | Требуются ли постоянные соединения (постоянные соединения HTTP 1.1 по умолчанию) | keep-alive / close |
| Transfer-Encoding | Формат кодирования передачи тела сообщения | chunked (разбитый по частям) / identity (несжатый и измененный) / gzip (сжатие LZ77) / Compress (сжатие LZW, устарело) / deflate (сжатие структуры zlib) |
заголовок запроса
| поле | эффект | грамматика |
|---|---|---|
| Accept | Сообщите (серверу), какой контент может обрабатывать клиент. | текст/html, изображение/*, */* |
| If-Modified-Since | БудуLast-ModifiedЗначение отправляется на сервер, чтобы спросить, истек ли срок действия ресурса (изменен), и если он истекает, он вернет новый ресурс, в противном случае он вернет 304 |
Пример: If-Modified-Since: среда, 21 октября 2015 г., 07:28:00 по Гринвичу. |
| If-Unmodified-Since | БудуLast-ModifiedЗначение отправляется на сервер, чтобы узнать, был ли файл изменен, если нет, он вернет 200, в противном случае он вернет ошибку предварительной обработки 412, которую можно использовать для возобновления загрузки. С точки зрения непрофессионалаIf-Unmodified-Sinceзагружается, когда файл не изменен,If-Modified-Sinceзагружается при изменении файла |
Пример: If-Unmodified-Since: среда, 21 октября 2015 г., 07:28:00 по Гринвичу. |
| If-None-Match | БудуETagЗначение отправляется на сервер, чтобы спросить, истек ли срок действия ресурса (изменен), и если он истекает, он вернет новый ресурс, в противном случае он вернет 304 |
Пример: If-None-Match: "bfc13a6472992d82d" |
| If-Match | БудуETagЗначение файла отправляется на сервер, чтобы узнать, был ли файл изменен.Если нет, он вернет 200, в противном случае он вернет ошибку предварительной обработки 412, которую можно использовать для возобновления загрузки с точки останова. |
Пример: Если-Match: "bfc129c88ca92d82d" |
| Range | Сообщите серверу, какую часть файла нужно вернуть для возобновления загрузки. | Пример: Диапазон: байты=200-1000, 2000-6576, 19000- |
| Host | Указывает доменное имя сервера (для виртуальных хостов) и (необязательно) номер порта TCP, на котором сервер прослушивает | Пример: Хост: www.baidu.com |
| User-Agent | Сообщите HTTP-серверу имя и версию операционной системы и браузера, используемых клиентом. | User-Agent: Mozilla/<version> (<system-information>) <platform> (<platform-details>) <extensions> |
заголовок ответа
| поле | эффект | грамматика |
|---|---|---|
| Location | Адрес, на который следует перенаправить страницу. Как правило, это имеет смысл только в ответе с кодом ответа 3xx. | Location: <url> |
| ETag | Идентификатор конкретной версии ресурса, веб-серверу не нужно отправлять полный ответ, если содержимое не изменилось | ETag: "<etag_value>" |
| Server | Информация, связанная с программным обеспечением, используемая исходным сервером для обработки запроса. | Server: <product> |
Заголовки сущностей (заголовки используются для сущностной части сообщений запросов и ответов)
| поле | эффект | грамматика |
|---|---|---|
| Allow | Способ, которым ресурс может поддерживать HTTP-запрос | Разрешить: |
| Last-Modified | Время последней модификации ресурса, используемое в качестве валидатора для определения того, согласуются ли полученные или сохраненные ресурсы друг с другом, не так точно, как ETag. | Пример: Последнее изменение: среда, 21 октября 2020 г., 07:28:00 по Гринвичу. |
| Expires | Срок действия ответа | Срок действия: |
Конечно заголовков HTTP больше, чем несколько, но во избежание написания слишком много людей не могут запомнить (В основном потому, что больше ничего не смотрел.), здесь представлены только некоторые часто используемые, подробности можно посмотретьДокументация по MDN
6. В чем разница между HTTP/1.0 и HTTP/1.1
- Длинное соединение:HTTP/1.1 поддерживает длинные соединения и конвейеры запросов, и несколько HTTP-запросов могут быть отправлены по одному TCP-соединению, что позволяет избежать затрат времени и задержек, связанных с многократным установлением TCP-соединений.
-
Обработка кэша:Представлено HTTP/1.1
Entity tag,If-Unmodified-Since, If-Match, If-None-MatchПодождите, пока новый заголовок запроса будет управлять кешем, подробности см. в разделе «Кэш браузера». - Оптимизация пропускной способности и использование интернет-соединения:HTTP1.1 представил поле заголовка диапазона в заголовке запроса, которое поддерживает функцию возобновления загрузки.
- Обработка заголовка хоста:В HTTP/1.0 считается, что каждый сервер имеет уникальный IP-адрес, но с развитием технологии виртуального хоста несколько хостов все чаще используют общий IP-адрес.Как сообщения запроса, так и сообщения ответа HTTP 1.1 должен поддерживать домен Host header., и если в сообщении запроса нет поля Host header, возникнет ошибка 400
7. Представьте новые возможности HTTP/2.0
- Мультиплексирование:То есть несколько запросов выполняются одновременно через одно TCP-соединение.
- Пуш сервера:Сервер может активно передавать ресурсы клиенту
- Новый бинарный формат:HTTP/2 использует двоичный формат для передачи данных.По сравнению с текстовым форматом HTTP/1.1, двоичный формат имеет лучшую разборчивость и масштабируемость.
- Сжатие заголовка:HTTP/2 сжимает заголовки сообщений, уменьшая размер передаваемых данных.
8. Расскажите об основных принципах мультиплексирования HTTP/2.0 и проблемах, которые оно решает.
Проблема, которую решает HTTP/2, — это проблема, существующая в HTTP/1.1:
- Медленный запуск TCP:После того, как TCP-соединение будет установлено, оно будет медленно стартовать, а затем быстро отправится, как при запуске автомобиля. большая потеря производительности. Кроме того, медленный старт — это стратегия, используемая TCP для уменьшения перегрузки сети, и у нас нет возможности ее изменить.
- Несколько соединений TCP конкурируют за пропускную способность:Если одновременно установлено несколько TCP-подключений, когда пропускной способности недостаточно, они будут конкурировать за пропускную способность, что повлияет на загрузку ключевых ресурсов.
- Блокировка заголовка строки HTTP/1.1:Хотя длинные ссылки HTTP/1.1 могут передавать несколько запросов через одно TCP-соединение, одновременно может обрабатываться только один запрос, а другие запросы могут быть заблокированы только до завершения текущего запроса.
Для решения вышеуказанных проблем,HTTP/2 Доменное имя использует только одно длинное TCP-соединение для передачи данных, а запрос является прямым параллельным и неблокирующим, что является мультиплексированием.
Принцип реализации:HTTP/2 вводит уровень двоичного кадрирования. Когда клиент и сервер передают, данные будут обрабатываться уровнем двоичного кадрирования и преобразовываться в кадры с идентификаторами запроса. Эти кадры объединяются в соответствии с идентификатором после завершения передачи. в соответствующие данные.
9. Расскажите о HTTP/3.0
Хотя HTTP/2 решает многие проблемы версии 1.1, у HTTP/2 все еще есть некоторые дефекты. Эти дефекты возникают не из-за самого протокола HTTP/2, а из-за лежащего в его основе протокола TCP. Мы знаем, что соединение TCP является надежным соединением. происходит потеря пакетов, все соединение должно ждать повторной передачи.HTTP/1.1 может использовать 6 TCP-соединений одновременно, и одно может блокировать другие пять, но HTTP/2 имеет только одно TCP-соединение, и проблема блокировка усиливается.
Так как протокол TCP получил широкое распространение, нам сложно напрямую модифицировать протокол TCP, исходя из этого, HTTP/3 выбирает метод компромисса — протокол UDP, HTTP/2 реализует мультиплексирование и 0-RTT на основе UDP., шифрование TLS, управление потоком, повторная передача при потере пакетов и другие функции.
Использованная литература:История http Разработка (http0.9, http1.0, http1.1, http2, http3) сортировка заметок(рекомендуется к прочтению)
10. В чем разница между HTTP и HTTPS
- HTTPS использует порт 443, а HTTP использует 80.
- HTTPS требует сертификат
- HTTP — это протокол передачи гипертекста, который представляет собой передачу открытого текста; HTTPS — это протокол с шифрованием SSL, и передача более безопасна.
- HTTPS медленнее, чем HTTP, потому что в дополнение к трем пакетам рукопожатия TCP, HTTPS также добавляет девять пакетов рукопожатия SSL.
11. Как шифруется HTTPS
Шаг за шагом анализируя несколько методов шифрования, мы понимаем метод шифрования HTTPS и почему он используется:
Симметричное шифрование
Клиент и сервер совместно используют ключ для шифрования и расшифровки сообщений, что называется симметричным шифрованием. Клиент и сервер согласовывают ключ шифрования. Клиент использует ключ для шифрования сообщения перед отправкой сообщения, а после отправки на сервер сервер расшифровывает сообщение с помощью ключа, чтобы получить сообщение.
Асимметричное шифрование
Когда используется асимметричное шифрование, и клиент, и сервер имеют открытый ключ и закрытый ключ, а содержимое, зашифрованное открытым ключом, может быть расшифровано только соответствующим закрытым ключом. Закрытый ключ хранится сам по себе, а открытый ключ отправляется другой стороне. Таким образом, перед отправкой сообщение шифруется с помощью открытого ключа другой стороны, а затем расшифровывается с помощью ее собственного закрытого ключа после его получения. Таким образом, злоумышленник может получить открытый ключ только в процессе передачи и не может расшифровать содержание передачи.
篡改公钥способ получить или подделать содержимое передачи, а производительность асимметричного шифрования намного хуже, чем у симметричного шифрования.сторонняя сертификация
Слабость вышеуказанного метода заключается в том, что клиент не знает, возвращен ли открытый ключ сервером или посредником, поэтому мы вводим стороннюю ссылку аутентификации: то есть третья сторона использует закрытый ключ для шифрования наших данных.自己的公钥, браузер имеет встроенные открытые ключи некоторых авторитетных сторонних сертификационных агентств, и браузер будет использовать第三方的公钥распутать第三方私钥加密过的我们自己的公钥, чтобы получить открытый ключ, если он может быть успешно расшифрован, это означает, что полученный自己的公钥верно
Однако сторонняя сертификация также не смогла полностью решить проблему, сторонняя сертификация доступна для всех, посредники могут подать заявку на сертификат, если брокер использует свой собственный сертификат, незаметно оригинальный сертификат, клиент все еще не может подтвердить подлинность Открытый ключ
цифровой подписи
Чтобы клиент мог проверить источник открытого ключа, мы добавляем цифровую подпись к открытому ключу.Эта цифровая подпись получается путем одностороннего хеширования различной информации и открытых ключей, таких как предприятия и веб-сайты. составляющая цифровую подпись. Если она изменится, значение хеш-функции изменится, что представляет собой уникальную идентификацию источника открытого ключа.
В частности, сервер генерирует пару ключей локально, а затем передает открытый ключ и различную информацию, такую как предприятия и веб-сайты, в ЦС (сторонний центр сертификации) для подачи заявки на цифровой сертификат. хэш-алгоритм (например, MD5), сгенерировать строку дайджестов, эта строка дайджестов является уникальным идентификатором этой кучи информации, а затем CA также будет использовать свой собственный закрытый ключ для шифрования дайджеста и отправить его нам вместе с открытый ключ нашего собственного сервера.
После того, как браузер получит цифровую подпись, он будет использоватьВстроенный браузерОткрытый ключ ЦС используется для разблокировки цифрового сертификата и его проверки, чтобы получить правильный открытый ключ. Из-за низкой производительности асимметричного шифрования после получения открытого ключа клиент будет случайным образом генерировать симметричный ключ, использовать этот открытый ключ для шифрования и отправки его на сервер, а сервер будет использовать собственный закрытый ключ для разблокировки симметричного ключ и последующее шифрование. Соединение симметрично зашифровано с помощью этого симметричного ключа.
Таким образом, асимметричное шифрование HTTPS + + сторонняя сертификация цифровой подписи на этапе проверки для получения правильного открытого ключа для получения правильного открытого ключа для связи с симметричным шифрованием
Использованная литература:Посмотрите на графику HTTPS
Фронтальная безопасность
Что такое CSRF-атака
CSRF расшифровывается как подделка межсайтовых запросов (подделка межсайтовых запросов).
Предположим, хакер размещает на своем сайте внешние ссылки с других веб-сайтов, например"www.weibo.com/api, по умолчанию браузер выводитweibo.comЕсли пользователь авторизовался на сайте и сайт не защищен от CSRF-атак, сервер будет думать, что пользователь сам вызывает этот интерфейс и выполняет связанные с ним операции, что приводит к захвату аккаунта.
Как защититься от CSRF-атак
- проверять
Token: когда браузер запрашивает сервер, сервер возвращает токен, и каждый запрос должен приносить и токен, и файл cookie, чтобы считаться законным запросом. - проверять
Referer: проверьте исходный сайт, проверив Referer заголовка запроса, но заголовок запроса легко подделать. - настраивать
SameSite: SameSite, который устанавливает файлы cookie, чтобы файлы cookie не отправлялись с междоменными запросами, но совместимость браузеров отличается.
Что такое XSS-атака
XSS означает межсайтовый скриптинг, который относится к внедрению вредоносного кода инструкции в веб-страницу путем использования лазеек, оставленных при разработке веб-страницы, так что пользователь загружает и выполняет программу веб-страницы, злонамеренно созданную злоумышленником. Например, код JS внедряется в область комментариев, и код выполняется, когда пользователь входит на страницу комментариев, в результате чего на странице размещаются рекламные объявления и украдена информация об учетной записи.
Какие существуют типы XSS-атак
- тип хранения: То есть атака хранится на сервере.Обычно скрипт атаки вставляется в область комментария.Если скрипт хранится на сервере, то все пользователи, увидевшие соответствующий комментарий, будут атакованы.
- Светоотражающий: Злоумышленник смешивает скрипт с URL-адресом, а сервер получает URL-адрес, принимает вредоносный код в качестве параметра и вставляет его обратно в HTML.Браузер выполняет вредоносный код после анализа HTML.
- тип документа: Напишите сценарий атаки в URL-адресе, чтобы побудить пользователя щелкнуть URL-адрес. Если URL-адрес проанализирован, сценарий атаки будет выполнен. Основное отличие от первых двух заключается в том, что атаки типа DOM не проходят через сервер.
Как защититься от XSS-атак
-
входная проверка: для входного содержимого
<script><iframe>Побег или фильтр теги - установить httpOnly: многие цели XSS-атак заключаются в краже пользовательских файлов cookie для подделки аутентификации, установка этого атрибута может помешать JS получать файлы cookie.
- Включить CSP, то есть включается белый список, что может предотвратить загрузку и запуск ресурсов вне белого списка
Алгоритм сортировки
1. Пузырьковая сортировка от руки
Пузырьковая сортировка должна быть первой, с которой сталкиваются многие люди, она относительно проста и не будет объясняться.
function bubbleSort(arr){
for(let i = 0; i < arr.length; i++) {
for(let j = 0; j < arr.length - i - 1; j++) {
if(arr[j] > arr[j+1]) {
let temp = arr[j]
arr[j] = arr[j+1]
arr[j+1] = temp
}
}
}
return arr
}
2. Как оптимизировать пузырьковую сортировку
Пузырьковая сортировка всегда будет выполняться (N-1)+(N-2)+(N-3)+..+2+1 раз, но если сортировка была завершена при достижении одного из прогонов или ввод Упорядоченный массив, то следующие сравнения избыточны.Чтобы избежать этой ситуации, мы добавляем флаг, чтобы определить, была ли сортировка завершена в середине (то есть, чтобы определить, есть ли обмен элементами)
function bubbleSort(arr){
for(let i = 0; i < arr.length; i++) {
let flag = true
for(let j = 0; j < arr.length - i - 1; j++) {
if(arr[j] > arr[j+1]) {
flag = false
let temp = arr[j]
arr[j] = arr[j+1]
arr[j+1] = temp
}
}
// 这个flag的含义是:如果`某次循环`中没有交换过元素,那么意味着排序已经完成
if(flag)break;
}
return arr
}
3. Рукописная быстрая сортировка
Основные шаги быстрой сортировки:
- Выберите опорный элемент
- Элементы меньшего размера, чем базовый элемент, размещаются слева, элементы большего размера размещаются справа.
- Повторяйте шаги 1 и 2 в левом и правом подмассивах, пока в массиве не останется только один элемент.
- Объединить массивы вверх по уровню
function quickSort(arr) {
if(arr.length <= 1) return arr //递归终止条件
const pivot = arr.length / 2 | 0 //基准点
const pivotValue = arr.splice(pivot, 1)[0]
const leftArr = []
const rightArr = []
arr.forEach(val => {
val > pivotValue ? rightArr.push(val) : leftArr.push(val)
})
return [ ...quickSort(leftArr), pivotValue, ...quickSort(rightArr)]
}
4. Как оптимизировать быструю сортировку
Сортировать по месту
Вышеупомянутая быстрая сортировка предназначена только для того, чтобы читатели почувствовали это. Мы не можем написать быструю сортировку таким образом. Если мы каждый раз будем открывать два массива, это займет много места в памяти. Когда объем данных большой, это может вызвать переполнение памяти. следует избегать открытия нового пространства памяти. , то есть сортировка выполняется на месте
Вместо того, чтобы открывать новый массив, мы можем использовать замену элементов и менять местами элементы непосредственно в исходном массиве каждый раз, когда мы разделяем его.Переместите элементы меньше базового числа в начало массива,к[5,1,4,2,3]Например:
Код:
function quickSort(arr, left, right) { //这个left和right代表分区后“新数组”的区间下标,因为这里没有新开数组,所以需要left/right来确认新数组的位置
if (left < right) {
let pos = left - 1 //pos即“被置换的位置”,第一趟为-1
for(let i = left; i <= right; i++) { //循环遍历数组,置换元素
let pivot = arr[right] //选取数组最后一位作为基准数,
if(arr[i] <= pivot) { //若小于等于基准数,pos++,并置换元素, 这里使用小于等于而不是小于, 其实是为了避免因为重复数据而进入死循环
pos++
let temp = arr[pos]
arr[pos] = arr[i]
arr[i] = temp
}
}
//一趟排序完成后,pos位置即基准数的位置,以pos的位置分割数组
quickSort(arr, left, pos - 1)
quickSort(arr, pos + 1, right)
}
return arr //数组只包含1或0个元素时(即left>=right),递归终止
}
//使用
var arr = [5,1,4,2,3]
var start = 0;
var end = arr.length - 1;
quickSort(arr, start, end)
Этот процесс обмена все еще требует некоторого времени, чтобы понять и переварить.Для подробного анализа вы можете прочитать это:js алгоритм — Quicksort (Быстрая сортировка)
Быстрая гребля втроем
Вышеупомянутая быстрая сортировка не может быть оптимизирована, следует сказать, что это правильный способ написания быстрой сортировки На самом деле есть две проблемы, которые мы можем оптимизировать:
- Случай отсортированных массивов: Если входной массив упорядочен, а контрольная точка также берется последовательно, это может привести к тому, что подмассив на одной стороне контрольной точки будет все время пустым, что приведет к уменьшению временной сложности до O (n2)
-
В случае большого количества дублирующихся данных: Например, входные данные
[1,2,2,2,2,3], независимо от того, является ли контрольная точка 1, 2 или 3, размер массивов по обе стороны от контрольной точки будет несбалансированным, что повлияет на эффективность быстрой сортировки.
Для первой проблемы мы можем решить ее, рандомизируя при взятии реперных точек, а для второй проблемы мы можем использовать三路快排способ оптимизации, скажем, для вышеуказанного[1,2,2,2,2,3], за точку отсчета берем 2, а при разбиении делим элементы массива на小于2|等于2|大于2Три области, часть, равная контрольной точке, больше не попадет в следующую сортировку, что значительно повышает эффективность быстрой сортировки.
5. Рукописная сортировка слиянием
Идеи сортировки слиянием и быстрой сортировки аналогичны.Оба являются рекурсивными разделяй и властвуй.Разница в том, что быстрая сортировка сортируется при разбиении, а сортировка слиянием только после завершения разбиения.
function mergeSort(arr) {
if(arr.length <= 1) return arr //数组元素被划分到剩1个时,递归终止
const midIndex = arr.length/2 | 0
const leftArr = arr.slice(0, midIndex)
const rightArr = arr.slice(midIndex, arr.length)
return merge(mergeSort(leftArr), mergeSort(rightArr)) //先划分,后合并
}
//合并
function merge(leftArr, rightArr) {
const result = []
while(leftArr.length && rightArr.length) {
leftArr[0] <= rightArr[0] ? result.push(leftArr.shift()) : result.push(rightArr.shift())
}
while(leftArr.length) result.push(leftArr.shift())
while(rightArr.length) result.push(rightArr.shift())
return result
}
6. Ручная сортировка кучи
Куча — это особое дерево, пока оно удовлетворяет
这棵树是完全二叉树а также堆中每一个节点的值都大于或小于其左右孩子节点эти два условия, то это куча, согласно堆中每一个节点的值都大于或小于其左右孩子节点, который далее делится на большую корневую кучу и малую корневую кучу
Процесс сортировки кучи:
- Инициализируйте большую (маленькую) корневую кучу, в это время корневой узел является максимальным (маленьким) значением, и замените корневой узел последним узлом (последним элементом массива).
- За исключением последнего узла, измените размер большой (маленькой) корневой кучи так, чтобы корневой узел имел наибольшее (меньшее) значение.
- Повторяйте шаг 2, пока в куче не останется один элемент и сортировка не будет завершена.
к[1,5,4,2,3]В качестве примера для создания большой корневой кучи:
// 堆排序
const heapSort = array => {
// 我们用数组来储存这个大根堆,数组就是堆本身
// 初始化大顶堆,从第一个非叶子结点开始
for (let i = Math.floor(array.length / 2 - 1); i >= 0; i--) {
heapify(array, i, array.length);
}
// 排序,每一次 for 循环找出一个当前最大值,数组长度减一
for (let i = Math.floor(array.length - 1); i > 0; i--) {
// 根节点与最后一个节点交换
swap(array, 0, i);
// 从根节点开始调整,并且最后一个结点已经为当前最大值,不需要再参与比较,所以第三个参数为 i,即比较到最后一个结点前一个即可
heapify(array, 0, i);
}
return array;
};
// 交换两个节点
const swap = (array, i, j) => {
let temp = array[i];
array[i] = array[j];
array[j] = temp;
};
// 将 i 结点以下的堆整理为大顶堆,注意这一步实现的基础实际上是:
// 假设结点 i 以下的子堆已经是一个大顶堆,heapify 函数实现的
// 功能是实际上是:找到 结点 i 在包括结点 i 的堆中的正确位置。
// 后面将写一个 for 循环,从第一个非叶子结点开始,对每一个非叶子结点
// 都执行 heapify 操作,所以就满足了结点 i 以下的子堆已经是一大顶堆
const heapify = (array, i, length) => {
let temp = array[i]; // 当前父节点
// j < length 的目的是对结点 i 以下的结点全部做顺序调整
for (let j = 2 * i + 1; j < length; j = 2 * j + 1) {
temp = array[i]; // 将 array[i] 取出,整个过程相当于找到 array[i] 应处于的位置
if (j + 1 < length && array[j] < array[j + 1]) {
j++; // 找到两个孩子中较大的一个,再与父节点比较
}
if (temp < array[j]) {
swap(array, i, j); // 如果父节点小于子节点:交换;否则跳出
i = j; // 交换后,temp 的下标变为 j
} else {
break;
}
}
}
Использованная литература:JS реализует сортировку кучи
7. В чем разница между слиянием, быстрой сортировкой и сортировкой в куче
| Сортировать | Временная сложность (лучший случай) | Временная сложность (худший случай) | космическая сложность | стабильность |
|---|---|---|---|---|
| быстрая сортировка | O(nlogn) | O(n^2) | O(logn)~O(n) | нестабильный |
| Сортировка слиянием | O(nlogn) | O(nlogn) | O(n) | стабилизировать |
| сортировка кучей | O(nlogn) | O(nlogn) | O(1) | нестабильный |
На самом деле, из таблицы видно, что с точки зрения временной сложности быстрая сортировка не имеет большого преимущества, однако, почему быстрая сортировка стала наиболее часто используемым методом сортировки, это потому, что временная сложность может объяснить только随着数据量的增加,算法时间代价增长的趋势, не представляет непосредственно фактическое время выполнения. Фактическое время выполнения также включает в себя разницу многих постоянных параметров. Кроме того, при столкновении с различными типами данных (такими как упорядоченные данные, большое количество повторяющихся данных) производительность тоже разные.Эффективность времени самая высокая
В практических приложениях используется не только один метод сортировки, такой как V8.Array.sort()взял этоПри n10 используйте трехэтапную быструю сортировку.стратегия сортировки
Шаблоны проектирования
Существует множество шаблонов проектирования, вот несколько наиболее часто используемых:
| Шаблоны проектирования | описывать | пример |
|---|---|---|
| одноэлементный шаблон | Можно построить только один экземпляр класса | Магазин Redux/Vuex |
| заводской узор | Инкапсуляция логики создания объекта | jQuery $(селектор) |
| Шаблон наблюдателя | Когда объект изменяется, его зависимые объекты автоматически уведомляются | Подписка Redux, двусторонняя привязка Vue |
| Шаблон декоратора | Обертка класса для динамического расширения функциональности класса | Компоненты высшего порядка React, декораторы ES7 |
| режим адаптера | Совместимость со старыми и новыми интерфейсами, упаковка классов | Обертывание старых API |
| прокси-режим | контролировать доступ к объектам | Прокси события, прокси ES6 |
1. Внедрить принцип единой ответственности и открытый закрытый принцип
-
Принцип единой ответственности: Класс отвечает только за соответствующие обязанности в одной функциональной области или может быть определен как: Что касается класса, то должна быть только одна причина для его изменения.
-
открытый закрытый принцип: основная идея заключается в том, что программные объекты (классы, модули, функции и т. д.) расширяемы, но не модифицируемы. То есть он открыт для расширения и закрыт для модификации.
2. Одноэлементный шаблон
Шаблон singleton означает, что класс может создавать только уникальный экземпляр.Смысл шаблона singleton в том, чтообщий, уникальный,Redux/Vuexхранить в ,JQ$ или корзина покупок и окно входа в бизнес-сценарий — все это приложения шаблона singleton.
class SingletonLogin {
constructor(name,password){
this.name = name
this.password = password
}
static getInstance(name,password){
//判断对象是否已经被创建,若创建则返回旧对象
if(!this.instance)this.instance = new SingletonLogin(name,password)
return this.instance
}
}
let obj1 = SingletonLogin.getInstance('CXK','123')
let obj2 = SingletonLogin.getInstance('CXK','321')
console.log(obj1===obj2) // true
console.log(obj1) // {name:CXK,password:123}
console.log(obj2) // 输出的依然是{name:CXK,password:123}
3. Заводской узор
Фабричный шаблон — это инкапсуляция логики создания объектов, или его можно просто понимать какnewЭтот тип инкапсуляции похож на фабрику по созданию объектов, отсюда и название фабрики. Фабричный шаблон распространен в больших проектах, таких как объект JQ $. Причина, по которой у нас нет нового селектора при создании объекта селектора, заключается в том, что $() уже является фабричным методом. Другие примеры включаютReact.createElement(),Vue.component()Оба являются реализациями фабричного шаблона. Существует несколько фабричных шаблонов:简单工厂模式,工厂方法模式,抽象工厂模式, вот только простой фабричный паттерн в качестве примера:
class User {
constructor(name, auth) {
this.name = name
this.auth = auth
}
}
class UserFactory {
static createUser(name, auth) {
//工厂内部封装了创建对象的逻辑:
//权限为admin时,auth=1, 权限为user时, auth为2
//使用者在外部创建对象时,不需要知道各个权限对应哪个字段, 不需要知道赋权的逻辑,只需要知道创建了一个管理员和用户
if(auth === 'admin') new User(name, 1)
if(auth === 'user') new User(name, 2)
}
}
const admin = UserFactory.createUser('cxk', 'admin');
const user = UserFactory.createUser('cxk', 'user');
4. Шаблон наблюдателя
Шаблон наблюдателя является наиболее часто используемым шаблоном проектирования во внешнем интерфейсе.Концепция шаблона наблюдателя очень проста: наблюдатель слушает изменения наблюдаемого объекта, и когда наблюдаемый объект изменяется, он уведомляет всех наблюдателей. Паттерн наблюдатель широко используется для реализации мониторинга событий, подробное применение паттерна наблюдателя вы можете посмотреть в другом моем пояснении.Статья о реализации Redux
//观察者
class Observer {
constructor (fn) {
this.update = fn
}
}
//被观察者
class Subject {
constructor() {
this.observers = [] //观察者队列
}
addObserver(observer) {
this.observers.push(observer)//往观察者队列添加观察者
}
notify() { //通知所有观察者,实际上是把观察者的update()都执行了一遍
this.observers.forEach(observer => {
observer.update() //依次取出观察者,并执行观察者的update方法
})
}
}
var subject = new Subject() //被观察者
const update = () => {console.log('被观察者发出通知')} //收到广播时要执行的方法
var ob1 = new Observer(update) //观察者1
var ob2 = new Observer(update) //观察者2
subject.addObserver(ob1) //观察者1订阅subject的通知
subject.addObserver(ob2) //观察者2订阅subject的通知
subject.notify() //发出广播,执行所有观察者的update方法
В некоторых статьях режим наблюдателя также упоминается как режим публикации-подписки.На самом деле это два разных режима.Режим публикации-подписки имеет на один диспетчерский центр больше, чем режим наблюдателя.
5. Шаблон декоратора
Шаблон декоратора можно рассматривать как оболочку класса для динамического расширения функций класса.装饰器Синтаксис и в React高阶组件(HoC) — все реализации этого шаблона. Функция connect() в react-redux также использует шаблон декоратора, вот пример декоратора ES7:
function info(target) {
target.prototype.name = '张三'
target.prototype.age = 10
}
@info
class Man {}
let man = new Man()
man.name // 张三
6. Режим адаптера
Шаблон адаптера преобразует один интерфейс в другой интерфейс, который нужен клиенту, чтобы те классы, чьи интерфейсы несовместимы, могли работать вместе. Мы часто используем переходники в нашей жизни.Например, вилка и розетка выездного путешествия не совпадают.В это время нам нужно использовать вилку-переходник, то есть переходник, который поможет нам решить проблему.
class Adaptee {
test() {
return '旧接口'
}
}
class Target {
constructor() {
this.adaptee = new Adaptee()
}
test() {
let info = this.adaptee.test()
return `适配${info}`
}
}
let target = new Target()
console.log(target.test())
7. Режим прокси
Режим прокси, чтобы найти замену объекту, чтобы получить доступ к исходному объекту. То есть между посетителем и целевым объектом добавляется слой прокси, а авторизация и управление осуществляются через прокси. Наиболее распространенным примером является бизнес брокеров, выступающих в роли знаменитостей. Предположим, вы, как инвестор, хотите связаться со знаменитостями для рекламы, тогда вам нужно сначала пройти через агента агентства.Агент проверит вашу квалификацию и уведомит вас о знаменитости расписание.Отфильтруйте ненужную информацию по самим звездам. агент событий,JQuery的$.proxy, ЭС6proxyВсе являются реализацией этого режима.Ниже приведен пример прокси ES6:
const idol = {
name: '蔡x抻',
phone: 10086,
price: 1000000 //报价
}
const agent = new Proxy(idol, {
get: function(target) {
//拦截明星电话的请求,只提供经纪人电话
return '经纪人电话:10010'
},
set: function(target, key, value) {
if(key === 'price' ) {
//经纪人过滤资质
if(value < target.price) throw new Error('报价过低')
target.price = value
}
}
})
agent.phone //经纪人电话:10010
agent.price = 100 //Uncaught Error: 报价过低
связанные с HTML
1. Расскажите о новых функциях HTML5 в тегах, атрибутах, хранилище и API.
- Теги: добавить смысловые теги (
aside / figure / section / header / footer / navд.), добавить мультимедийные тегиvideoа такжеaudio, делая стиль и структуру более разделенными - Атрибут: Улучшенная форма, в основном усиленная
inputАтрибут типа;metaУвеличьте charset, чтобы установить набор символов;scriptДобавьте async для асинхронной загрузки скриптов - Хранение: увеличение
localStorage,sessionStorageа такжеindexedDB, представилapplication cacheКэшировать веб и приложения - API: увеличить
拖放API,地理定位,SVG绘图,canvas绘图,Web Worker,WebSocket
2. Какова роль типа документа?
Объявите тип документа, чтобы сообщить браузеру, какой стандарт документа использовать для анализа этого документа:
- Странный режим: браузер использует свой собственный режим для анализа документа и по умолчанию использует странный режим без добавления типа документа.
- Стандартный режим: браузер анализирует документ в соответствии со стандартами W3C.
3. Несколько типов внешнего хранилища и различия между ними
- cookies: Основной метод локального хранения до HTML5, размер всего 4k, заголовок HTTP-запроса автоматически принесет куки, и совместимость хорошая
- localStorage: новые функции HTML5, постоянное хранилище, не будет очищено, даже если страница закрыта, хранится в парах ключ-значение с размером 5M.
- sessionStorage: новые функции HTML5, операция и размер такие же, как у localStorage, отличие от localStorage в том, что sessionStorage очищается при закрытии вкладки (страницы), а sessionStorage между разными вкладками не взаимодействует
- IndexedDB: база данных NoSQL, аналогичная MongoDB, использует пары ключ-значение для хранения, работает с базой данных асинхронно, поддерживает транзакции, а объем хранилища может превышать 250 МБ, но IndexedDB ограничен политикой одного и того же источника.
- Web SQL: это реляционная база данных, моделируемая в браузере. Разработчики могут работать с Web SQL с помощью операторов SQL. Это независимый набор спецификаций, отличных от HTML5, с плохой совместимостью.
4. В чем разница между href и src
href(hyperReference)То есть гипертекстовая ссылка: когда браузер встречает href, он будет загружать ресурсы параллельно, не блокируя парсинг страницы.Например, мы используем<link>При внедрении CSS браузеры будут загружать CSS параллельно, не блокируя синтаксический анализ страницы, поэтому мы рекомендуем использовать CSS при внедрении CSS.<link>вместо@import
<link href="style.css" rel="stylesheet" />
src(resource)То есть ресурса, когда браузер встречает src, он приостанавливает парсинг страницы до тех пор, пока ресурс не будет скачан или выполнен, именно поэтому тег script размещен внизу
<script src="script.js"></script>
5. Каковы атрибуты мета и каковы функции?
метатеги используются для описания веб-страниц元信息, такие как автор веб-сайта, описание, ключевые слова, метаданныеname=xxxа такжеcontent=xxxФорма состоит в том, чтобы определить информацию, и общие настройки следующие:
- charset: определяет набор символов HTML-документа.
<meta charset="UTF-8" >
- http-equiv: может использоваться для имитации заголовков HTTP-запросов, может устанавливать время истечения срока действия, кеширование, обновление
<meta http-equiv="expires" content="Wed, 20 Jun 2019 22:33:00 GMT">
- viewport: окно просмотра, используемое для управления шириной и высотой страницы, а также коэффициентом масштабирования.
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1"
>
6. Какие параметры вьюпорта и каковы их функции?
- ширина/высота, ширина и высота, ширина по умолчанию 980px
- начальный масштаб, начальный коэффициент масштабирования, 1~10
- максимальный/минимальный масштаб, максимальный/минимальный масштаб, который разрешено масштабировать пользователю
- масштабируемый пользователем, является ли пользователь масштабируемым (да/нет)
7. Роль и параметры атрибута http-equive
- истекает, укажите срок действия
- прога, установка no-cache может отключить кеширование
- обновление, регулярное обновление
- set-cookie, вы можете установить файлы cookie
- Совместимость с X-UA, используйте браузерную версию
- apple-mobile-web-app-status-bar-style, для полноэкранного режима WebApp, скрыть строку состояния/установить цвет строки состояния
связанные с CSS
Как очистить поплавки
Почему вы хотите очистить поплавок: Очистка поплавка — это решение проблемы, заключающейся в том, что высота родительского элемента схлопывается из-за плавающего элемента дочернего элемента.
<div class="parent">
<div class="child"></div>
<!-- 添加一个空元素,利用css提供的clear:both清除浮动 -->
<div style="clear: both"></div>
</div>
2. Используйте псевдоэлементы
/* 对父元素添加伪元素 */
.parent::after{
content: "";
display: block;
height: 0;
clear:both;
}
3. Активировать родительский элемент BFC
/* 触发父元素BFC */
.parent {
overflow: hidden;
/* float: left; */
/* position: absolute; */
/* display: inline-block */
/* 以上属性均可触发BFC */
}
Знакомство с гибкой версткой
На самом деле, изначально я написал раздел, касающийся горизонтального/вертикального центрирования, но мне показалось, что содержание было слишком простым и занимало слишком много времени, поэтому я удалил его. В качестве итоговой статьи этот подраздел не должен начинаться с «Что такое flex ?» В начале считается, что понятия главной оси и боковой оси известны всем, кто использовал flex layout, поэтому поговорим о нескольких свойствах flex непосредственно:
Свойства контейнера (свойства, используемые в контейнерах гибкого макета)
- justify-content
Определяет выравнивание дочерних элементов по главной оси (горизонтальной оси)
.container {
justify-content: center | flex-start | flex-end | space-between | space-around;
/* 主轴对齐方式:居中 | 左对齐(默认值) | 右对齐 | 两端对齐(子元素间边距相等) | 周围对齐(每个子元素两侧margin相等) */
}
- align-items
Определяет, как определенные элементы выравниваются по поперечной оси (вертикальной оси).
.container {
align-items: center | flex-start | flex-end | baseline | stretch;
/* 侧轴对齐方式:居中 | 上对齐 | 下对齐 | 项目的第一行文字的基线对齐 | 如果子元素未设置高度,将占满整个容器的高度(默认值) */
}
- flex-direction
Направление главной оси (горизонтальной оси)
.container {
flex-direction: row | row-reverse | column | column-reverse;
/* 主轴方向:水平由左至右排列(默认值) | 水平由右向左 | 垂直由上至下 | 垂直由下至上 */
}
- flex-wrap
новая линия
.container {
flex-wrap: nowrap | wrap | wrap-reverse;
/* 换行方式:不换行(默认值) | 换行 | 反向换行 */
}
- flex-flow
Свойство flex-flow является сокращением от свойств flex-direction и flex-wrap.
.container {
flex-flow: <flex-direction> || <flex-wrap>;
/* 默认值:row nowrap */
}
- align-content
Определение выравнивания нескольких линий сетки
.container {
align-content: center | flex-start | flex-end | space-between | space-around | stretch;
/* 默认值:与交叉轴的中点对齐 | 与交叉轴的起点对齐 | 与交叉轴的终点对齐 | 与交叉轴两端对齐 | 每根轴线两侧的间隔都相等 | (默认值):轴线占满整个交叉轴 */
}
свойства элемента (свойства, используемые для дочерних элементов внутри контейнера)
- flex-grow
Определить коэффициент увеличения проекта, по умолчанию 0, даже если осталось место, он не будет увеличен. Если все дочерние элементы flex-grow равны 1, то оставшееся пространство будет разделено поровну, если дочерний элемент flex-grow равен 2, то этот дочерний элемент будет занимать в 2 раза больше оставшегося места
.item {
flex-grow: <number>; /* default 0 */
}
- flex-shrink
Определяет коэффициент уменьшения элемента, по умолчанию 1, то есть если места недостаточно, дочерние элементы будут уменьшены. если все дочерние элементыflex-shrinkвсе 1, дочерний элементflex-shrinkравно 0, то дочерний элемент не будет уменьшаться
.item {
flex-shrink: <number>; /* default 1 */
}
- flex-basis
Определяет пространство на главной оси, которое занимает элемент, перед выделением лишнего пространства., авто по умолчанию, то есть исходный размер дочернего элемента, если для него установлено фиксированное значение, то дочерний элемент будет занимать фиксированное место
.item {
flex-basis: <length> | auto; /* default auto */
}
- flex
гибкое свойствоflex-grow,flex-shrinkа такжеflex-basisСокращение для , значение по умолчанию 0 1 auto, то есть если есть оставшееся место, то оно не будет увеличено, если оставшегося места не хватит, то уменьшится, а дочерний элемент займет свой размер
.item {
flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}
flex имеет два ярлыка:autoа такжеnone, Представляя1 1 auto(если останется место, то оно будет распределено равномерно, если места недостаточно, оно будет пропорционально уменьшено, а место, занимаемое дочерним элементом, будет равно его собственному размеру) и0 0 auto(Если есть оставшееся место, оно не будет выделено, а если места недостаточно, оно не будет уменьшено. Пространство, занимаемое дочерним элементом, равно его собственному размеру)
- order
Определите порядок проекта. Чем меньше значение, тем больше аранжировка - это значение по умолчанию 0
.item {
order: <integer>;
}
- align-self
Определяет, как устроены отдельные дочерние элементыНапример, если align-items устанавливает center для выравнивания всех подэлементов по центру, то вы можете установить метод сортировки подэлементов по отдельности, установив align-self для подэлемента.
.item {
align-self: auto | flex-start | flex-end | center | baseline | stretch;
}
Использованная литература:Гибкий макет Руан Ифэн
общая компоновка
Редактирование, пожалуйста, подождите -_-||
Что такое БФК
Полное название BFC — Block Formatting Context.块级格式上下文, проще говоря, BFC — это изолированный независимый контейнер на странице, свободный от внешнего вмешательства или вмешательства из внешнего мира
Как активировать BFC
-
floatни для кого -
overflowзначение не видно -
positionявляется абсолютным или фиксированным -
displayЗначение представляет собой встроенный блок, ячейку таблицы, заголовок таблицы или сетку.
Каковы правила рендеринга BFC
- BFC — это изолированный независимый контейнер на странице, свободный от постороннего вмешательства или вмешательства из внешнего мира.
- При расчете высоты BFC в расчете также участвуют плавающие дочерние элементы (то есть схлопывание высоты не произойдет, когда внутри есть плавающие элементы)
- Площадь BFC не будет перекрывать площадь элемента поплавка
- Элементы внутри БТЭ расположены вертикально
- Поля двух соседних элементов в BFC будут перекрываться
Сценарии применения BFC
- очистить поплавок: Плавающий элемент внутри BFC будет участвовать в вычислении высоты, поэтому его можно использовать для очистки плавающей точки и предотвращения разрушения высоты.
- Предотвратить покрытие элемента плавающим элементом: область BFC не будет перекрывать область плавающего элемента
- Предотвращение перекрытия полей: поля двух соседних блоков, принадлежащих одному и тому же BFC, будут свернуты, но разные BFC не будут свернуты.
Суммировать
Для объяснения базовых знаний о интерфейсе вот небольшой абзац. Мир фронтенда сложен и выходит далеко за рамки того, что автор может описать всего несколькими штрихами.Автор как ребенок собирающий ракушки на пляже.Иногда мне везет и я собираю одну или две,так что я в восторге от этого и не могу дождаться, чтобы поделиться им с друзьями.
Наконец, я хотел бы стыдливо выразить (себя) (хвастовство) (•‾̑⌣‾̑•)✧˖°:
Неосознанно я нахожусь в Наггетс больше полугода.За последние полгода я написал почти 60000 слов,но по факту статей всего 5.Это потому что не хочу писать гидрологию, и я не хочу излагать основы в нескольких тысячах слов, десятки статей, которые нужно смешивать и обновлять. Напишите статью, прежде всего, чтобы иметь возможность убедить себя. Возьмите на себя ответственность за то, что вы пишете, даже если это картинка, знаки препинания. Например, на первой картинке я ее корректировал не менее десяти раз.В первый раз я напрямую перехватил результат конвертации babel.После скачивания обнаружил, что ширина двух картинок разная, и скачал снова заполнить ширину. Я обнаружил, что в моем коде не хватает пробела, и загрузил его снова. Чтобы реализовать эффект бок о бок двух изображений, я написал HTML, чтобы настроить стиль двух изображений. и поля каждой картинки одинаковые.При съемке скриншотов я записываю размер и поля каждого скриншота, и каждый скриншот корректирует поля в соответствии с предыдущими данными.
На самом деле, я не призываю тратить время на эти детали, но я просто чувствую, что если статья написана плохо, ее нельзя опубликовать.Великие истины мира часто бывают такими простыми.
Прошлые статьи:
1. Асинхронное программирование две-три вещи | Анализ принципа реализации Promise/async/Generator | 9k слов
2. 10 строк кода, чтобы увидеть реализацию redux — проектирование и реализация промежуточного программного обеспечения redux, react-redux и redux | 8k слов
3.Красно-черное дерево, красно-черные фрукты, красно-черное дерево, ты и я - Brokenhead Getting Started | 6K word
4. Принципы службы глубокого рендеринга React | 1W word