1、Flex布局,实现两个子元素垂直,并一个靠右一个靠左 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <body > <div class ="parent" > <div class ="left" > 左子垂直分布</div > <div class ="right" > 右子垂直分布</div > </div > </body > <style > .parent { display: flex; align-items: center; justify-content: space-between; height :400px ; border :1px black solid ; }.left { width :100px ; height :150px ; border :1px red solid ; }.right { width :100px ; height :150px ; border :1px green solid ; }
触类旁通,来练习一手经典居中,实现了其中的四种,剩下的等我有空继续补上,先睡觉惹!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > </head > <body > <div class ="initial" > <div class ="center4" > </div > <div class ="center2" > </div > <div class ="center1" > </div > <div class ="center3" > </div > </div > </body > <style > .parent { display: flex; align-items: center; justify-content: space-between; height: 400px; border: 1px black solid; } .parentCenter1 { display: flex; align-items: center; justify-content: center; height: 400px; border: 1px black solid; } .initial { position: absolute; width: 400px; height: 400px; border: 1px black solid; } .left { width: 100px; height: 150px; border: 1px red solid; } .right { width: 100px; height: 150px; border: 1px green solid; } .center1 { position: relative; margin: -75px auto; top: 50%; height: 150px; border: 1px green solid; width: 100px; } .center2 { opacity: 0.5; position: absolute; height: 200px; width: 200px; background-color: brown; top: 50%; left: 50%; margin: -100px 0 0 -100px; } .center3 { opacity: 0.3; position: absolute; width: 25%; height: 25%; background : #000 ; margin: auto; top: 0; left: 0; bottom: 0; right: 0; } .center4 { opacity: 0.9; position: absolute; top :50 %; left :50 %; height :30 %; width :30 %; transform :translate(-50 %,-50 %); background-color :blueviolet ; }</style > </html >
参考链接:https://www.cnblogs.com/mokeycode/p/10635912.html
2、链表的倒数第K个元素删除 看到一个笔试题,返回链表的倒数第K个元素。那么随便搭建一个链表吧。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 class Node { constructor (element ) { this .element = element; this .next = null ; } element = null ; next = null ; }class LinkedList { constructor (elements = [] ) { this .head = null ; this .size = elements.length; for (let _ of elements) { this .Insert(_); } } head = null ; size = 0 ; Insert (newElement ) { if (!this .head) this .head = new Node(newElement); else { var newNode = new Node(newElement); var currNode = this .Findtail(); currNode.next = newNode; } this .size++; }; Findtail (curHead = this .head ) { if (!curHead) throw "Error: empty tail" ; if (curHead.next) return this .Findtail(curHead.next); else return curHead; } Display ( ) { if (!this .head) return ; let curhead = this .head; let message = curhead.element; while (curhead.next) { message += "->" + curhead.next.element curhead = curhead.next; } console .log(message) } IsEmpty ( ) { if (this .head) return false ; else return true ; } Size ( ) { return this .size } Delete (index ) { let pre = this .Find(index); let cur = pre.next; pre.next = cur.next; } Find (index ) { if (index > this .size) throw "the index lager than the size" let curHead = this .head; while (index-- && curHead.next) { curHead = curHead.next; } return curHead; } }function deleteK (List,k ) { let cur = List.head; let index = 0 ; let K_ele = List.Find(k); while (K_ele.next){ K_ele = K_ele.next; cur = cur.next; index++; } List.Delete(index); }let list = new LinkedList([1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 ]); deleteK(list,2 ); list.Display();
3、宽度自适应的搜索框 1 2 3 4 5 6 7 8 9 10 11 12 13 css: form { display: flex; align-items: stretch; } input { flex-grow: 1; } html: <form action ="#" > <input type ="text" placeholder ="Enter your email" > </form >
4、快速排序 怎么说手写算法都得来,那咱们来练两道算法题,先练个快排,经典操作要娴熟
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 function quickSort (arr, i, j ) { if (i < j) { let left = i; let right = j; let pivot = arr[left]; while (i < j) { while (arr[j] >= pivot && i < j) { j--; } if (i < j){ arr[i++] = arr[j]; } while (arr[i] <= pivot && i < j) { i++; } if (i < j) { arr[j--] = arr[i]; } } arr[i] = pivot; quickSort(arr, left, i - 1 ); quickSort(arr, i + 1 , right); return arr; } }
居然写错了两次才改过来,看来手写真的很有必要,不要纸上谈兵了(此处骂自己)。
第一次采用c++的习惯思路写错, 改过来了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 function quickSort (arr, i, j ) { if (i < j) { let left = i; let right = j; let pivot = arr[left]; while (i < j) { while (arr[j] >= pivot && i < j) { j--; } while (arr[i] <= pivot && i < j) { i++; } if (i<j){ let temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } let temp = arr[left]; arr[left] = arr[i]; arr[i] = temp; quickSort(arr, left, i - 1 ); quickSort(arr, i + 1 , right); return arr; } }var arr = [5 ,6 ,36 ,23 ,6 ,23 ,64 ,5 ,7 ,0 ,2 ,6 ,24 ]console .log(quickSort(arr,0 ,arr.length-1 ))
但是我搞明白后,更倾向于第一种方法,不许要借助额外空间,好像交换次数也少了一半。
5、防抖和节流 这也是前端面试过程中的高频问题。今天也切实的落实一遍,很基础,要会。在前端的查询请求的过程中,防抖的场景:就比如我们是在刷空间这样,他下面刷到底了,但是要加载下一页的时候,这时候用户因为网络啊一些问题,可能会下拉两次,那么在加载页面的时候,跳了很多页面就显得不合适,就需要使用防抖功能,在一段时间内,只执行一次操作。再次操作就重置时间计时。
节流操作的应用场景:就是类似百度的实时查询,当你在查询框里输入一个字,马上就会有一些东西弹出来了。但是用户有时候在打第一个字和第二个字之间,也打进去很多字符,但是对于这个查询的操作是没有意义的。这时候就没必要每次输入都请求服务器。这样会对给服务器较大的压力。因此这时候,就需要节流,来保证在一定时间内事件发生,只会响应一次。同时在实现的时候,移动端尽量去使用事件戳来做,设立定时器,对于性能的影响很大。
下面是手写的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > 防抖和节流</title > <style > .content { height :200px ; width :200px ; border :1px blue solid ; } </style > </head > <body > <div id ="content" class ="content" > </div > </body > </html > <script > let num = 1 ; let content = document .getElementById("content" ); function count ( ) { content.innerHTML = num++; } content.onmousemove = throttle(count,1000); function debounce (func,wait ) { let timeout; return function ( ) { if (timeout) clearTimeout (timeout); timeout = setTimeout (function ( ) { func.apply(this ); },wait) } } function debounce2 (func,wait ) { let timeout; return function ( ) { if (timeout) clearTimeout (timeout); let callNow = !timeout; timeout = setTimeout (()=> { timeout = null ; },wait); if (callNow) func.apply(this ); } } function throttle (func,wait ) { let timeout; return function ( ) { if (!timeout){ timeout = setTimeout (()=> { timeout = null ; func.apply(this ); },wait) } } } function throttle2 (func,wait ) { let prev = 0 ; return function ( ) { let now = Date .now(); if (now - prev > wait){ func.apply(this ) prev = now; } } }</Script >
6、并发控制 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 let mapLimit = (list, limit, asyncHandle ) => { let recursion = (arr ) => { return asyncHandle(arr.shift()) .then(()=> { if (arr.length!==0 ) return recursion(arr) else return 'finish' ; }) }; let listCopy = [].concat(list); let asyncList = []; while (limit--) { asyncList.push( recursion(listCopy) ); } return Promise .all(asyncList); }var dataLists = [1 ,2 ,3888 ,4 ,5 ,6 ,7 ,8 ,9 ,11 ,100 ,123 ];var count = 0 ; mapLimit(dataLists, 3 , (curItem )=> { return new Promise (resolve => { count++ setTimeout (()=> { console .log(curItem, '当前并发量:' , count--) resolve(); }, Math .random() * 5000 ) }); }).then(response => { console .log('finish' , response) })
7、一个长页面如何懒加载,加视窗位置的确定 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 <!DOCTYPE html> <html> <head> <meta charset="UTF-8" > <title>Document</title> <style> img { display: block; margin-bottom: 50px; width: 400px; height: 400px; } </style> </head> <body> <img src="" data-src="http://ww4.sinaimg.cn/large/006y8mN6gw1fa5obmqrmvj305k05k3yh.jpg" alt="" > </body> <script> var num = document .getElementsByTagName('img' ).length; var img = document .getElementsByTagName("img" ); var n = 0 ; lazyload(); function lazyload ( ) { var seeHeight = document .documentElement.clientHeight; var scrollTop = document .documentElement.scrollTop || document .body.scrollTop; for (var i = n; i < num; i++) { if (img[i].offsetTop < seeHeight + scrollTop) { if (img[i].getAttribute("src" ) == "" ) { img[i].src = img[i].getAttribute("data-src" ); } n = i + 1 ; } } } function throttle (fun, delay, time ) { var timeout, startTime = new Date (); return function ( ) { var context = this , args = arguments , curTime = new Date (); clearTimeout (timeout); if (curTime - startTime >= time) { fun.apply(context, args); startTime = curTime; } else { timeout = setTimeout (function ( ) { fun.apply(context, args); }, delay); } }; };window .addEventListener('scroll' ,throttle(lazyload,500 ,1000 )); </script> </html>
8、设计通用组件要考虑哪些问题
细粒度考量
我们在学习设计模式的时候会遇到很多种设计原则,其中一个设计原则就是单一职责原则 ,在组件库的开发中同样适用,我们原则上一个组件只专注一件事情,单一职责的组件的好处很明显,由于职责单一就可以最大可能性地复用组件,但是这也带来一个问题,过度单一职责的组件也可能会导致过度抽象,造成组件库的碎片化。
举个例子,一个自动完成组件(AutoComplete),他其实是由 Input 组件和 Select 组件组合而成的,因此我们完全可以复用之前的相关组件,就比如 Antd 的AutoComplete组件中就复用了Select组件,同时Calendar、 Form 等等一系列组件都复用了 Select 组件,那么Select 的细粒度就是合适的,因为 Select 保持的这种细粒度很容易被复用.
组件通用性考量 组件设计之初是为了当时的页面设计进行封装设计的,那么之后的页面设计极大可能是与之前不同的,那么之前设计的组件就不能用了。
而一旦发生这样的情况,就说明我们之前所设计的组件是不通用的,需要重新设计了。就像Antd组件库那样,预留了dropdownRender进行组件渲染。
通用性的设计就代表着将放弃对DOM的操作权,暴露给开发者进行操作,组件开发者本身只负责底层逻辑和基本的DOM结构。这也是开发通用型组件的秘诀之一。
9、手写一个new方法 你都应该大概知道了new过程中会新建对象 ,此对象会继承构造器的原型与原型上的属性 ,最后它会被作为实例返回 这样一个过程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 let Parent = function (name, age ) { this .name = name; this .age = age; }; Parent.prototype.sayName = function ( ) { console .log(this .name); };let newMethod = function (Parent, ...rest ) { let child = Object .create(Parent.prototype); let result = Parent.apply(child, rest); return typeof result === 'object' ? result : child; };const child = newMethod(Parent, 'echo' , 26 ); child.sayName() child instanceof Parent child.hasOwnProperty('name' ) child.hasOwnProperty('age' ) child.hasOwnProperty('sayName' )
10、闭包实现累加、柯里化实现累加 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 function add (x ) { var sum = x; var tmp = function (y ) { if (!y) return tmp; else { sum = sum + y; return tmp; } }; tmp.toString = function ( ) { return sum; }; return tmp; }console .log(add(1 )(2 )(3 )()); console .log(add(1 )(2 )(3 )(4 )); console .log(add(1 )(2 )(3 )(4 )(5 ));console .log(add(1 )(2 )(3 )(4 )(5 )(6 ));function add ( ) { var args = Array .prototype.slice.call(arguments ); var fn = function ( ) { args.push(...arguments) return fn; } fn.toString = function ( ) { return args.reduce(function (a, b ) { return a + b; }) } return fn; } console .log(add(1 ,2 )) console .log(add(1 )(2 )) console .log(add(1 )(2 )(3 )) console .log(add(1 ,2 ,3 )(4 ))
11、画圆、画三角、画半圆、画圆角、0.5px边框 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 .div1 { //三角形 width : 0; height : 0; border-top :40px solid transparent ; border-left :40px solid transparent ; border-right :40px solid transparent ; border-bottom :40px solid #ff0000 ; } .div2{ //圆形 width :40px ; height :40px ; background-color : red ; border-radius : 50%; } .div3{ //圆角 width :40px ; height : 40px ; background-color : green ; border-radius : 10px ; } .div4{ //半圆 width :40px ; height :20px ; background-color :red ; border-radius :20px 20px 0 0;//左上、右上、右下、左下 } .border { //0.5px单边框 width : 200px ; height : 200px ; margin : 0 auto ; border-bottom : 1px solid transparent ; border-image : linear-gradient (to bottom ,transparent 50%, red 50%) 0 0 100%/1px 0; } .border { //四边0.5px width : 200px ; height : 200px ; margin : 0 auto ; position : relative ; } .border ::before { content : " " ; position : absolute; top : 0 ; left : 0 ; width : 200% ; height : 200% ; border : 1px solid red; transform-origin : 0 0 ; transform : scale (0.5 ); }
12、文件树的数据结构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class FileTree { rmEmpty: Boolean = false fileCount = 0 folderCount = 0 filesCount = 0 foldersCount = 0 allCount = 0 files = [] folders = [] Traverse (folder1 : any, dir = '' ) }
13、深拷贝 1 2 3 4 5 6 7 8 9 10 11 12 13 14 function deepCopy (source ) { if (!(typeof obj === 'object' && obj !== null )) return source; let target = Array .isArray(source)?[]:{} for (var k in source){ if (source.hasOwnProperty(k)){ if (typeof source[k] === 'object' ) target[k] = deepCopy(source[k]) }else { target[k] = source[k]; } } return target; }
14、setTimeout实现setInterval 1 2 3 4 5 6 7 8 9 10 11 12 function setInterval (func, t ) { var inter = function ( ) { setTimeout (inter,t); try { func.call(null ); } catch (e){ throw e.toString(); } } setTimeout (inter,t); };
15、手撕bind、call、apply 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 function myBind2 (context, ...args1 ) { var self = this ; var Fn = function (...args2 ) { return self.apply(this instanceof context ? this : context, args1.concat(args2)) } var Fmiddle = function ( ) { }; Fmiddle.prototype = this .prototype; Fn.prototype = new Fmiddle(); return Fn; }Function .prototype._call = function (obj ) { var _obj = obj ? Object (obj) : window _obj.fn = this var argArr = Array .from(arguments ).slice(1 ) _obj.fn(...argArr) delete _obj.fn }Function .prototype._apply = function (obj, argArr ) { var _obj = obj ? obj : window _obj.fn = this var arg = [] if (!argArr || argArr.length == 0 ) { _obj.fn() } else { for (var i = 0 ; i < argArr.length; i++) { arg.push('argArr[' + i + ']' ) } eval ("_obj.fn(" + arg + ")" ) } delete _obj.fn }
16、Common.js和es6 module 产生模块化
的原因:js很难编写大型项目,由于全局变量的污染和难以管理的依赖关系,这些问题导致了JS无法进行精细的模块划分,因为精细的模块化划分会导致更多的全局污染以及更加复杂的依赖关系;
Common.js模板化
目前只有node环境才支持CommonJs模板化标准,要使用CommonJs,必须安装node
node遵循EcmaScript标准,但是由于脱离了浏览器环境,因此:无法使用浏览器的dom对象、window对象、document对象
如果一个模板需要暴露一些数据或者功能供其他模板使用,需要使用代码module.expots = xxx
如果一个模块需要使用另一个模块导出的内容,需要使用require(‘模块路径’)
路径必须以./或者../开头
require函数返回的内容是模块导出的内容
模块中所有全局代码产生的变量、函数均不会对全局造成任何污染,仅在模块内使用。
模块具有缓存,第一次导入模块时会缓存模块的导出,之后再导入同一个模块,直接使用之前的缓存结果。
ES6模板化
基本导出可以有多个,默认导出只能有一个
基本导出必须要有名字,默认导出由于有特殊名字,所以可以不用写名字。
ES6 module采用的依赖预加载模式,所有模块导入代码均会提升到代码顶部
不能将导入代码放置到判断,循环中
导入的内容放置到常量中,不可更改
ES6 module使用了缓存,保证每个模块仅加载一次
17、实现一个实时搜索框 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 <template> <div> <input type="text" id="ss" placeholder="搜索" v-model="search" v-on:input="request" /> <button @click="btn" >搜索</button> <br /> <input v-model="result" /> </div> </template> <script>import axios from "axios" ;export default { name: "HelloWorld" , props: { msg: String , }, data ( ) { return { search : "" , result : "搜索结果:" }; }, methods: { request: function request ( ) { this .$watch( "search" , throttle(() => { var CancelToken = axios.CancelToken; var source = CancelToken.source(); if (typeof source === 'function' ) source.cancel('取消请求' ) axios .get("http://localhost:91" , { CancelToken: source.token }) .then((res ) => this .result = "查询的结果:" + res.data) .catch((err ) => { if (axios.isCancel(err)) { console .log("request canceled" , err.message); } else { console .log(err); } }); }, 3000 ) ) }, }, };function throttle (func, delay ) { let timeout; return function (...args ) { if (!timeout){ timeout = setTimeout (()=> { timeout = null ; func.apply(this ,args); },delay) } } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> </style>