美文网首页
前端面试经典

前端面试经典

作者: 2359634711 | 来源:发表于2019-09-25 12:14 被阅读0次

javaScript

  • 理解MVVM等框架,手写伪代码。

  • ES6新特性,说说class

  • 从编译角度谈谈变量提升

  • 对象的类型

  • 继承中的toString

每一个引用类型会重写toString方法。
所以如果要输出对象的类型,需要使用Object.prototype.toString方法。
将他call到需要输出的对象上。

基本类型6个

boolean、string、null、undefined、number、symbol

引用类型1个

object

  • 判断类型

1、instanceof

内部使用原型链的方式进行比较。
所以必须是引用类型,不可以是基本类型。
但是!!如果使用new创建的string为对象(引用类型)

2、typeof

只能对基本类型进行判断,对引用类型(Array、RegExp)返回object

3、constructor
str.constructor == String    //true
arr.constructor == Array     //true
4、toString
Object.prototype.toString.call(arr)      //"[object Array]"
Object.prototype.toString.call(str)      //"[object String]"
5、原型链比较proto
str.__proto__ == String.prototype      //true
arr.__proto__ == Array.prototype      //true
  • 继承

不要修改对象的__proto__属性,修改这个属性会同时修改构造函数的prototype的对应的参数,然后会修改所有派生的其他对象。
在javaScript编译过程中,分为两个阶段,预编译阶段和执行赋值阶段,在预编译阶段,js编译器会查找代码中的var关键字和函数声明,并将他们在顶部声明并赋值为undfine。执行赋值阶段在进行赋值。

Webpack

  • webpack是什么?运行流程?热更新原理?

webpack是一个打包模块化javaScript的工具,在webpack里一切文件皆为模块,通过loader转换文件,通过plugin注入钩子,最后输出由多个模块组合成的文件,webpack专注构建模块化项目。webpack可以看作是模块打包机:他做的事情是,分析你的项目结构,找到javaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript),并将其打包(通过loader)为合适的格式(css,ES5,javaScript)以供浏览器使用。


image
  • 0x02 webpack运行流程

1、初始化参数:从配置文件以及shell命令行获取参数,并整合成输入参数。
2、开始编译:将上一步的参数初始化compiler对象,加载所有配置的插件plugin,执行run方法开始编译。
3、寻找入口文件:通过配置文件的entry来找到所有的入口文件。
4、进行模块的编译:从入口文件出发,将所有依赖的模块通过loader进行编译,之后递归遍历所有引用的模块,编译输出。
5、完成模块编译:在经过第4步以后,得到了每个模块最终的翻译内容以及它们的依赖关系。
6、输出资源:根据入口文件和模块的依赖关系,组装成一个一个包含多个模块的chunk,再把每个chunk转换成一个单独的文件加入到输出列表,这步是可以修改输出文件的最后机会。
7、输出完成,在确定好输出内容以后,根据配置确定输出的路径和文件名,再把文件内容写入到文件系统。
在以上过程中,webpack在特定时间会广播特定事件,plugin可以监听感兴趣的事件,并通过webpackAPI修改运行结果。

  • 0x03 loader和plugin的编写思路以及功能特点:

Loader像是一个翻译官,把读到的原文件内容转译成新的文件内容,并且每个loader通过链式操作,将原文件一步一步翻译成想要的样子。

编写loader要遵循单一原则,每个loader只做一种转义功能。每个loader拿到的是原文件内容(source),可以通过返回值的方式将处理后的内容输出,也可以调用this.callback()方法,将内容返回给webpack。还可以通过this.async()生成一个callback函数,再用这个callback将处理后的内容输出出去。此外webpack还为开发者准备了开发loader的工具函数集--------loader-utils。
相对于loader而言,plugin的编写就灵活了许多,webpack运行的生命周期中会广播出很多事件,plugin可以监听这些事件,在合适的时机通过webpack提供的API改变输出结果。

  • 0x04 webpack的热更新是如何做到的?说明其原理?

