Вспомните процесс собеседования на большой фабрике.

JavaScript

предисловие

В середине июня 2019 года я очень устал от посредственной работы и ничем не примечательной раньше зарплаты, и, невзирая на противодействие своей семьи, я решительно решил отправиться в приморский город один, подумав о поиске работы поинтереснее, причем основательно. Заново полируйте себя в земле и в то же время добивайтесь лучшего пакета заработной платы. Конечно, до этого, каждый день после работы, я использовал свободное время, чтобы просмотреть и закрепить вопросы и т. д. Это началось, вероятно, в марте и продолжалось более 3 месяцев. Затем с середины июня до конца июня, примерно через две недели между ними, на самом деле, мое образование и опыт не являются выдающимися, но я лично чувствую, что это может быть связано с тем, что мое резюме немного хорошее (Возможно, позже я напишу отдельную статью, в которой расскажу о своем опыте составления резюме.), так что HR большой фабрики может бросить еще несколько взглядов Компании в середине включают в себя:Гималаи, Ctrip, Bilibili, Liulishuo, Dragonfly FM, AihuishouПодождите, давайте получим 4 или 5 предложений одно за другим, и теперь они стали положительными, поэтому я записываю некоторые из предыдущих вопросов интервью здесь и делюсь ими с вами.

текст

1. Сеть свирепого медведя

На самом деле я мало что знал об этой компании.Его посоветовал мой бывший коллега.Говорили,зарплата хорошая.Тогда у меня было свободное время в то время,поэтому я поехал попробовать.Хотя репутация компании не очень такие большие, как компании, упомянутые выше, но я думаю, что его вопросы для интервью все еще достаточно весомы.

1.1 Пожалуйста, укажите порядок выполнения следующего кода

async function async1() {
  console.log(1);
  const result = await async2();
  console.log(3);
}

async function async2() {
  console.log(2);
}

Promise.resolve().then(() => {
  console.log(4);
});

setTimeout(() => {
  console.log(5);
});

async1();
console.log(6);

Мой ответ [1,2,6,4,3,5]. Этот вопрос в основном проверяет JSзадача макросаа такжемикрозадачиСтепень понимания каждой макрозадачи в цикле событий JS называетсяTick(маркер), очередь микрозадач будет добавлена ​​в конце каждой разметки, и после выполнения макрозадачи будут выполняться все микрозадачи до тех пор, пока очередь не опустеет. В приведенном выше вопросе, как мне кажется, немного сложнее функция async1.Сама функция async1 возвращает обещание, а за ожиданием следует обещание, возвращаемое функцией async2.console.log(3)На самом деле он выполняется в операторе then обещания, возвращаемом функцией async2.Сам оператор then также вернет промис, а затем добавит его в очередь микрозадач, поэтому в очереди микрозадачconsole.log(3)существуетconsole.log(4)Позже студенты, которые не уверены, могут проверить информацию в Интернете или обратить внимание на мой публичный аккаунт «Front-end Realm», мы можем общаться и учиться вместе.

1.2 Вручную реализовать промис и написать псевдокод

К счастью, я только что проверил эту часть информации перед собеседованием, поэтому процесс ответа довольно удобен, в основном для того, чтобы следовать спецификации Promise/A+:
(1) Обещание должно иметь три состояния (ожидание|выполнено(разрешено)|отклонено). Когда оно находится в состоянии ожидания, оно может быть переведено в состояние выполнено (решено) или отклонено. (разрешенное) состояние или отклоненное состояние, состояние больше не может быть изменено;
(2) Промис должен иметь метод then, который должен принимать два параметра:

// onFulfilled在状态由pending -> fulfilled(resolved) 时执行,参数为resolve()中传递的值
// onRejected在状态由pending -> rejected 时执行,参数为reject()中传递的值
promise.then(onFulfilled,onRejected)

(3) Метод then должен возвращать обещание:

promise2 = promise1.then(onFulfilled, onRejected);

Вставьте код реализации напрямую:

Ссылка из:Реализуйте обещание, которое полностью соответствует спецификации Promise/A+.

function myPromise(constructor){
    let self=this;
    self.status="pending" //定义状态改变前的初始状态
    self.value=undefined;//定义状态为resolved的时候的状态
    self.reason=undefined;//定义状态为rejected的时候的状态
    self.onFullfilledArray=[];
    self.onRejectedArray=[];
    function resolve(value){
       if(self.status==="pending"){
          self.value=value;
          self.status="resolved";
          self.onFullfilledArray.forEach(function(f){
                f(self.value);
                //如果状态从pending变为resolved,
                //那么就遍历执行里面的异步方法
          });
        
       }
    }
    function reject(reason){
       if(self.status==="pending"){
          self.reason=reason;
          self.status="rejected";
          self.onRejectedArray.forEach(function(f){
              f(self.reason);
             //如果状态从pending变为rejected, 
             //那么就遍历执行里面的异步方法
          })
       }
    }
    //捕获构造异常
    try{
       constructor(resolve,reject);
    }catch(e){
       reject(e);
    }
}

myPromise.prototype.then=function(onFullfilled,onRejected){
    let self=this;
    let promise2;
    switch(self.status){
      case "pending":
        promise2 = new myPromise(function(resolve,reject){
             self.onFullfilledArray.push(function(){
                setTimeout(function(){
                  try{
	                 let temple=onFullfilled(self.value);
	                 resolvePromise(temple)
	                }catch(e){
	                   reject(e) //error catch
	                }
                })
             });
             self.onRejectedArray.push(function(){
                setTimeout(function(){
                   try{
	                   let temple=onRejected(self.reason);
	                   resolvePromise(temple)
	                 }catch(e){
	                   reject(e)// error catch
	               }
                })
             });
        })
      case "resolved":
        promise2=new myPromise(function(resolve,reject){
           setTimeout(function(){
               try{
	              let temple=onFullfilled(self.value);
	              //将上次一then里面的方法传递进下一个Promise状态
	              resolvePromise(temple);
	            }catch(e){
                  reject(e);//error catch
               }
           })
        })
        break;
      case "rejected":
        promise2=new myPromise(function(resolve,reject){
           setTimeout(function(){
             try{
               let temple=onRejected(self.reason);
               //将then里面的方法传递到下一个Promise的状态里
               resolvePromise(temple);   
             }catch(e){
               reject(e);
             }
           })
        })
        break;
      default:       
   }
   return promise2;
}

function resolvePromise(promise,x,resolve,reject){
  if(promise===x){
     throw new TypeError("type error")
  }
  let isUsed;
  if(x!==null&&(typeof x==="object"||typeof x==="function")){
      try{
        let then=x.then;
        if(typeof then==="function"){
           //是一个promise的情况
           then.call(x,function(y){
              if(isUsed)return;
              isUsed=true;
              resolvePromise(promise,y,resolve,reject);
           },function(e){
              if(isUsed)return;
              isUsed=true;
              reject(e);
           })
        }else{
           //仅仅是一个函数或者是对象
           resolve(x)
        }
      }catch(e){
         if(isUsed)return;
         isUsed=true;
         reject(e);
      }
  }else{
    //返回的基本类型,直接resolve
    resolve(x)
  }
}

1.3 Произнесите следующую распечатку

let a = {a: 10};
let b = {b: 10};
let obj = {
  a: 10
};
obj[b] = 20;
console.log(obj[a]);

Мой ответ: 20. Этот вопрос в основном проверяет владение типами данных JS и владение ES6.выражение имени свойствапонимание. в вопросе вышеobj[b] = 20После операции присваивания ,objФактически, это стало{a: 10, [object Object]: 20}, это связано с тем, что если выражение имени свойства является объектом, оно автоматически преобразует объект в строку по умолчанию.[object Object], последний шаг, чтобы получитьobj[a], сам по себе также является объектом, поэтому он будет преобразован для полученияobj['[object Object]']То есть 20, назначенных на предыдущем шаге.

1.4 Назовите несколько способов дедупликации массивов

На самом деле схем реализации в интернете уже много, и я, пожалуй, приведу следующие:

let originalArray = [1,2,3,4,5,3,2,4,1];

