【Еженедельно-1】Трехлетний интервьюер на большом заводе - подборка вопросов и ответов для интервью

JavaScript

предисловие

Я проработал в Alibaba и Tencent 6 лет, а в качестве фронтенд-интервьюера — 3 года.Я собрал вопросы и ответы, которые часто задают мои коллеги и я, в своем интервью Weekly-FE-Interview на Github. Я надеюсь быть полезным.

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

Адрес проекта:GitHub.com/Ай Руи спать/мы…

Подборка распространенных вопросов на собеседовании

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

Вопрос 1: Что такое 499 в коде состояния http? Как появляется 499, как устранить неполадки и решить

499 соответствует «клиент закрыл соединение». Клиент запрашивает ожидание закрытия соединения. Скорее всего, это связано с тем, что время обработки на стороне сервера слишком велико, а клиент «нетерпеливо» ждет. Другая причина заключается в том, что 499 появится, если сообщение будет отправлено дважды слишком быстро. Решение:

  • Внешний интерфейс устанавливает максимальное время ожидания тайм-аута, чтобы быть больше
  • Настройте proxy_ignore_client_abort на nginx;

Вопросы и ответы и дополнительный анализ:GitHub.com/Ай Руи спать/мы…

Вопрос 2: Как пройти по дереву домов

function traversal(node) {
    //对node的处理
    if (node && node.nodeType === 1) {
        console.log(node.tagName);
    }
    var i = 0,
        childNodes = node.childNodes,
        item;
    for (; i < childNodes.length; i++) {
        item = childNodes[i];
        if (item.nodeType === 1) {
            //递归先序遍历子节点
            traversal(item);
        }
    }
}

Вопросы и ответы и дополнительный анализ:GitHub.com/Ай Руи спать/мы…

Вопрос 3: Что делает новый оператор

Четыре шага:

1. Создайте пустой объект, и переменная this ссылается на объект, // lat target = {};

2. Наследовать прототип функции. // цель.proto = func.prototype;

3. К объекту, на который ссылается this, добавляются свойства и методы. и выполнил функцию func// func.call(target);

4. На вновь созданный объект ссылается this и, наконец, неявно возвращает this. // Если res, возвращаемый func.call(target), является объектом или функцией, возвращаем его

function new(func) {
	lat target = {};
	target.__proto__ = func.prototype;
	let res = func.call(target);
	if (typeof(res) == "object" || typeof(res) == "function") {
		return res;
	}
	return target;
}

Вопросы и ответы и дополнительный анализ:GitHub.com/Ай Руи спать/мы…

Вопрос 4: Рукописный код, простая реализация вызова

Function.prototype.call2 = function(context) {
    var context = context || window; //因为传进来的context有可能是null
    context.fn = this;
    var args = [];
    for (var i = 1; i < arguments.length; i++) {
        args.push("arguments[" + i + "]"); //不这么做的话 字符串的引号会被自动去掉 变成了变量 导致报错
    }
    args = args.join(",");

    var result = eval("context.fn(" + args + ")"); //相当于执行了context.fn(arguments[1], arguments[2]);

    delete context.fn;
    return result; //因为有可能this函数会有返回值return
}

Вопросы и ответы и дополнительный анализ:GitHub.com/Ай Руи спать/мы…

Вопрос 5: Рукописный код, простая реализация apply

Function.prototype.apply2 = function(context, arr) {
    var context = context || window; //因为传进来的context有可能是null
    context.fn = this;
    var args = [];
    var params = arr || [];
    for (var i = 0; i < params.length; i++) {
        args.push("params[" + i + "]"); //不这么做的话 字符串的引号会被自动去掉 变成了变量 导致报错
    }
    args = args.join(",");

    var result = eval("context.fn(" + args + ")"); //相当于执行了context.fn(arguments[1], arguments[2]);

    delete context.fn;
    return result; //因为有可能this函数会有返回值return
}

Вопросы и ответы и дополнительный анализ:GitHub.com/Ай Руи спать/мы…

Вопрос 6: Рукописный код, простая реализация bind