webpack的热更新又称热替换(Hot Module Replacement),缩写为HMR。这个机制可以做到不用刷新浏览器而将新更变的模块替换旧的模块。


image

1、第一步,在webpack的watch模式下,文件系统的某一个文件发生变化以后,webpack监听到文件变化,根据配置文件对模块重新打包编译,并将打包后的代码通过简单的javaScript对象保存在内存中。
2、第二步,webpack-dev-server和webpack之间的接口交互,在这一步,主要是dev-server的中间件webpack-dev-middleware和webpack之间的交互,webpack-dev-middleware调用webpack暴露的API对代码进行监控,并且告诉webpack,将代码打包到内存中。
3、第三步,webpack-dev-server对文件变化的监控,当我们的配置文件中devServer.watchContentBase为true的时候,server会监听这些配置文件夹中静态文件的变化,变化后会通知浏览器对应用进行live reload。是刷新浏览器,和HMR是两个概念。
4、第四步,webpack-dev-server通过sockjs(sebpack-dev-server的依赖)在浏览器和服务器之间建立一个websocket长连接,将webpack编译打包的各个阶段的状态信息告知浏览器端,同时也包括第三步中server监听静态文件变化的信息。浏览器根据这些信息进行不同的操作。当然,服务端传递的最主要的信息还是新模块的hash值,后面的步骤根据这个hash值来进行模块的热替换。
5、webpack-dev-server/client端并不能够请求更新的代码,也不会执行热更新模块操作,而是把这些工作交给webpack,webpack/hot/dev-server的工作就是根据webpack-dev-server/client传给他的信息以及dev-server的配置决定是刷新浏览器还是进行热更新,如果仅仅是刷新浏览器,就没有后面的步骤了。
6、HotModuleReplacement.runtime是客户端HMR的中枢,它接受上一步传递给他的新模块的hash值,他通过JsonpTemplate.runtime向server端发送ajax请求,服务端返回一个json,该json包含了所有要更新的模块的hash值,获取到更新列表后,该模块再次通过jsonp请求,获取到最新的模块代码,这就是上图的7、8、9步骤。
7、而第十步是决定HMR成功与否的关键步骤,在该步骤中,HotMoudulePlugin将会对新旧模块进行对比,决定是否更新模块,再决定更新模块后,检查模块之间的依赖关系,更新模块的同时更新模块间的依赖引用。
8、最后一步,当HMR失败后,回退到live reload操作,也就是刷新浏览器获取最新打包代码。

0x05 手写promise

    function MyPromise(executor) {
        let that = this;
        this.state = 'pending'
        this.value = undefined
        this.reason =undefined
        this.onFulfilledFunc = [];
        this.onRejectedFunc = [];
        executor(resolve, reject)

        function resolve(value){
            if(that.state == 'pending'){
                that.value = value;
                that.onFulfilledFunc.forEach(fn => fn(value))
                that.state = 'resolved'
            }
        }
        function reject(reason){
            if(that.state == 'pending'){
                that.reason = reason;
                that.onRejectedFunc.forEach(fn => fn(reason))
                that.state = 'rejected'
            }
        }
    }

MyPromise.prototype.then = function(onFulfilled, onRejected) {
    if(this.state == 'resolved'){
        if(typeof onFulfilled === 'function'){
            onFulfilled(this.value)
        }
    }
    if(this.state == 'rejected'){
        if(typeof onRejected === 'function'){
            onRejected(this.reason)
        }
    }
    if(this.state === 'pending'){
        if(typeof onFulfilled === 'function'){
            this.onFulfilledFunc.push(onFulfilled)
        }
        if(typeof onRejected === 'function'){
            this.onRejectedFunc.push(onRejected)
        }
    }
}

let a = new MyPromise((resolve, reject) => {
    setTimeout(()=>{
    resolve('assssd')//
    }, 1)
})
a.then(res => {
    console.log(res)
})

0x06 手写jsonp