// 方式1
const result = Array.from(new Set(originalArray));
console.log(result); // -> [1, 2, 3, 4, 5]

// 方式2
const result = [];
const map = new Map();
for (let v of originalArray) {
    if (!map.has(v)) {
        map.set(v, true);
        result.push(v);
    }
}
console.log(result); // -> [1, 2, 3, 4, 5]

// 方式3
const result = [];
for (let v of originalArray) {
    if (!result.includes(v)) {
        result.push(v);
    }
}
console.log(result); // -> [1, 2, 3, 4, 5]

// 方式4
for (let i = 0; i < originalArray.length; i++) {
    for (let j = i + 1; j < originalArray.length; j++) {
        if (originalArray[i] === originalArray[j]) {
            originalArray.splice(j, 1);
            j--;
        }
    }
}
console.log(originalArray); // -> [1, 2, 3, 4, 5]

// 方式5
const obj = {};
const result = originalArray.filter(item => obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true));
console.log(result); // -> [1, 2, 3, 4, 5]

1.5 Как дедуплицировать массивы объектов?

Данной темой задается не только одна компания.В начале я запутался,думая,что адрес памяти у каждого самого объекта разный.В чем смысл дедупликации?Если надо сделать,можно только пройтиJSON.stringifyСериализуйте его в строку (у этого метода есть определенные недостатки) и сравните его, или выполните сравнение ключ-значение рекурсивным способом, но это все еще требует много времени для больших вложенных объектов, поэтому я все еще не ответил на него хорошо. Позже интервьюер добавил, что я сказал, что дедупликация основана на определенном атрибуте каждого объекта, потому что, учитывая, что в данных, возвращаемых сервером, могут быть повторяющиеся идентификаторы, внешний интерфейс необходимо фильтровать следующим образом:

const responseList = [
  { id: 1, a: 1 },
  { id: 2, a: 2 },
  { id: 3, a: 3 },
  { id: 1, a: 4 },
];
const result = responseList.reduce((acc, cur) => {
    const ids = acc.map(item => item.id);
    return ids.includes(cur.id) ? acc : [...acc, cur];
}, []);
console.log(result); // -> [ { id: 1, a: 1}, {id: 2, a: 2}, {id: 3, a: 3} ]

2. Отключение

В это время накануне было телефонное интервью, а на следующий день двое интервьюеров по очереди задавали вопросы. Это длилось около полутора часов. Было еще много вопросов. , извините!

2.1 Вы понимаете глубокое копирование и поверхностное копирование?

мелкая копияОтносится к созданию объекта, имеющего точную копию значений свойств исходного объекта. Если свойство является типом-примитивом, копируется значение типа-примитива, а если свойство является ссылочным типом, копируется адрес памяти, поэтому, если один объект изменит некоторые свойства, это повлияет на другой объект.
глубокая копияЭто означает полное копирование объекта из памяти и выделение для него новой области памяти в памяти кучи для хранения, а изменение свойств объекта не повлияет на исходный объект.

2.2 Каковы методы реализации глубокого и неглубокого копирования?

Мелкая копия: (1) способ Object.assign (2) через оператор распространения объекта (3) через метод среза массива (4) через метод concat массива.
Глубокая копия: (1) json.Stringify для сериализации объектов (2), достигнутых вручную в рекурсивном порядке.

2.3 Об идее реализации бесшовного вращения?

Кратко расскажем об идее реализации карусели. Несколько картинок располагаются по порядку слева направо. При нажатии левой и правой кнопок для переключения картинок пусть значение смещения влево родительского контейнера картинки увеличивается или уменьшите ширину одного изображения. , и сотрудничайте с переходом перехода CSS3 или напишите функцию анимации вручную, которая может добиться более плавного эффекта анимации. Для бесшовной карусели моя идея в то время заключалась в том, чтобы скопировать родительский контейнер другого изображения, например исходного.<ul><li></li><li></li></ul>Соответствует двум картинкам, теперь их становится дваulСоответствует 4 изображениям одновременноulРодительский контейнер слушает свой собственныйscrollLeft, если значение уже больше или равноulширина, он тут же преобразует собственныйscrollLeftЗначение сбрасывается на 0, так что вращение может начаться снова с начальной точки для бесшовного эффекта.

