我的前端进阶之路
前言总括: 包含这三个月来碰到的一些觉得比较好的面试题,三个月没怎么写博客着实有些手痒,哈哈哈。7000余字,不成敬意2333
烈火试真金,逆境试强者 正文React和Vue对比相同点:
不同点:
(1). 手动添加 shouldComponentUpdate 来避免不需要的 vdom re-render。 (2).Components 尽可能都用 pureRenderMixin,然后采用 redux 结构 + Immutable.js;
gulp和webpack区别
防止重复发送Ajax请求
事件模型
浏览器缓存机制
Expires是Web服务器响应消息头字段,在响应http请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。Expires 是HTTP 1.0的东西,现在默认浏览器均默认使用HTTP 1.1,所以它的作用基本忽略。
Cache-Control与Expires的作用一致,都是指明当前资源的有效期,控制浏览器是否直接从浏览器缓读取数据还是重新发请求到服务器取数据。只不过Cache-Control的选择更多,设置更细致,如果同时设置的话,其优先级高于Expires。 以上是设置缓存时间的两种方法。那么当缓存时间过了咋整呢?有人肯定说了,那就再次发起请求啊,这是对的。问题是如果服务器资源并没有更新呢?比如说我有一个
首先Last-Modified/If-Modified-Since要配合Cache-Control使用。
Etag/If-None-Match也要配合Cache-Control使用。
HTTP1.1中Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:
Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。 Ajax的状态值与HTTP状态码
0: (未初始化)还没有调用send()方法。
200 & OK: 请求成功; 204 & No Content: 请求处理成功,但没有资源可以返回; 206 & Partial Content: 对资源某一部分进行请求(比如对于只加载了一般的图片剩余部分的请求); 301 & Move Permanently: 永久性重定向; 302 & Found: 临时性重定向; 303 & See Other: 请求资源存在另一个URI,应使用get方法请求; 304 & Not Modified: 服务器判断本地缓存未更新,可以直接使用本地的缓存; 307 & Temporary Redirect: 临时重定向; 400 & Bad Request: 请求报文存在语法错误; 401 & Unauthorized: 请求需要通过HTTP认证; 403 & Forbidden: 请求资源被服务器拒绝,访问权限的问题; 404 & Not Found: 服务器上没有请求的资源; 500 & Internal Server Error: 服务器执行请求时出现错误; 502 & Bad Gateway: 错误的网关; 503 & Service Unavailable: 服务器超载或正在维护,无法处理请求; 504 & Gateway timeout: 网关超时; React-router原理1.History
内部 // 内部的抽象实现 function createHistory(options={}) { ... return { listenBefore,// 内部的hook机制,可以在location发生变化前执行某些行为,AOP的实现 listen,// location发生改变时触发回调 transitionTo,// 执行location的改变 push,// 改变location replace,go,goBack,goForward,createKey,// 创建location的key,用于唯一标示该location,是随机生成的 createPath,createHref,createLocation,// 创建location } }
function createLocation() { return { pathname,// url的基本路径 search,// 查询字段 hash,// url中的hash值 state,// url对应的state字段 action,// 分为push、replace、pop三种 key // 生成方法为: Math.random().toString(36).substr(2,length) } } 三种方法各自执行
伪代码实现: // createBrowserHistory(HTML5)中的前进实现 function finishTransition(location) { ... const historyState = { key }; ... if (location.action === 'PUSH') ) { window.history.pushState(historyState,null,path); } else { window.history.replaceState(historyState,path) } } // createHashHistory的内部实现 function finishTransition(location) { ... if (location.action === 'PUSH') ) { window.location.hash = path; } else { window.location.replace( window.location.pathname + window.location.search + '#' + path ); } } // createMemoryHistory的内部实现 entries = []; function finishTransition(location) { ... switch (location.action) { case 'PUSH': entries.push(location); break; case 'REPLACE': entries[current] = location; break; } }
什么是原型链每一个对象都会在内部链接到另一个对象(该对象的原型对象),该对象有一个原型 什么是闭包
?
? 图片懒加载与预加载
跨域跨域的方式有很多种,最常用的是 CORS跨域,关键在于服务器,如果服务器实现了CORS跨域的接口,那么就可以使用ajax(请求路径为绝对路径)进行跨域请求。CORS请求分为两种,一种是简单请求,一种是非简单请求。简单请求是指请求方法在
非简单请求请求头: (1)Access-Control-Request-Method 该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法 (2)Access-Control-Request-Headers 该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段 执行简单请求的时候,浏览器会在请求头信息增加 (1)Access-Control-Allow-Origin 该字段是必须的。它的值要么是请求时 (2)Access-Control-Allow-Credentials 该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为 (3)Access-Control-Expose-Headers 该字段可选。CORS请求时, (4)Access-Control-Max-Age
(5)Access-Control-Allow-Methods
(6)Access-Control-Allow-Headers
其他方法: 函数节流和函数防抖函数节流让指函数有规律的进行调用,应用场景:window.resize,游戏中子弹发射(1s只能发射一颗子弹)等; 函数防抖让函数在"调用''之后的一段时间后生效,应用场景:输入框(例:在用户停止输入的500ms后再处理用户数据)。 //函数节流 /* * @params {Function} fun 调用函数 * @params {delay} number 延迟时间 */ const throttle = (fun,delay,...rest) => { let last = null; return () => { const now = + new Date(); if (now - last > delay) { fun(rest); last = now; } } } //实例 const throttleExample = throttle(() => console.log(1),1000); //调用 throttleExample(); throttleExample(); throttleExample(); //函数防抖 const debouce = (fun,...rest) => { let timer = null; return () => { clearTimeout(timer); timer = setTimeout(() => { fun(rest); },delay); } } //实例 const debouceExample = debouce(() => console.log(1),1000); //调用 debouceExample(); debouceExample(); debouceExample(); 快速排序
时间复杂度平均情况:O(nlog n) 最快:O(n^{2}) 空间复杂度: O(log n) var quickSort = function(arr) { console.time('2.快速排序耗时'); if (arr.length <= 1) { return arr; } var pivot = arr.splice(0,1)[0]; var left = []; var right = []; for (var i = 0; i < arr.length; i++){ if (arr[i] < pivot) { left.push(arr[i]); } else { right.push(arr[i]); } } console.timeEnd('2.快速排序耗时'); return quickSort(left).concat([pivot],quickSort(right)); }; var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48]; console.log(quickSort(arr));//[2,3,48,50] AMD和CMD的区别AMD 是 RequireJS 在推广过程中对模块定义的规范化产出。
JavaScript内存泄露的原因以及如何去手动释放内存易出现泄露的场景
JavaScript垃圾回收机制
此算法把“对象是否不再需要”简化定义为“对象有没有其他对象引用到它”。如果没有引用指向该对象(零引用),对象将被垃圾回收机制回收。 限制:无法处理循环引用。在下面的例子中,两个对象被创建,并互相引用,形成了一个循环。它们被调用之后不会离开函数作用域,所以它们已经没有用了,可以被回收了。然而,引用计数算法考虑到它们互相都有至少一次引用,所以它们不会被回收。
当变量进入环境时,例如,在函数中声明一个变量,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开环境时,则将其标记为“离开环境”。 垃圾回收器在运行的时候会给存储在内存中的所有变量都加上标记(当然,可以使用任何标记方式)。然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记(闭包)。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后,垃圾回收器完成内存清除工作,销毁那些带标记的值并回收它们所占用的内存空间。 柯里化函数所谓的柯里化函数简单的说就是将本来接受多个参数的函数变为只接受一个参数的函数。柯里化函数的模板和实例如下: var currying = function(fun) { //格式化arguments var args = Array.prototype.slice.call(arguments,_args); }; } var add = currying(function() { var args = Array.prototype.slice.call(arguments); return args.reduce(function(a,b) { return a + b; }); }) add(1,4) /* * 经典面试题 * 函数参数不定回调函数数目不定 * 编写函数实现: * add(1,5)==15 * add(1,2)(3,4)(5)==15 */ function add() { // 第一次执行时,定义一个数组专门用来存储所有的参数 var _args = [].slice.call(arguments); // 在内部声明一个函数,利用闭包的特性保存_args并收集所有的参数值 var adder = function () { var _adder = function() { [].push.apply(_args,[].slice.call(arguments)); return _adder; }; // 利用隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回 _adder.toString = function () { return _args.reduce(function (a,b) { return a + b; }); } return _adder; } return adder.apply(null,_args); } // 输出结果,可自由组合的参数 console.log(add(1,5)); // 15 console.log(add(1,4)(5)); // 15 console.log(add(1)(2)(3)(4)(5)); // 15 Less常用特性
ES6常用特性
react中setState的原理题目: import React from 'react' class App extends React.Component { constructor() { super(); this.state = { value: 0 } } componentDidMount() { this.setState({value: this.state.value + 1}); console.log(this.state.value); this.setState({value: this.state.value + 1}); console.log(this.state.value); this.setState({value: this.state.value + 1}); console.log(this.state.value); setTimeout(() => { this.setState({value: this.state.value + 1}); console.log(this.state.value); this.setState({value: this.state.value + 1}); console.log(this.state.value); },0) } } 答案: 0、0、0、2、3; 分析: 当
源码地址:enqueueUpdate function enqueueUpdate(component) { ensureInjected(); //判断是否处于批量更新模式 if (!batchingStrategy.isBatchingUpdates) { //关键!下面的代码片段是这个方法的源码 batchingStrategy.batchedUpdates(enqueueUpdate,component); return; } //如果处于批量更新模式,则将这个组件保存在dirtyComponents dirtyComponents.push(component); } 源码地址:ReactDefaultBatchingStrategy //batchingStrategy对象 var ReactDefaultBatchingStrategy = { //注意默认为false isBatchingUpdates: false,batchedUpdates: function(callback,a,b,c,d,e) { var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates; ReactDefaultBatchingStrategy.isBatchingUpdates = true; if (alreadyBatchingUpdates) { callback(a,e); } else { //关键!!!事务的理解 transaction.perform(callback,e); } },}; 源码地址:Transaction
如图:事务会将所需要执行的方法(图中的anyMethod)使用 var Transaction = require('./Transaction'); // 我们自己定义的 var MyTransaction = function() { //do something }; Object.assign(MyTransaction.prototype,Transaction.Mixin,{ //需要自定义一个getTransactionWrappers对象,获取所有需要封装的initialize方法和close方法 getTransactionWrappers: function() { return [{ initialize: function() { console.log('before method perform'); },close: function() { console.log('after method perform'); } }]; }; }); //实例化一个transaction var transaction = new MyTransaction(); //需要调用的方法 var testMethod = function() { console.log('test'); } transaction.perform(testMethod); //before method perform //test //after method perform 理解题目的关键是,整个组件渲染到DOM中的过程就已经处于一次大的事务中了,因此在 XSS与CSRF介绍XSS是一种跨站脚本攻击,是属于代码注入的一种,攻击者通过将代码注入网页中,其他用户看到会受到影响(代码内容有请求外部服务器); CSRF是一种跨站请求伪造,冒充用户发起请求,完成一些违背用户请求的行为(删帖,改密码,发邮件,发帖等) 防御方法举例:
后记时隔三个月,终于迎来了博文的更新,有看到博友在评论留言: (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |