【周刊-1】三年大厂面试官-面试题精选及答案

前言

在阿里和腾讯工做了6年,当了3年的前端面试官,把期间我和个人同事常问的面试题和答案汇总在我 Github 的 Weekly-FE-Interview 中。但愿对你们有所帮助。javascript

若是你在bat面试的时候遇到了什么不懂的问题,欢迎给我提issue,我会把题目汇总并将面试要点和答案写好放在周刊里,你们一块儿共同进步和成长,助力你们进入本身理想的企业。前端

项目地址是:github.com/airuikun/We…java

常见面试题精选

如下是十道大厂一面的时候常见的面试题,若是所有理解而且弄透,在一面或者电话面的时候基本上能中1~2题。小伙伴能够先不急着看答案,先本身尝试着思考一下和本身实现一下,而后再看答案。node

第 1 题:http的状态码中,499是什么?如何出现499,如何排查跟解决

499对应的是 “client has closed connection”,客户端请求等待连接已经关闭,这颇有多是由于服务器端处理的时间过长,客户端等得“不耐烦”了。还有一种缘由是两次提交post过快就会出现499。 解决方法:nginx

  • 前端将timeout最大等待时间设置大一些
  • nginx上配置proxy_ignore_client_abort on;

提问解答与更多解析:github.com/airuikun/We…git

第 2 题:如何遍历一个dom树

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/airuikun/We…github

第 3 题:new操做符都作了什么

四大步骤:面试

一、建立一个空对象,而且 this 变量引用该对象,// lat target = {};算法

二、继承了函数的原型。// target.proto = func.prototype;数组

三、属性和方法被加入到 this 引用的对象中。并执行了该函数func// func.call(target);

四、新建立的对象由 this 所引用,而且最后隐式的返回 this 。// 若是func.call(target)返回的res是个对象或者function 就返回它

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/airuikun/We…

第 4 题:手写代码,简单实现call

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/airuikun/We…

第 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/airuikun/We…

第 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/airuikun/We…

第 7 题:讲解一下HTTPS的工做原理

HTTPS在传输数据以前须要客户端(浏览器)与服务端(网站)之间进行一次握手,在握手过程当中将确立双方加密传输数据的密码信息。TLS/SSL协议不只仅是一套加密传输的协议,更是一件通过艺术家精心设计的艺术品,TLS/SSL中使用了非对称加密,对称加密以及HASH算法。握手过程的简单描述以下:

  • 浏览器将本身支持的一套加密规则发送给网站。

  • 网站从中选出一组加密算法与HASH算法,并将本身的身份信息以证书的形式发回给浏览器。证书里面包含了网站地址,加密公钥,以及证书的颁发机构等信息。

  • 得到网站证书以后浏览器要作如下工做:

    • a) 验证证书的合法性(颁发证书的机构是否合法,证书中包含的网站地址是否与正在访问的地址一致等),若是证书受信任,则浏览器栏里面会显示一个小锁头,不然会给出证书不受信的提示。

    • 若是证书受信任,或者是用户接受了不受信的证书,浏览器会生成一串随机数的密码,并用证书中提供的公钥加密。

    • 使用约定好的HASH计算握手消息,并使用生成的随机数对消息进行加密,最后将以前生成的全部信息发送给网站。

  • 网站接收浏览器发来的数据以后要作如下的操做:

    • a) 使用本身的私钥将信息解密取出密码,使用密码解密浏览器发来的握手消息,并验证HASH是否与浏览器发来的一致。

    • b) 使用密码加密一段握手消息,发送给浏览器。

  • 浏览器解密并计算握手消息的HASH,若是与服务端发来的HASH一致,此时握手过程结束,以后全部的通讯数据将由以前浏览器生成的随机密码并利用对称加密算法进行加密。

提问解答与更多解析:github.com/airuikun/We…

第 8 题:讲解一下https对称加密和非对称加密。

对称加密: 发送方和接收方须要持有同一把密钥,发送消息和接收消息均使用该密钥。相对于非对称加密,对称加密具备更高的加解密速度,但双方都须要事先知道密钥,密钥在传输过程当中可能会被窃取,所以安全性没有非对称加密高。

非对称加密: 接收方在发送消息前须要事先生成公钥和私钥,而后将公钥发送给发送方。发送放收到公钥后,将待发送数据用公钥加密,发送给接收方。接收到收到数据后,用私钥解密。 在这个过程当中,公钥负责加密,私钥负责解密,数据在传输过程当中即便被截获,攻击者因为没有私钥,所以也没法破解。 非对称加密算法的加解密速度低于对称加密算法,可是安全性更高。

提问解答与更多解析:github.com/airuikun/We…

第 9 题: 简单实现项目代码按需加载,例如import { Button } from 'antd',打包的时候只打包button

原理很简单,就是将

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/airuikun/We…

第 10 题:简单手写实现promise

// 简易版本的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/airuikun/We…

结语

本人还写了一些前端进阶知识的文章,若是以为不错能够点个star。

blog项目地址是:github.com/airuikun/bl…

我是小蝌蚪,腾讯高级前端工程师,跟着我一块儿每周攻克几个前端技术难点。但愿在小伙伴前端进阶的路上有所帮助,助力你们进入本身理想的企业。

相关文章
相关标签/搜索