(function(window, document){
    "use strict"
    var jsonp = function(url, data, callback){
        //data 为json对象
        //将data转化为dataStr
        let dataStr = '?'
        for (const key in data) {
            dataStr += key + '=' + data[ley] + '&'
        }
        //定义jsonp的callback名字,需要包含随机数字
        let cbFuncName = 'my_json_cb_' + Math.random().toString().replace('.', '');
        dataStr += 'callBack='+cbFuncName;
        //创建jsonp script节点
        let script = document.createElement('script');
        //修改jsonp script节点的url
        script.src = url + dataStr
        //全局jsonp函数
        window[cbFuncName] = function(data) {
            //执行callback
            callback(data)
            //执行完毕删除script节点
            document.body.removeChild(script)
        }
        //加入script节点进行请求
        document.body.appendChild(script)
        //将jsonp挂载到window上面
        window.$jsonp = jsonp
    }
})(window, document)

0x07 手写new

//new
function _new(){
    let newObj = {};
    let Constructor = Array.prototype.shift.call(arguments);
    newObj.__proto__ = Constructor.prototype;
    Constructor.apply(newObj, arguments);
    return newObj
}

0x08 手写bind/call/apply

//call

/**
 * @param this
 * @param ...arg
 */
Function.prototype.myCall = function(obj){
    let object = obj || window;
    let args = [...arguments].slice(1);
    object.func = this;//绑定函数
    let result = object.func(...args);
    delete object.func;
    return result
}

//bind
Function.prototype.myBind = function(obj){
    let that = this;
    const object = obj;
    let args = [...arguments].slice(1);
    return function(){
        let newArgs = [...arguments];
        return that.apply(object, args.concat(newArgs))
    }
}

0x09 手写双向绑定

<body>
    <div></div>
    <p></p>
    <div style="border-top: 10px solid rgba(0, 0, 0, 0);border-right: 10px solid rgba(0, 0, 0, 0.5);border-left: 10px solid rgba(0, 0, 0, 0);border-bottom: 10px solid rgba(0, 0, 0, 1);background: rgba(0, 0, 0, 0);width: 10px;height: 10px;"></div>
<input type="text" id="txt">
    <script>
        console.log(Math.round(4, 2))
        var obj = {}
        Object.defineProperty(obj, 'txt', {
            get: function() {
                return obj
            },
            set: function(newValue){
                document.body.getElementsByTagName('div')[0].innerHTML = newValue
            }
        })

        document.addEventListener('keyup', (e) => {
            obj.txt = e.target.value
        })
    </script>
</body>

算法

  • 二叉树
    javaScript前序遍历
// 先序遍历:中,左,右
const TreeNode = {
  val: 1,
  left: {
    val: 2,
    left: {
      val: 4,
    },
    right: {
      val: 5
    }
  },
  right: {
    val: 3,
    left: {
      val: 6,
    },
    right: {
      val: 7
    }
  }
};

// 递归方式的先序遍历方法
var preOrderRecur = function(root){

  var list = [];
  var preOrder = function(root){
    if(root === undefined){
      return root;
    }
    list.push(root.val)
    preOrder(root.left);
    preOrder(root.right);
  }
  preOrder(root);
  return list;
};

// 非递归方式的先序遍历方法
var preOrder = function(TreeNode){
  var list = [];
  let stack = [TreeNode];
  while(stack.length !== 0){
    const cur = stack.pop();
    const right = cur.right;
    const left = cur.left;
    list.push(cur.val);

    if(right){
      stack.push(right);
    }
    if(left){
      stack.push(left);
    }
  }
  return list;
  
  
}


var list = preOrderRecur(TreeNode);
console.log('递归前序遍历', list);

var listUnRecur = preOrder(TreeNode);
console.log('非递归前序遍历', listUnRecur);

// [1, 2, 4, 5, 3, 6, 7]
  • 链表环
  • 冒泡算法都有哪些?优势与区别?
  • 时间复杂度是什么?如何计算时间复杂度?

