Список вопросов для интервью на этой неделе:
- Какова цель функции дроссельной заслонки? Каковы сценарии приложений, пожалуйста, реализуйте функцию регулирования
- Расскажите мне о своем понимании стека контекста выполнения JS и цепочки областей видимости?
- Что такое БФК? Каковы правила компоновки для BFC? Как создать БФУ?
- В чем разница между let, const и var?
- В чем разница между глубоким копированием и поверхностным копированием? Как реализовать глубокую копию?
Более качественные изделия можно штамповать: GitHub.com/Иветт Л.А. Ю/Б…
6. Какова цель функции дроссельной заслонки? Каковы сценарии приложений, пожалуйста, реализуйте функцию дросселирования. (2019-05-27)
Роль дроссельной заслонки
Функция дросселирования заключается в указании единицы времени, в течение которой выполнение функции может быть запущено не более одного раза.Если функция запускается несколько раз в течение этой единицы времени, она может сработать только один раз.
Например: мать Сяо Мина и Сяо Мин договорились, что если Сяо Мин получит высокие оценки в еженедельном тесте, он может отвести его на детскую площадку в этом месяце, но он может ходить на детскую площадку не чаще одного раза в месяц.
На самом деле это пример троттлинга: за месяц поход на детскую площадку может сработать максимум один раз. Даже за это время Сяо Мин получил много полных оценок.
Сценарии регулирования приложений
1. Событие нажатия кнопки
2. Событие перетаскивания
3.onScoll
4. Рассчитать расстояние, на которое перемещается мышь (mousemove)
Реализация функции дроссельной заслонки
использовать отметку времени
function throttle (func, delay) {
var lastTime = 0;
function throttled() {
var context = this;
var args = arguments;
var nowTime = Date.now();
if(nowTime > lastTime + delay) {
func.apply(context, args);
lastTime = nowTime;
}
}
//节流函数最终返回的是一个函数
return throttled;
}
Реализовано с таймером
function throttle(func, delay) {
var timeout = null;
function throttled() {
var context = this;
var args = arguments;
if(!timeout) {
timeout = setTimeout(()=>{
func.apply(context, args);
clearTimeout(timeout);
timeout=null
}, delay);
}
}
return throttled;
}
Ни метка времени, ни метод таймера не учитывают последнее выполнение, например, если есть событие нажатия кнопки, установленное время интервала составляет 1 с, а если щелчок производится через 0,5 с, 1,8 с и 2,2 с, то только 0,5 с. S и 1.8S Два щелчка могут вызвать выполнение функции, а последние 2.2S будут проигнорированы.
Комбинированная реализация, позволяющая установить, запускать ли выполнение функции в первый или последний раз
function throttle (func, wait, options) {
var timeout, context, args, result;
var previous = 0;
if (!options) options = {};
var later = function () {
previous = options.leading === false ? 0 : Date.now() || new Date().getTime();
timeout = null;
result = func.apply(context, args);
if (!timeout) context = args = null;
};
var throttled = function () {
var now = Date.now() || new Date().getTime();
if (!previous && options.leading === false) previous = now;
var remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining <= 0 || remaining > wait) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
previous = now;
result = func.apply(context, args);
if (!timeout) context = args = null;
} else if (!timeout && options.trailing !== false) {
// 判断是否设置了定时器和 trailing
timeout = setTimeout(later, remaining);
}
return result;
};
throttled.cancel = function () {
clearTimeout(timeout);
previous = 0;
timeout = context = args = null;
};
return throttled;
}
Его легко использовать:
btn.onclick = throttle(handle, 1000, {leading:true, trailing: true});
7. Расскажите мне о своем понимании стека контекста выполнения JS и цепочки областей видимости? (2019-05-28)
Прежде чем мы начнем объяснять стек и область контекста JS, давайте сначала объясним концепцию контекста и области действия JS.
Контекст выполнения JS
Контекст выполнения — это абстрактное понятие среды, в которой анализируется и выполняется текущий код JavaScript.Любой код, работающий в JavaScript, выполняется в контексте выполнения.
Типы контекста выполнения делятся на:
- глобальный контекст выполнения
- контекст выполнения функции
- контекст выполнения функции eval (не рекомендуется)
В процессе создания контекста выполнения необходимо сделать следующее:
- Создайте объект переменной: сначала инициализируйте аргументы аргумента функции, поднимите объявление функции и объявление переменной.
- Создайте цепочку областей действия (цепочка областей действия): на этапе создания контекста времени выполнения цепочка областей действия создается после объекта переменной.
- Определите значение this, т.е. ResolveThisBinding
объем
объемОтвечает за сбор и обслуживание набора запросов, состоящего из всех объявленных идентификаторов (переменных), и за соблюдение очень строгого набора правил, определяющих доступ к этим идентификаторам при выполнении кода в данный момент. - Выдержка из «JavaScript, которого вы не знаете» (том 1)
Существуют две рабочие модели области видимости: лексическая область видимости и динамическая область видимости, которую использует JS.лексический объемРабочая модель, лексическая область видимости означает, что область видимости определяется расположением объявлений переменных и функций при написании кода. (with
а такжеeval
Можно изменить лексическую область видимости, но это не рекомендуется, и для этого не делается никаких специальных указаний)
Область применения делится на:
- глобальная область
- объем функции
- область действия блока
Стек контекста выполнения JS (далее стек исполнения)
Стек выполнения, также называемый стеком вызовов, имеетLIFOСтруктура (Last In, First Out), используемая для хранения всех контекстов выполнения, созданных во время выполнения кода.
Правила следующие:
- Когда код JavaScript запускается в первый раз, создается глобальный контекст выполнения, который помещается в текущий стек выполнения. Всякий раз, когда происходит вызов функции, движок создает новый контекст выполнения функции для этой функции и перемещает его в верхнюю часть стека. текущий стек выполнения.
- Когда функция в верхней части стека завершена, соответствующий ей контекст выполнения функции будет извлечен из стека выполнения, а управление контекстом будет перемещено в следующий контекст выполнения текущего стека выполнения.
Чтобы проиллюстрировать фрагмент кода:
function fun3() {
console.log('fun3')
}
function fun2() {
fun3();
}
function fun1() {
fun2();
}
fun1();
Global Execution Context
(то есть глобальный контекст выполнения) сначала помещается в стек, и процесс выглядит следующим образом:
Поддельный код:
//全局执行上下文首先入栈
ECStack.push(globalContext);
//执行fun1();
ECStack.push(<fun1> functionContext);
//fun1中又调用了fun2;
ECStack.push(<fun2> functionContext);
//fun2中又调用了fun3;
ECStack.push(<fun3> functionContext);
//fun3执行完毕
ECStack.pop();
//fun2执行完毕
ECStack.pop();
//fun1执行完毕
ECStack.pop();
//javascript继续顺序执行下面的代码,但ECStack底部始终有一个 全局上下文(globalContext);
цепочка прицелов
Цепочка областей видимости состоит в том, чтобы искать переменную слой за слоем из текущей области видимости, пока глобальная область видимости не будет найдена и все еще не найдена, она сдастся. Эта послойная связь представляет собой цепочку областей видимости.
Такие как:
var a = 10;
function fn1() {
var b = 20;
console.log(fn2)
function fn2() {
a = 20
}
return fn2;
}
fn1()();
Цепочка областей fn2 = [область fn2, область fn1, глобальная область]
8. Что такое БФК? Каковы правила компоновки для BFC? Как создать БФУ? (2019-05-29)
Что такое БФК
BFC — это сокращение от Block Formatting Context, то есть контекст форматирования блока. Давайте посмотрим на описание BFC в спецификации CSS2.1.
Floats, absolutely positioned elements, block containers (such as inline-blocks, table-cells, and table-captions) that are not block boxes, and block boxes with 'overflow' other than 'visible' (except when that value has been propagated to the viewport) establish new block formatting contexts for their contents.
Плавающие, абсолютно позиционированные элементы, блочные контейнеры для неблочных блоков (например, встроенные блоки, ячейки таблицы и заголовки таблиц) и
overflow
Значение неvisible
(кроме случаев, когда значение было передано в область просмотра) Устанавливает новый контекст форматирования блока для его содержимого.
Поэтому, если мы хотим глубже понять BFC, нам необходимо понять следующие две концепции:
1.Box
2.Formatting Context
Box
Блок — это объект и основная единица макета CSS, а страница состоит из нескольких блоков.
тип элемента иdisplay
Атрибут, определяющий тип этого ящика. Различные типы блоков будут участвовать в разных контекстах форматирования.
Formatting Context
Контекст форматирования представляет собой область рендеринга страницы и имеет набор правил рендеринга, которые определяют, как будут позиционироваться его дочерние элементы, а также их взаимосвязь и взаимодействие с другими элементами.
Контекст форматирования включает BFC (контекст форматирования блока), IFC (контекст встроенного форматирования), FFC (контекст форматирования Flex) и GFC (контекст форматирования сетки). FFC и GFC появились в CC3 впервые.
Правила компоновки BFC
- Внутри BFC коробки расположены последовательно вертикально.
- В BFC расстояние по вертикали между двумя ящиками определяется выражением
margin
атрибутивное решение. Поля двух соседних блоков, принадлежащих одному и тому же BFC, будут перекрываться [поля, соответствующие принципу слияния, объединяются для использования большего поля] - В BFC левый внешний край каждого блока касается левого края внутреннего блока (для форматов с письмом справа налево касается правого края). Это верно даже при наличии поплавков. Если не будет создан новый BFC.
- Область BFC не будет перекрывать флоат-бокс.
- BFC — это изолированный и независимый контейнер на странице, и дочерние элементы внутри контейнера не будут влиять на внешние элементы. Наоборот.
- При расчете высоты БФК в расчете также участвуют плавающие элементы.
Как создать БФЦ
- корневой элемент
- Плавающий элемент (свойство float не равно none)
- позиция абсолютная или фиксированная
- блочные элементы, переполнение которых не видно
- display inline-block, table-cell, table-caption
Применение БФК
1. Предотвратите перекрытие полей
<style>
.a{
height: 100px;
width: 100px;
margin: 50px;
background: pink;
}
</style>
<body>
<div class="a"></div>
<div class="a"></div>
</body>
два div сразуmargin
50px и бываетmargin
перекрытие.
Согласно правилам BFC, два соседних ящика в пределах одного BFC являются
margin
Будет перекрытие, поэтому мы можем вложить другой контейнер вне div и запустить контейнер для создания BFC, поэтому<div class="a"></div>
будет принадлежать двум БФК, и естественно больше не повторитсяmargin
перекрытие
<style>
.a{
height: 100px;
width: 100px;
margin: 50px;
background: pink;
}
.container{
overflow: auto; /*触发生成BFC*/
}
</style>
<body>
<div class="container">
<div class="a"></div>
</div>
<div class="a"></div>
</body>
2. Очистить внутренний поплавок
<style>
.a{
height: 100px;
width: 100px;
margin: 10px;
background: pink;
float: left;
}
.container{
width: 120px;
border: 2px solid black;
}
</style>
<body>
<div class="container">
<div class="a"></div>
</div>
</body>
Высота контейнера не растягивается.Если мы хотим, чтобы высота контейнера содержала плавающие элементы, мы можем создать новый BFC, так как по правилам BFC при расчете высоты BFC также участвуют плавающие элементы в расчете.
<style>
.a{
height: 100px;
width: 100px;
margin: 10px;
background: pink;
float: left;
}
.container{
width: 120px;
display: inline-block;/*触发生成BFC*/
border: 2px solid black;
}
</style>
3. Адаптивная многоколоночная верстка
<style>
body{
width: 500px;
}
.a{
height: 150px;
width: 100px;
background: pink;
float: left;
}
.b{
height: 200px;
background: blue;
}
</style>
<body>
<div class="a"></div>
<div class="b"></div>
</body>
По правилам, площадь БТЧ не будет перекрывать флоат-бокс. Следовательно, генерация нового BFC может быть запущена следующим образом:
<style>
.b{
height: 200px;
overflow: hidden; /*触发生成BFC*/
background: blue;
}
</style>
9. В чем разница между let, const и var? (2019-05-30)
Метод объявления | переменное продвижение | Временная мертвая зона | Повторите заявление | область действия блока действительна | Первоначальный значение | переназначить |
---|---|---|---|---|---|---|
var | Могу | не существует | разрешать | нет | не обязательно | разрешать |
let | Не будет | существует | не положено | да | не обязательно | разрешать |
const | Не будет | существует | не положено | да | должен | не положено |
1. Переменные, определенные с помощью let/const, не будут повышаться, в то время как переменные, определяемые с помощью var, будут повышаться.
a = 10;
var a; //正常
a = 10;
let a; //ReferenceError
2. В той же области видимости let и const не допускают повторных объявлений, а var допускает повторные объявления.
let a = 10;
var a = 20;
//抛出异常:SyntaxError: Identifier 'a' has already been declared
3. Начальное значение должно быть установлено, когда const объявляет переменную
const a;//SyntaxError: Missing initializer in const declaration
4.const объявляет константу только для чтения, которую нельзя изменить.
Здесь есть очень важный момент: для сложных типов данных адрес, хранящийся в стеке, является адресом памяти кучи, адрес, хранящийся в стеке, неизменен, но значение, хранящееся в куче, можно изменить. Существуют ли довольно постоянные указатели/константы указателей~
const a = 20;
const b = {
age: 18,
star: 500
}
Изображение стоит тысячи слов, как показано на рисунке ниже, константа 20 хранится в a в памяти стека, а 0x0012ff21 (случайное число) хранится в b. И {возраст: 18, звезда: 200} изменчив. Подумайте, какой метод следует использовать, если вы хотите, чтобы объект был неизменным?
5. Переменные, объявленные с помощью let/const, допустимы только в области блочного уровня. Переменные, объявленные с помощью var, по-прежнему доступны за пределами области блока.
{
let a = 10;
const b = 20;
var c = 30;
}
console.log(a); //ReferenceError
console.log(b); //ReferenceError
console.log(c); //30
До let/const, когда я впервые изучал JS, меня беспокоила следующая проблема:
ожидать:a[0]() 输出 0 , a[1]() 输出 1 , a[2]() 输出 2 , ...
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 10
Хотя позже я узнал почему, но для получения нужного мне результата, мне все равно нужно все закрытие.Я... Что я сделал не так, что со мной так обращаются...
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = (function(j){
return function () {
console.log(j);
}
})(i)
}
a[6](); // 6
С позволь, наконец, не будь таким хлопотным.
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6
Красиво, а есть~
Красота прекрасна, но вы должны спросить себя, почему~
var i
Почему вывод равен 10, это потому, что i допустимо в глобальной области видимости, что эквивалентно только одной переменной i и т. д.a[6]()
, каково значение этого i? Пожалуйста, говорите.
Глядя снова на let, мы говорим, что переменные, объявленные с помощью let, действительны только в области видимости блока, переменная i объявлена с помощью let, а текущая i допустима только в этом цикле, поэтому i в каждом цикле на самом деле новая переменная. Заинтересованные партнеры могут просмотреть скомпилированный код babel.
6. Переменные, объявленные var в области видимости верхнего уровня, висят на окне (окружение браузера)
var a = 10;
console.log(window.a);//10
7.let/const имеет проблему временной мертвой зоны, то есть переменные, объявленные в let/const, недоступны до тех пор, пока они не определены. При использовании будет выброшена ошибка.
Пока в области блочного уровня есть команда let, объявляемые ею переменные «привязаны» к этой области и больше не подвержены влиянию извне.
var a = 10;
if (true) {
a = 20; // ReferenceError
let a;
}
Внутри блока кода переменная недоступна, пока она не будет объявлена с помощью команды let/const, что означает, что typeof больше не является на 100% безопасной операцией.
console.log(typeof b);//undefined
console.log(a); //ReferenceError
let a = 10;
10. В чем разница между глубоким и поверхностным копированием? Как реализовать глубокую копию? (2019-05-31)
Глубокое копирование и мелкое копирование предназначены для сложных типов данных.
глубокая копия
Глубокое копирование копирует значение переменной.Для переменных небазового типа выполняется рекурсия к переменной базового типа перед копированием. Объект после глубокого копирования полностью изолирован от исходного объекта и не влияет друг на друга, модификации одного объекта не повлияют на другой объект.
мелкая копия
Поверхностная копия заключается в копировании каждого свойства объекта по очереди, но когда значение свойства объекта является ссылочным типом, фактическая копия является его ссылкой, и когда значение, на которое указывает ссылка, изменяется, оно также изменится.
можно использоватьfor in
,Object.assign
, оператор спреда...
,Array.prototype.slice()
,Array.prototype.concat()
и т.д., например:
let obj = {
name: 'Yvette',
age: 18,
hobbies: ['reading', 'photography']
}
let obj2 = Object.assign({}, obj);
let obj3 = {...obj};
obj.name = 'Jack';
obj.hobbies.push('coding');
console.log(obj);//{ name: 'Jack', age: 18,hobbies: [ 'reading', 'photography', 'coding' ] }
console.log(obj2);//{ name: 'Yvette', age: 18,hobbies: [ 'reading', 'photography', 'coding' ] }
console.log(obj3);//{ name: 'Yvette', age: 18,hobbies: [ 'reading', 'photography', 'coding' ] }
Видно, что поверхностным копированием копируется только первый слой атрибутов.Когда значение атрибута первого слоя является базовым типом данных, новый объект и исходный объект не влияют друг на друга, но если значение атрибута первый слой — сложный тип данных, тогда значения атрибутов нового объекта и исходного объекта указывают на один и тот же адрес памяти. Давайте посмотрим на использованиеfor in
Реализуйте поверхностную копию.
let obj = {
name: 'Yvette',
age: 18,
hobbies: ['reading', 'photography']
}
let newObj = {};
for(let key in obj){
newObj[key] = obj[key];
//这一步不需要多说吧,复杂数据类型栈中存的是对应的地址,因此赋值操作,相当于两个属性值指向同一个内存空间
}
console.log(newObj);
//{ name: 'Yvette', age: 18, hobbies: [ 'reading', 'photography' ] }
obj.age = 20;
obj.hobbies.pop();
console.log(newObj);
//{ name: 'Yvette', age: 18, hobbies: [ 'reading' ] }
реализация глубокого копирования
1. Простейшая реализация глубокого копирования:
JSON.parse(JSON.stringify(obj))
let obj = {
name: 'Yvette',
age: 18,
hobbies: ['reading', 'photography']
}
let newObj = JSON.parse(JSON.stringify(obj));//newObj和obj互不影响
obj.hobbies.push('coding');
console.log(newObj);//{ name: 'Yvette', age: 18, hobbies: [ 'reading', 'photography' ] }
JSON.parse(JSON.stringify(obj))
это самый простой способ реализации, но имеет небольшой недостаток:
1. Когда значением свойства объекта является функция, его нельзя скопировать.
let obj = {
name: 'Yvette',
age: 18,
hobbies: ['reading', 'photography'],
sayHi: function() {
console.log(sayHi);
}
}
let newObj = JSON.parse(JSON.stringify(obj));
console.log(newObj);//{ name: 'Yvette', age: 18, hobbies: [ 'reading', 'photography' ] }
2. Свойства цепочки прототипов не могут быть получены
function Super() {
}
Super.prototype.location = 'NanJing';
function Child(name, age, hobbies) {
this.name = name;
this.age = age;
}
Child.prototype = new Super();
let obj = new Child('Yvette', 18);
console.log(obj.location); //NanJing
let newObj = JSON.parse(JSON.stringify(obj));
console.log(newObj);//{ name: 'Yvette', age: 18}
console.log(newObj.location);//undefined;原型链上的属性无法获取
3. Не удается правильно обрабатывать данные типа Date
4. Не может обрабатывать регулярное выражение
5. Символ будет проигнорирован
6. Будет игнорировать неопределенное
let obj = {
time: new Date(),
reg: /\d{3}/,
sym: Symbol(10),
name: undefined
}
let obj2 = JSON.parse(JSON.stringify(obj));
console.log(obj2); //{ time: '2019-06-02T08:16:44.625Z', reg: {} }
2. Реализуйте функцию deepClone
- Если это базовый тип данных, вернуть напрямую
- если
RegExp
илиDate
тип, вернуть соответствующий тип - Если это сложный тип данных, рекурсивный.
function deepClone(obj) { //递归拷贝
if(obj instanceof RegExp) return new RegExp(obj);
if(obj instanceof Date) return new Date(obj);
if(obj === null || typeof obj !== 'object') {
//如果不是复杂数据类型,直接返回
return obj;
}
/**
* 如果obj是数组,那么 obj.constructor 是 [Function: Array]
* 如果obj是对象,那么 obj.constructor 是 [Function: Object]
*/
let t = new obj.constructor();
for(let key in obj) {
//如果 obj[key] 是复杂数据类型,递归
if(obj.hasOwnProperty(key)){//是否是自身的属性
t[key] = deepClone(obj[key]);
}
}
return t;
}
тестовое задание:
function Super() {
}
Super.prototype.location = 'NanJing';
function Child(name, age, hobbies) {
this.name = name;
this.age = age;
this.hobbies = hobbies;
}
Child.prototype = new Super();
let obj = new Child('Yvette', 18, ['reading', 'photography']);
obj.sayHi = function () {
console.log('hi');
}
console.log(obj.location); //NanJing
let newObj = deepClone(obj);
console.log(newObj);//
console.log(newObj.location);//NanJing 可以获取到原型链上的属性
newObj.sayHi();//hi 函数属性拷贝正常
3. Циркулярные ссылки
Предыдущий deepClone не рассматривал проблему циклических ссылок, таких как атрибут объекта, который является самим объектом.
function deepClone(obj, hash = new WeakMap()) { //递归拷贝
if(obj instanceof RegExp) return new RegExp(obj);
if(obj instanceof Date) return new Date(obj);
if(obj === null || typeof obj !== 'object') {
//如果不是复杂数据类型,直接返回
return obj;
}
if (hash.has(obj)) {
return hash.get(obj);
}
/**
* 如果obj是数组,那么 obj.constructor 是 [Function: Array]
* 如果obj是对象,那么 obj.constructor 是 [Function: Object]
*/
let t = new obj.constructor();
hash.set(obj, t);
for(let key in obj) {
//如果 obj[key] 是复杂数据类型,递归
if(obj.hasOwnProperty(key)){//是否是自身的属性
if(obj[key] && typeof obj[key] === 'object') {
t[key] = deepClone(obj[key], hash);
}else{
t[key] = obj[key];
}
}
}
return t;
}
Тестовый код:
const obj1 = {
name: 'Yvetet',
sayHi: function(){
console.log('Hi')
},
time: new Date(),
info: {
}
}
obj1.circle = obj1;
obj1.info.base = obj1;
obj1.info.name = obj1.name;
console.log(deepClone(obj1));
Справочная статья:
[1] woooooooo.EC-Code-international.org/EC-Code-262/6. …
[2] Понимание контекста выполнения Javascript и стека выполнения
[4] GitHub.com/ в настоящее время имеет бриз…
[5] блог woo woo woo.cn на.com/coco1 is/afraid/40…
[6] woo woo woo.cn blog on.com/Wang Fupeng 1…
[7] Уууу. Я 3.org/TR/2011/rec…
[8] GitHub.com/ в настоящее время имеет бриз…
Спасибо за вашу готовность потратить свое драгоценное время на чтение этой статьи. Если эта статья дала вам небольшую помощь или вдохновение, пожалуйста, не скупитесь на лайки и звезды. Вы, безусловно, самая большая движущая сила для меня, чтобы двигаться вперед .GitHub.com/Иветт Л.А. Ю/Б…