Function.prototype.bind2 = function(context) {
    var _this = this;
    var argsParent = Array.prototype.slice.call(arguments, 1);
    return function() {
        var args = argsParent.concat(Array.prototype.slice.call(arguments)); //转化成数组
        _this.apply(context, args);
    };
}

Вопросы и ответы и дополнительный анализ:GitHub.com/Ай Руи спать/мы…

Вопрос 7: Объясните, как работает HTTPS

HTTPS требует рукопожатия между клиентом (браузером) и сервером (веб-сайтом) перед передачей данных. Протокол TLS/SSL — это не только набор зашифрованных протоколов передачи, но и произведение искусства, тщательно разработанное художником.В TLS/SSL используются асимметричное шифрование, симметричное шифрование и алгоритмы HASH. Краткое описание процесса рукопожатия выглядит следующим образом:

  • Браузер отправляет набор поддерживаемых им правил шифрования на веб-сайт.

  • Веб-сайт выбирает набор алгоритмов шифрования и алгоритмов HASH и отправляет свою идентификационную информацию обратно в браузер в виде сертификата. Сертификат содержит такую ​​информацию, как адрес веб-сайта, открытый ключ шифрования и орган, выдавший сертификат.

  • После получения сертификата веб-сайта браузер должен сделать следующее:

    • а) Проверить легитимность сертификата (является ли организация, выпустившая сертификат, законной, совпадает ли адрес веб-сайта, содержащийся в сертификате, с посещаемым адресом и т. д.), если сертификат является доверенным, небольшая блокировка будет отображаться в строке браузера, иначе будет сообщение о том, что сертификат не является доверенным.

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

    • Используйте согласованный HASH для расчета сообщения рукопожатия, зашифруйте сообщение сгенерированным случайным числом и, наконец, отправьте всю ранее сгенерированную информацию на веб-сайт.

  • После того, как веб-сайт получает данные, отправленные браузером, он делает следующее:

    • а) Используйте свой собственный закрытый ключ для расшифровки информации и извлечения пароля, используйте пароль для расшифровки сообщения рукопожатия, отправленного браузером, и проверьте, соответствует ли HASH тому, который отправлен браузером.

    • б) Зашифровать сообщение рукопожатия паролем и отправить его в браузер.

  • Браузер расшифровывает и вычисляет HASH сообщения рукопожатия.Если он согласуется с HASH, отправленным сервером, процесс рукопожатия на этом заканчивается, и все данные связи после этого будут зашифрованы случайным паролем, сгенерированным браузером. и с использованием алгоритма симметричного шифрования.

Вопросы и ответы и дополнительный анализ:GitHub.com/Ай Руи спать/мы…

Вопрос 8: Расскажите о симметричном шифровании https и асимметричном шифровании.

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

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

Вопросы и ответы и дополнительный анализ:GitHub.com/Ай Руи спать/мы…

Вопрос 9: Простая реализация загрузки кода проекта по запросу, например import {Button} из 'antd', при упаковке упаковывается только кнопка

Принцип прост, т.

import { Select, Pagination, Button } from 'xxx-ui';

Преобразовано в Babel

import Button from `xxx-ui/src/components/ui-base/Button/Button`;
import Pagination from `xxx-ui/src/components/ui-base/Pagination/Pagination`;
import Select from `xxx-ui/src/components/ui-base/Select/Select`;

Настройте и расширьте плагин Babel, код выглядит следующим образом:

visitor: {
	ImportDeclaration (path, { opts }) {
	    const specifiers = path.node.specifiers;
	    const source = path.node.source;

            // 判断传入的配置参数是否是数组形式
	    if (Array.isArray(opts)) {
	        opts.forEach(opt => {
	            assert(opt.libraryName, 'libraryName should be provided');
	        });
	        if (!opts.find(opt => opt.libraryName === source.value)) return;
	    } else {
	        assert(opts.libraryName, 'libraryName should be provided');
	        if (opts.libraryName !== source.value) return;
	    }

	    const opt = Array.isArray(opts) ? opts.find(opt => opt.libraryName === source.value) : opts;
	    opt.camel2UnderlineComponentName = typeof opt.camel2UnderlineComponentName === 'undefined'
	        ? false
	        : opt.camel2UnderlineComponentName;
	    opt.camel2DashComponentName = typeof opt.camel2DashComponentName === 'undefined'
	        ? false
	        : opt.camel2DashComponentName;

	    if (!types.isImportDefaultSpecifier(specifiers[0]) && !types.isImportNamespaceSpecifier(specifiers[0])) {
	        // 遍历specifiers生成转换后的ImportDeclaration节点数组
    		const declarations = specifiers.map((specifier) => {
	            // 转换组件名称
                    const transformedSourceName = opt.camel2UnderlineComponentName
                	? camel2Underline(specifier.imported.name)
                	: opt.camel2DashComponentName
            		    ? camel2Dash(specifier.imported.name)
            		    : specifier.imported.name;
    		    // 利用自定义的customSourceFunc生成绝对路径,然后创建新的ImportDeclaration节点
                    return types.ImportDeclaration([types.ImportDefaultSpecifier(specifier.local)],
                	types.StringLiteral(opt.customSourceFunc(transformedSourceName)));
                });
                // 将当前节点替换成新建的ImportDeclaration节点组
    		path.replaceWithMultiple(declarations);
    	}
    }
}

Вопросы и ответы и дополнительный анализ:GitHub.com/Ай Руи спать/мы…

Вопрос 10: Простая рукописная реализация обещаний

       // 简易版本的promise 
        // 第一步: 列出三大块  this.then   resolve/reject   fn(resolve,reject)
        // 第二步: this.then负责注册所有的函数   resolve/reject负责执行所有的函数 
        // 第三步: 在resolve/reject里面要加上setTimeout  防止还没进行then注册 就直接执行resolve了
        // 第四步: resolve/reject里面要返回this  这样就可以链式调用了
        // 第五步: 三个状态的管理 pending fulfilled rejected
     
        // *****promise的链式调用 在then里面return一个promise 这样才能then里面加上异步函数
        // 加上了catch
        function PromiseM(fn) {
            var value = null;
            var callbacks = [];
            //加入状态 为了解决在Promise异步操作成功之后调用的then注册的回调不会执行的问题
            var state = 'pending';
            var _this = this;

            //注册所有的回调函数
            this.then = function (fulfilled, rejected) {
                //如果想链式promise 那就要在这边return一个new Promise
                return new PromiseM(function (resolv, rejec) {
                    //异常处理
                    try {
                        if (state == 'pending') {
                            callbacks.push(fulfilled);
                            //实现链式调用
                            return;
                        }
                        if (state == 'fulfilled') {
                            var data = fulfilled(value);
                            //为了能让两个promise连接起来
                            resolv(data);
                            return;
                        }
                        if (state == 'rejected') {
                            var data = rejected(value);
                            //为了能让两个promise连接起来
                            resolv(data);
                            return;
                        }
                    } catch (e) {
                        _this.catch(e);
                    }
                });
            }

            //执行所有的回调函数
            function resolve(valueNew) {
                value = valueNew;
                state = 'fulfilled';
                execute();
            }

            //执行所有的回调函数
            function reject(valueNew) {
                value = valueNew;
                state = 'rejected';
                execute();
            }

            function execute() {
                //加入延时机制 防止promise里面有同步函数 导致resolve先执行 then还没注册上函数
                setTimeout(function () {
                    callbacks.forEach(function (cb) {
                        value = cb(value);
                    });
                }, 0);
            }

            this.catch = function (e) {
                console.log(JSON.stringify(e));
            }

            //经典 实现异步回调
            fn(resolve, reject);
        }


Вопросы и ответы и дополнительный анализ:GitHub.com/Ай Руи спать/мы…

Эпилог

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

Адрес проекта блога:GitHub.com/Эрик сонный/был бы…

Я Маленький Головастик, старший фронтенд-инженер в Tencent, и каждую неделю я буду преодолевать вместе со мной несколько технических трудностей. Я надеюсь, что это поможет вам на пути к развитию ваших друзей и поможет вам войти в ваше идеальное предприятие.