node

  • 异步
  • 调试

html css

  • ie模式和标准模式的盒模型

vue和react的区别

react setState如何优化

shouldComponentUpdate(nextProps, nextState) {
  return nextState.someData !== this.state.someData
}

http2头部压缩

http2头部压缩采用HPACK头部压缩,使用霍夫曼编码。

宏任务、微任务、event-loop

宏任务、微任务、event-loop
宏任务:setInterval、setTimeout、setImmediate、IO、requestAnimationFrame
微任务:promise、nextTick、async/await(本质上是promise)、mutationObserver
event-loop:实在宏任务完成后进行微任务检查。

  • 注意:宏任务中requestAnimationFarme要先于setTimeout执行。
  • setTimeout和setImmediate同级。
  • setTimeout为何不准确?如何让setTimeout更准确?
    setTimeout不准确是因为代码运行需要时间。
    在setTimeout内部计算代码运行的时间,然后减去。

http1.0 http1.1 http2.0 http和https区别

https://www.cnblogs.com/heluan/p/8620312.html

HTTP1.0和HTTP1.1的一些区别
  • 缓存处理,在HTTP1.0中主要使用header里的If-Modified-Since,Expires来做为缓存判断的标准,HTTP1.1则引入了更多的缓存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略。

  • 带宽优化及网络连接的使用,HTTP1.0中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP1.1则在请求头引入了range头域,它允许只请求资源的某个部分,即返回码是206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。

  • 错误通知的管理,在HTTP1.1中新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。

  • Host头处理,在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)。

  • 长连接,HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启Connection: keep-alive,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。

HTTP2.0的一些优势
  • 新的二进制格式(Binary Format),HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。

  • 多路复用(MultiPlexing),即连接共享,即每一个request都是是用作连接共享机制的。一个request对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的 id将request再归属到各自不同的服务端请求里面。

  • header压缩,如上文中所言,对前面提到过HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。

  • 服务端推送(server push),同SPDY一样,HTTP2.0也具有server push功能。

HTTP和HTTPS的一些区别
  • HTTPS协议需要到CA申请证书,一般免费证书很少,需要交费。

  • HTTP协议运行在TCP之上,所有传输的内容都是明文,HTTPS运行在SSL/TLS之上,SSL/TLS运行在TCP之上,所有传输的内容都经过加密的。

  • HTTP和HTTPS使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。

  • HTTPS可以有效的防止运营商劫持,解决了防劫持的一个大问题。

async await 实现原理 generator + yield + promise

https://www.jianshu.com/p/862ab6d1a2f6
主要是通过generator+yield+promise实现

原型链图

image.png

let和var

varlet均有变量遮蔽!!。
var没有块级作用域,但是let有块级作用域!!。

map和parseInt问题

参考文章

[1,2,2,3].map(parseInt)
//(4) [1, NaN, NaN, NaN]

因为parseInt第二个参数为将要转换的数字进制类型。
2进制没有3这个数字,
3进制没有4这个数字,
以此类推,所有显示NaN

reduce实现map

reduce实现map
reduce

Array.prototype._map = function(fn) { 
   return this.reduce((result, item) => [...result, fn(item)], []) 
} 
Array.prototype._filter = function(fn) { 
    return this.reduce((result, item) => fn(item) ? [...result, item] : result, []) 
}

稀疏数组

1 in [0,,2,3,4]
//false
1 in [0,2,2,3,4]
//true

BFC

参考文档
BFC面试题

多个标签页间进行通讯

  • worker
    通过postMessage和事件监听
//worker
// sharedWorker所要用到的js文件,不必打包到项目中,直接放到服务器即可
    let data = ''
    onconnect = function (e) {
        let port = e.ports[0]
        port.onmessage = function (e) {
            if (e.data === 'get') {
                port.postMessage(data)
            }
            else { data = e.data }
        }
    }