2.3 Произнесите результат выполнения следующего кода

  var a = 10;
  var obj = {
      a: 20,
      say: function () {
          console.log(this.a);
      }
  };
  obj.say();

Это моя упрощенная версия. Я не могу четко вспомнить конкретные вопросы. Во всяком случае, это главный вопрос этого теста. Ответ на вопрос выше - 20. Затем интервьюер продолжил спрашивать, как вывести 10, и дал следующий метод:

  // 方式1
  var a = 10;
  var obj = {
      a: 20,
      say: () => {  // 此处改为箭头函数
          console.log(this.a);
      }
  };
  obj.say(); // -> 10
  
  // 方式2
  var a = 10;
  var obj = {
      a: 20,
      say: function () {
          console.log(this.a);
      }
  };
  obj.say.call(this); // 此处显示绑定this为全局window对象
  
  // 方式3
  var a = 10;
  var obj = {
      a: 20,
      say: function () {
          console.log(this.a);
      }
  };
  
  var say = obj.say; // 此处先创建一个临时变量存放函数定义,然后单独调用
  say();

2.4 Каковы жизненные циклы Vue?

Создать: перед созданием, создано;
Загрузка: beforeMount, смонтированный;
обновление: перед обновлением, обновлено;
Уничтожено: beforeDestroy, уничтожено;

2.5 Как разработать удобный компонент заголовка для мобильного терминала?

Идея в то время заключалась в том, что шапка вообще делится на три части: левую, среднюю и правую, и делится на три области по дизайну.Середина является основным заголовком, а заголовок каждой страницы должен быть разным, поэтому может быть сделано с помощью vue props. Это настраивается и доступно для внешнего мира. Большинство страниц слева могут быть кнопками «Назад», но стиль и содержание отличаются. Правая сторона обычно представляет собой функциональную кнопку управления, поэтому левая и правые стороны могут проходить через слот слота vue.Метод подвергается воздействию внешнего мира для достижения диверсификации, а слот по умолчанию также может быть предоставлен для унификации стиля страницы.

2.6 Назовите разницу между пространством-между и пространством-вокруг?

Это содержимое гибкого макета, которое на самом деле является разницей в полях.Согласно горизонтальному макету,space-betweenНет поля слева и справа, в то время какspace-aroundПоля будут оставлены слева и справа, и то же самое верно для вертикальной компоновки, как показано на следующем рисунке:

2.7. Известные вам решения по оптимизации производительности переднего плана

На самом деле вариантов еще больше, можно начать сУровень стакана цен,Уровень стиля CSSа такжеЛогический уровень JSДля начала отдельно, пожалуй, дам следующее:
(1) Чтобы уменьшить количество посещений DOM, DOM можно кэшировать в переменных;
(2) Уменьшениеперерисоватьа такжепереплавка, любой вызоветперерисоватьа такжепереплавкаоперации должны быть сведены к выполнениюОбъединение нескольких операций в одну;
(3) попробуйте использоватьделегация мероприятияПривязка событий таким образом, чтобы избежать чрезмерного использования памяти, вызванного большим количеством привязок;
(4) уровень CSS, насколько это возможноПлоский, избегайте слишком большого количества уровней вложенности, попробуйте использоватьконкретный селекторразличать;
(5) Используйте CSS3 для анимации как можно большеАнимационные свойстваДля этого включите аппаратное ускорение графического процессора;
(6) Изображение продвигается перед загрузкойУкажите ширину и высотуиливне документооборота, что позволяет избежать переформатирования страницы, вызванного пересчетом после загрузки;
(7) Файл css находится в<head>Представленный в теге файл js находится в<body>Представлено в тегах, оптимизированокритический путь рендеринга;
(8) Чтобы ускорить или уменьшить HTTP-запросы, используйтеCDN для загрузки статических ресурсов, разумное использование браузераСильный кеша такжеСогласовать кеш, можно использовать маленькие картинкиBase64Вместо этого добросовестное использование браузераПредварительная выборка инструкцийа такжепредварительная загрузка инструкции;
(9) Сжать запутанный код,удалить бесполезный код,разделение кодаУменьшить размер файла;
(10) Используйте Sprite для небольших изображений, выберите подходящую картинкукачественный,размера такжеФормат, чтобы не тратить трафик.

2.8 Как разрешать конфликты, когда несколько человек сотрудничают в git

Конфликты в основном возникают, когда несколько человек изменяют одну и ту же часть одного и того же файла, а другая сторонаpush, то вы послеpushКогда git обнаружит, что две фиксации не совпадают, предложит вамConflict,затем выpullНижний код будет использоваться в конфликтующем месте=====Раздельно, в это время нужно найти соответствующего разработчика для обсуждения выбора кода, вырезанияНе может быть изменен по желанию и принудительно отправлен, после разрешения конфликта сноваpushВот и все.

3. Гималаи

В то время было два раунда технических интервью, одно на месте и одно на месте.На некоторые вопросы на электронном экране все еще были расплывчатые ответы.

3.1 Вручную реализовать метод привязки

код показывает, как показано ниже:

Function.prototype.bind = function(context, ...args1) {
    if (typeof this !== 'function') {
        throw new Error('not a function');
    }
    
    let fn = this;
    let resFn = function(...args2) {
        return fn.apply(this instanceof resFn ? this : context, args1.concat(args2));
    };
    const DumpFunction = function DumpFunction() {};
    DumpFunction.prototype = this.prototype;
    resFn.prototype = new DumpFunction();
    
    return resFn;
}

3.2 Расскажите о своем понимании React Hooks

В React у нас обычно есть два способа создания компонентов:определение классаилиопределение функции;В определениях классов мы можем использовать многие функции React, такие как состояние или различные хуки жизненного цикла, но не в определениях функций. Поэтому в версии React 16.8 была недавно введена функция React Hooks.Благодаря React Hooks мы можем использовать функции, которые можно использовать только в определении класса в определении функции. Конечно, появление React Hooks само по себе также связано с повторным использованием компонентов, и по сравнению с хуками жизненного цикла в определениях классов, React Hooks обеспечиваютuseEffectОбъединение нескольких хуков жизненного цикла делает логику, изначально разбросанную по определению класса, более централизованной, что удобно для обслуживания и управления.

3.3 Как useEffect в React Hooks отличает хуки жизненного цикла

useEffectможно рассматривать какcomponentDidMount,componentDidUpdateа такжеcomponentWillUnmountсочетание трех.useEffect(callback, [source])Получив два параметра, метод вызова выглядит следующим образом:

 useEffect(() => {
   console.log('mounted');
   
   return () => {
       console.log('willUnmount');
   }
 }, [source]);

Функция жизненного цикла вызывается в основном через второй параметр[source]Для контроля существуют следующие ситуации:
(1) [source]Когда параметры не передаются, функция, возвращаемая в последней сохраненной функции, будет вызываться первой каждый раз, а затем будет вызываться внешняя функция;
(2) [source]передача параметров[], внешняя функция будет вызываться только один раз во время инициализации, а возвращаемая функция будет вызываться только один раз при выгрузке компонента;
(3) [source]Когда параметр имеет значение, он будет вызывать возвращаемую функцию только после изменения значения в массиве, а затем вызывать внешнюю функцию.

3.4 Что такое компонент высшего порядка (HOC)

Сам компонент высшего порядка на самом деле не компонент, а функция, которая получаетметакомпонентв качестве параметра, затем возвращает новыйРасширенные компоненты, внешний вид компонентов более высокого порядка также предназначен для повторного использования логики, например:

  function withLoginAuth(WrappedComponent) {
      return class extends React.Component {
          
          constructor(props) {
              super(props);
              this.state = {
                isLogin: false
              };
          }
          
          async componentDidMount() {
              const isLogin = await getLoginStatus();
              this.setState({ isLogin });
          }
          
          render() {
            if (this.state.isLogin) {
                return <WrappedComponent {...this.props} />;
            }
            
            return (<div>您还未登录...</div>);
          }
      }
  }

3.5 Произнесите результат выполнения следующего кода

parseInt('2017-07-01') // -> 2017
parseInt('2017abcdef') // -> 2017
parseInt('abcdef2017') // -> NaN

3.6 В мобильном приложении, реализованном на React, если есть зависание, какие решения по оптимизации можно рассмотреть

(1) увеличениеshouldComponentUpdateкрючок для старого и новогоpropsсравнивать и предотвращать обновления, если значения совпадают, избегая ненужного рендеринга, или использоватьPureReactComponentзаменятьComponent, который был заключен внутриshouldComponentUpdateНеглубокая логика сравнения ;
(2) Для списков или других узлов с одинаковой структурой добавьте уникальныйkeyсвойства для облегчения ReactdiffПовторное использование узла в алгоритме сокращает создание и удаление узлов;
(3) renderВ функции уменьшить что-то вродеonClick={() => {doSomething()}}Способ письма, каждый звонокrenderПри использовании функции будет создана новая функция. Даже если содержимое не изменилось, это вызовет ненужную повторную визуализацию узла. Рекомендуется сохранить функцию в объекте-члене компонента, чтобы она создаваться только один раз;
(4) КомпонентыpropsЕсли вам нужно выполнить ряд операций для получения конечного результата, вы можете рассмотреть возможность использованияreselectБиблиотека кэширует результаты, еслиpropsЕсли значение не изменилось, результат берется прямо из кеша, чтобы избежать больших вычислительных затрат;
(5) webpack-bundle-analyzerПроанализируйте зависимости текущей страницы, чтобы увидеть, нет ли лишнего, если да, то найдите точку оптимизации и оптимизируйте ее.

3.7 (Алгоритмическая проблема) Как найти 10 самых больших чисел из 10 000 чисел

Я плохо ответил на этот вопрос, два слова описывают его: неаккуратно! Столкнувшись с проблемой алгоритма, легко занервничать и растеряться.Приходите к правильному решению.

Создайте минимальную структуру кучи, начальное значение — первые 10 из 10 000 чисел, а вершина кучи — наименьшее число из 10 чисел. Затем пройдите оставшиеся 9990 номеров.Если число меньше, чем число в верхней части кучи, отбрасывайте его напрямую.В противном случае удалите число в верхней части кучи, вставьте пройденное число в кучу и структуру кучи будет автоматически скорректирован, поэтому число вершины кучи может быть гарантировано. Должно быть наименьшее из 10 чисел. После завершения обхода 10 чисел в куче являются самыми большими 10 из 10 000 чисел.

4. Говорите свободно

В то время было предварительное телефонное интервью, а затем я выехал на место через несколько дней.Было два раунда технических интервью на месте.Компания уделяла большое внимание основополагающим принципам, поэтому ответа не было. отлично.

4.1 React реализует поле ввода нечеткого запроса с защитой от сотрясения

код показывает, как показано ниже:

  // 防抖函数
  function debounce(fn, wait, immediate) {
    let timer = null;
    
    return function (...args) {
        let context = this;
        
        if (immediate && !timer) {
            fn.apply(context, args);
        }
        
        if (timer) clearTimeout(timer);
        timer = setTimeout(() => {
            fn.apply(context, args);
        }, wait);
    }
  }
  
  class SearchInput extends React.Component {
  
      constructor(props) {
          super(props);
          this.state = {
              value: ''
          };
          this.handleChange = this.handleChange.bind(this);
          this.callAjax = debounce(this.callAjax, 500, true);
      }
      
      handleChange(e) {
          this.setState({
              value: e.target.value
          });
          this.callAjax();
      }
      
      callAjax() {
          // 此处根据输入值调用服务端接口
          console.log(this.state.value);
      }
      
      render() {
          return (<input type="text" value={this.state.value} onChange={this.handleChange} />);
      }
      
  }

4.2 Вручную инкапсулировать функцию запроса, вы можете установить максимальное количество запросов.Если запрос будет успешным, больше запросов не будет.Если запрос не будет выполнен, запрос будет продолжаться до тех пор, пока не будет превышено максимальное количество раз.

код показывает, как показано ниже:

  function request(url, body, successCallback, errorCallback, maxCount = 3) {
      return fetch(url, body)
               .then(response => successCallback(response))
               .catch(err => {
                   if (maxCount <= 0) return errorCallback('请求超时');
                   return request(url, body, successCallback, errorCallback, --maxCount);
               });
  }
  
  // 调用
  request('https://some/path', { method: 'GET', headers: {} }, (response) => {
      console.log(response.json());
  }, (err) => console.error(err));

4.3 Разница между == и === в JS

==выражатьабстрактное равенство, когда типы значений на обеих сторонах разные, это будет сделано первымнеявное преобразование типов, а затем сравните значения;
===выражатьстрогое равенство, преобразование типов выполняться не будет, и типы с обеих сторон не должны совпадать.

4.4 Разница между GET и POST

(1) GET-запросы безвредны, когда браузер откатывается и обновляется, а POST-запросы информируют пользователя о том, что данные будут отправлены повторно;
(2) Запросы GET могут быть добавлены в закладки, но запросы POST не могут быть добавлены в закладки;
(3) Запросы GET можно кэшировать, но запросы POST нельзя кэшировать, если в заголовок ответа не включено соответствующее поле Cache-Control/Expires, но не рекомендуется кэшировать запросы POST, которые не удовлетворяют идемпотентности, и каждый вызов будут затронуты ресурсы сервера;
(4) Запросы GET обычно не имеют тела запроса, поэтому может выполняться только кодирование URL, тогда как запросы POST поддерживают несколько методов кодирования.
(5) параметры GET-запроса могут храниться в истории браузера, а POST-запрос не будет сохранен;
(6) Поскольку запросы GET добавляют данные к URL-адресу, разные производители браузеров, прокси-серверов и веб-серверов могут иметь свои собственные ограничения по длине, в то время как запросы POST не имеют ограничений по длине;
(7) запросы GET допускают только символы ASCII, запросы POST не ограничены, поддерживаются двоичные данные;
(8) Безопасность запроса GET низкая, и данные отображаются в URL-адресе браузера, поэтому их нельзя использовать для передачи конфиденциальной информации.Безопасность запроса POST лучше, и данные не будут раскрыты в URL-адресе;
(9) запросы GET являются идемпотентными (множественные запросы не влияют на ресурсы), а запросы POST не являются идемпотентными;
(10) Запрос GET обычно не имеет тела запроса, и запрос обычно не содержит протокола 100-continue, поэтому отправляется только один запрос, в то время как запрос POST позволяет обеим сторонам «подтвердить» перед отправкой данных в сервер, и клиент сначала отправляет ожидание: сообщение 100-continue спрашивает сервер, готов ли он получать данные.После получения правильного ответа 100-continue от сервера тело запроса будет отправлено на сервер, и сервер ответит 200, чтобы вернуть данные.

4.5 Давайте поговорим о механизме кэширования браузера

Механизм кэширования браузера можно разделить наСильный кеша такжеСогласовать кеш, сервер может добавить в заголовок ответаCache-Control/Expiresустановить срок действия кеша для текущего ресурса (Максимальный возраст Cache-Control имеет более высокий приоритет, чем Expires), когда браузер снова отправляет запрос, он сначала определяет, истек ли срок действия кеша. Если срок его действия не истек, он попадет в сильный кеш и напрямую использует ресурсы локального кеша браузера. Если срок его действия истек, он будет использовать согласованный кеш.Есть примерно два варианта согласования кеша:
(1) Уникальный идентификатор:Etag (передается ответом сервера) и If-None-Match (передается запросом клиента);
(2) Время последней модификации:Last-Modified (передается ответом сервера) и If-Modified-Since (передается запросом клиента), его приоритет ниже, чем Etag.
Сервер оценивает, согласуются ли значения, и если да, возвращает напрямую304Скажите браузеру использовать локальный кеш и вернуть новый ресурс, если он несовместим.

5. Билибили

Во время двух туров технических интервью я задавал много вопросов для проверки базовых знаний, в целом ответы меня вполне удовлетворили.