// 这段代码是必须的,打开页面后注册SharedWorker,显示指定worker.port.start()方法建立与worker间的连接

    if (typeof Worker === "undefined") {

      alert('当前浏览器不支持webworker')

    } else {

      let worker = new SharedWorker('worker.js')

      worker.port.addEventListener('message', (e) => {

        console.log('来自worker的数据:', e.data)

      }, false)

      worker.port.start()

      window.worker = worker

    }

// 获取和发送消息都是调用postMessage方法,我这里约定的是传递'get'表示获取数据。

window.worker.port.postMessage('get')

window.worker.port.postMessage('发送信息给worker')

//页面A发送数据给worker,然后打开页面B,调用window.worker.port.postMessage('get'),即可收到页面A发送给worker的数据。
  • websocket
  • 轮询
  • 同域cookie
  • localStorage

最大数字

javaScript最大数字

判断整数

xxx % 1 === 0

1+-'1'+1 = 1

七层协议

  • 物理层
    第一层,物理电路连接,网络通信数据传输介质,由电缆和设备构成。
  • 数据链路层
    第二层,传输以‘帧’为单位的数据包,采用差错控制与流量控制,使得有差错的物理线路变成无差错的数据链路。基于MAC地址实现,SWITCH交换机。
  • 网络层
    第三层,为数据节点之间传输创建逻辑链路,通过路由选择算法为子网选择合适的路径,实现网络拥塞控制,网络互连。基于IP,实现router路由器。
  • 传输层
    第四层,提供可靠的端对端服务,处理数据包错误,数据次序,以及一些其他的关键问题,向高层屏蔽下层细节,是非常关键的一层。
    TCP/IP,UDP等协议在此层。
  • 会话层
    第五层,负责维护两个节点的传输连接,确保点到点不中断,管理数据交换。
  • 表示层
    第六层,处理两个通信系统中交换信息的表示方式,主要包括数据格式的变换,数据的加密解密,数据的压缩与恢复。
  • 应用层
    最高层,为软件提供很多服务,比如文件服务器,数据库服务,电子邮件与其他网络软件服务。(HTTP、POP、STMP、FTP)
  • Promise catch
    内部采用try...catch实现的,只能catch同步操作

curry

参考文章curry

function curry(fn){
    //第一个参数是基础执行方法,slice切除
    var args=Array.prototype.slice.call(arguments,1);
    //直接返回匿名函数
    return function(){
        //slice新参数以便能调用concat
        var innerArgs=Array.prototype.slice.call(arguments);
        //将配置的参数和新传入的参数合并
        var finalArgs=args.concat(innerArgs);
        return fn.apply(null,finalArgs);
    };
}
//ES6
var curry = fn => (...left) => (...right) => fn(...left, ...right)

reduce

Array.prototype.customReduce = function(fn , prev) {
    for(let i = 0; i<this.length; i++) {
        if (typeof prev === 'undefined') {
            // prev不存在
            prev = fn(this[i], this[i+1], i+1, this);
            i++;
        } else {
            prev = fn(prev, this[i], i, this);
        }
    }
    return prev;
}
  • 使用reduce实现map
Array.prototype._map = function(fn, callbackThis) {
    // 最终返回的新数组
    let res = [];
    // 定义回调函数的执行环境
    // call第一个参数传入null,则 this指向全局对象,同 map的规则
    let CBThis = callbackThis || null;
    this.reduce((brfore, after, idx, arr) => {
        // 传入map回调函数拥有的参数
        // 把每一项的执行结果push进res中
        res.push(fn.call(CBThis, after, idx, arr));
    }, null);
    return res;
};

首页白屏?

当前很多无线页面都使用前端模板进行数据渲染,那么在糟糕的网速情况下,一进去页面,看到的不是白屏就是 loading,这成为白屏问题。

此问题发生的原因基本可以归结为网速跟静态资源

1、css文件加载需要一些时间,在加载的过程中页面是空白的。 解决:可以考虑将css代码前置和内联。

2、首屏无实际的数据内容,等待异步加载数据再渲染页面导致白屏。 解决:在首屏直接同步渲染html,后续的滚屏等再采用异步请求数据和渲染html。

3、首屏内联js的执行会阻塞页面的渲染。 解决:尽量不在首屏html代码中放置内联脚本。(来自翔歌)

解决方案

根本原因是客户端渲染的无力,因此最简单的方法是在服务器端,使用模板引擎渲染所有页面。同时

1减少文件加载体积,如html压缩,js压缩

2加快js执行速度 比如常见的无限滚动的页面,可以使用js先渲染一个屏幕范围内的东西

3提供一些友好的交互,比如提供一些假的滚动条

4使用本地存储处理静态文件。

json不能传输的格式

DOM节点、文件表单等不能转化为文本的信息。

前端性能指标

白屏时间
首屏时间
用户可操作时间
页面总下载时间

inline-block

  • 设置letter-spacing: -3px;
  • 设置font-size: 0px;
  • 设置font-size:0px;会有什么问题?
    如果inline-block里面没有内容的话,垂直方向会有间隙,需要设置:
{
  font-size: 0px;  
  vertical-align: bottom;
}

伪类和伪元素

  • 伪类是选择器,辅助CSS选择器选不到的元素
    比如
    :first-child
    :hover
    :focus
  • 伪元素是添加的额外的css容器

    ::before
    ::after

xss和csrf

参考文章XSS
参考文章CSRF
XSS:通过任何手段,在目标网站上留下一段脚本,当受害者执行时记录cookie等信息。
CSRF:通过目标网站植入表单等脚本,诱导用户执行。借用cookie,但是不记录。

display属性

image.png

align属性

image.png

text-align属性

image.png

vertical-align属性

image.png

数字超过最大安全数字

安全数字bigInt
最大数字1.111112^1023 Number.MAX_VALUE
最大安全数字1.11111
2^52 Number.MAX_SAFE_INTEGER
使用bigInt可以解决,数字+n

typeof 12n//bigInt

for循环中,i++

image.png

相关文章

  • 前端面试的经典题

    前端面试的经典题 前端面试三部曲 前端面试概念收集器 前端面试的经典题 前端面试的难题和怪题 Javascript...

  • 前端面试概念收集器

    前端面试概念收集器 前端面试三部曲 前端面试概念收集器 前端面试的经典题 前端面试的难题和怪题 本文分为 概念,原...

  • 前端面试的难题和怪题

    前端面试的难题和怪题 前端面试三部曲 前端面试概念收集器 前端面试的经典题 前端面试的难题和怪题 函数 答案 Er...

  • 总结前端问题

    前端经典面试题: 1、(前端面试题)https://zhuanlan.zhihu.com/p/84212558?f...

  • Front Interview导航2020-09-07

    JavaScript 【面试】前端JavaScript面试技巧【反向面试】—反问面试官的问题玩转经典十大Top10...

  • 2019前端面试题汇总(主要为Vue)

    摘要: 经典面试题。 原文:2019前端面试题汇总(主要为Vue) 作者:前端小酱 Fundebug经授权转载,版...

  • 2019前端面试题汇总(主要为Vue)

    摘要: 经典面试题。 原文:2019前端面试题汇总(主要为Vue) 作者:前端小酱 Fundebug经授权转载,版...

  • 前端面试经典

    javaScript 理解MVVM等框架,手写伪代码。 ES6新特性,说说class 从编译角度谈谈变量提升 对象...

  • 2018年最新经典web前端面试题

    2018年最新经典web前端面试题汇总。如果你一些基本问题答对了,那么我可以肯定的是 你面试任何公司的前端...

  • 2018最新Web前端经典面试试题及答案

    index 2018最新Web前端经典面试试题及答案 __wu javascript JavaScript中如何检...

网友评论

      本文标题:前端面试经典

      本文链接:https://www.haomeiwen.com/subject/kjtwyctx.html