5.1 Каковы свойства перехода и анимации в CSS3

transitionАнимация перехода:
(1) transition-property: Имя свойства
(2) transition-duration: интервалы
(3) transition-timing-function: кривая анимации
(4) transition-delay: Задерживать

animationАнимация ключевого кадра:
(1) animation-name: название анимации
(2) animation-duration: интервалы
(3) animation-timing-function: кривая анимации
(4) animation-delay: Задерживать
(5) animation-iteration-count: Количество анимаций
(6) animation-direction: направление
(7) animation-fill-mode: отключить режим

5.2 Блочная модель

Относится к модели макета, используемой элементами DOM при отображении страницы. Пространство, занимаемое элементом, состоит из нескольких частей, содержимого, отступов, границ и полей. в состоянии пройтиbox-sizingЧтобы установить, содержимое блочной модели IE содержит отступы и границы, которые отличаются от стандартной блочной модели W3C.

5.3 Приоритет селектора

!important > встроенные стили > селектор идентификатора > селектор класса > селектор тегов > * > наследование > по умолчанию

5.4 Разница между forEach, картой и фильтром

forEachОбход массива, параметр является функцией обратного вызова, функция обратного вызова получает три параметра, текущий элемент, индекс элемента и весь массив;
mapа такжеforEachАналогично обходим массив, но возвращаемое значение его функции обратного вызова сформирует новый массив, структура индекса нового массива такая же, как у исходного массива, а исходный массив остается неизменным;
filterВозвращает подмножество исходного массива, функция обратного вызова используется для логического суждения, возвращаетtrueТекущий элемент добавляется к возвращаемому массиву, в противном случае текущий элемент исключается, а исходный массив остается неизменным.

5.5 Реализация каррирования функций

код показывает, как показано ниже:

const curry = (fn, ...args1) => (...args2) => (
 arg => arg.length === fn.length ? fn(...arg) : curry(fn, ...arg)
)([...args1, ...args2]);

// 调用
const foo = (a, b, c) => a * b * c;
curry(foo)(2, 3, 4); // -> 24
curry(foo, 2)(3, 4); // -> 24
curry(foo, 2, 3)(4); // -> 24
curry(foo, 2, 3, 4)(); // -> 24

5.6 Каковы способы связи между вкладками

(1) BroadCast Channel
(2) Service Worker
(3) LocalStorage + мониторинг window.onstorage
(4) Shared Worker + опрос таймера (setInterval)
(5) IndexedDB + опрос таймера (setInterval)
(6) cookie + опрос таймера (setInterval)
(7) window.open + window.postMessage
(8) Websocket

5.7 Реализуйте функцию для определения типа данных

код показывает, как показано ниже:

function getType(obj) {
   if (obj === null) return String(obj);
   return typeof obj === 'object' 
   ? Object.prototype.toString.call(obj).replace('[object ', '').replace(']', '').toLowerCase()
   : typeof obj;
}

// 调用
getType(null); // -> null
getType(undefined); // -> undefined
getType({}); // -> object
getType([]); // -> array
getType(123); // -> number
getType(true); // -> boolean
getType('123'); // -> string
getType(/123/); // -> regexp
getType(new Date()); // -> date

Суммировать

Некоторые вопросы интервью я действительно не могу вспомнить. Большинство из приведенных выше вопросов относительно простые, и частота их задается относительно часто. Вот простое изложение. Я надеюсь, что это поможет вам более или менее. Если у вас есть какие-либо сомнения , пожалуйста, оставьте сообщение для обсуждения.

общаться с

Я поделюсь этим здесь сегодня Автор только что открыл новую официальную учетную запись Если вы заинтересованы в обучении с автором и обсуждении технологий друг с другом, вы можете подписаться на нашу официальную учетную запись и стать свидетелем роста официальной учетной записи.

Статья обновлена ​​доБлог на гитхабе, Если вы считаете, что статья приемлема, добро пожаловать!

Один из ваших лайков заслуживает моих дополнительных усилий!

Вырастая перед лицом невзгод, только постоянно учась, вы можете стать лучшей версией себя и поощрять себя!