当前位置: 首页 > Web前端 > HTML5

5个提升你JavaScript编码水平的例子

时间:2023-04-05 01:28:25 HTML5

虽然在2020年的今天,各种前端框架和工具层出不穷,这些框架和工具已经帮我们提前解决了很多棘手的问题,但是工具始终是工具,扎实的基础功是核心,现在让我们通过几个实际的代码片段来提升我们的原生JS编码水平。在这里,小编建了一个前端学习交流按钮群:132667127,自己整理的最新前端资料和进阶开发教程。有需要的可以进群学习,交流,判断数据类型。首先提一个问题:typeof的类型能不能正确判断?答案是:不会,因为历史原因,判断基本类型时typeofnull会等于object。而对于对象来说,除了函数之外,都会被转化为object。例子如下:typeof1;//'number'typeof"1";//'string'typeofnull;//类型[];//'对象'typeof{};//'object'typeofwindow.alert;//'function'再问一个问题,instanceof能正确判断类型吗?答案是:仍然没有。instanceof虽然是通过原型链来判断的,但是对于object来说,Array也会被转化为Object,无法区分基本类型string和boolean。例如:functionFunc(){}constfunc=newFunc();console.log(funcinstanceofFunc);//trueconstobj={};constarr=[];obj对象实例;//truearrinstanceof对象;//truearrinstanceofArray;//trueconststr="abc";conststr2=newString("abc");strinstanceofString;//falsestr2instanceofString;//真的那么怎么办?这时候我们可以使用:Object.prototype.toString.call()那为什么呢?因为每个对象都有一个toString()方法,当对象要表示为文本值或以需要字符串的方式引用时会自动调用该方法。默认情况下,从Object派生的每个对象都继承toString()方法。如果此方法未在自定义对象中重写,则toString()返回[Objecttype],其中type是对象类型。于是就有了下面的例子:Object.prototype.toString.call(newDate());//[对象日期]Object.prototype.toString.call("1");//[对象字符串]Object.prototype.toString.call(1);//[objectNumer]Object.prototype.toString.call(undefined);//[对象未定义]Object.prototype.toString.call(null);//[objectNull]所以上面的知识是综合点,我们可以封装如下通用的类型判断方法:vartype=function(data){vartoString=Object.prototype.toString;vardataType=datainstanceof元素?'element'//为了统一DOM节点类型output:toString.call(data).replace(/\[object\s(.+)\]/,''$1').toLowerCase()returndataType}用法如下:type("a");//字符串类型(1);//数字类型(窗口);//窗口类型(document.querySelector("h1"));//元素通用数组/类数组对象封装如果我们使用ES5/ES6+的数组API,很容易进行数组的各种循环操作,但是如果我们要循环一个类数组对象怎么办?例如节点列表。直接循环会报错:document.querySelectorAll("div").map(e=>e);//未捕获的类型错误:document.querySelectorAll(...).map不是一个函数如果我们不使用展开运算符呢?那么我们就可以利用call的特性,将NodeList中的元素一个一个插入到数组中。例子如下:varlistMap=function(array,type,fn){return!fn?array:Array.prototype[type]["call"](array,fn);};使用如下:vardivs=document.querySelectorAll("div");listMap(divs,"forEach",function(e){console.log(e);});获取dom元素节点的偏移量。如果用过jQuery的童鞋一定不会忘记$('').offset()api的强大功能。这个api可以轻松获取元素的偏移量。如果我们没有jQuery怎么办?我们先来看例子:varscrollLeft=el.getBoundingClientRect().left+document.body.scrollLeft+document.documentElement.scrollLeft;返回{顶部:scrollTop,左侧:scrollLeft};};首先,让我们看一下getBoundingClientRect()方法。getBoundingClientRect()方法返回元素的大小及其相对于视口的位置。返回值是一个DOMRect对象,它是与元素关联的CSS边框的集合。那么document.body.scrollTop和document.documentElement.scrollTop是两个函数,但是一个在不同的浏览器下永远是0,所以做了上面的兼容处理。所以我们在做拖拽功能的时候,可以依赖上面的属性。使用方法如下:varel=document.querySelector(".moveBox");getOffset(el);//{top:xxx,left:xxx}我们可以看到上面的摇杆效果,这里是使用offset()来进行位置判断。具体实现代码可见:https://codepen.io/krischan77...Fade特效//FadeinvarfadeIn=function(el){el.style.opacity=0varlast=+newDate()vartick=function(){el.style.opacity=+el.style.opacity+(newDate()-last)/400last=+newDate()if(+el.style.opacity<1){requestAnimationFrame(tick))}}tick()}//淡出varfadeOut=function(el){el.style.opacity=1varlast=+newDate()vartick=function(){el.style.opacity=+el.风格。opacity-(newDate()-last)/400last=+newDate()if(+el.style.opacity>0){requestAnimationFrame(tick)}}tick()}以上就是淡入的具体实现以及淡出效果,这里是使用requestAnimationFrame递归修改opacity。其实这里需要提一个概念,就是时间分片。这是一个非常重要的概念。比如React的Fiber核心实现就是时间分片。它将一个长任务分成一个包含若干个小任务的任务队列,然后一个一个执行。requestAnimationFrame就是这样一个API。可以根据系统决定回调函数的执行时机。其实就是在下次重绘之前更新动画帧。由于这种机制,可以防止帧丢失。使用队列的概念进行数据操作队列(queue)是一个先进先出(FIFO,First-In-First-Out)的线性表。在具体应用中,通常用链表或数组来实现。队列只允许在后端(称为rear)插入和在前端(称为front)删除。虽然很多人认为了解数据结构对前端影响不大,但是如果我们了解了一些基本概念,是不是可以在编码的时候更加开阔思路呢?我们看下面两个例子:获取父节点下节点的坐标。如果我们要操作原生DOM,我们绕不开获取父节点节点下标的功能,那么如何实现呢?当然,我们使用我们的循环来遍历子元素集合,直到确定下标。代码如下:varindex=function(el){if(!el){return-1;}变种我=0;while((el=el.previousElementSibling)){i++;}返回我;};清空子节点如果我们想清除DOM节点的子节点,我们有以下方法:}};以上只是一个思路,el.innerHTML=''会更简洁。使用reduce优化数据数组去重没错,又是一个常见的问题,数组去重,但是我们这次去除的不是单条数据,而是键值相同的对象集合。例如,在下面的示例中,我们有以下数据:Awesomereducedatadeduplication首先,让我们来看一个老掉牙的问题。假设有这样一个对象:constdata=[{name:"Kris",age:"24"},{name:"Andy",age:"25"},{name:"Kitty",age:"25"},{name:"Andy",age:"25"},{name:"Kitty",age:"25"},{name:"Andy",age:"25"},{name:“小猫”,年龄:“25”}];现在我们要重新加载里面重名的对象,这时候就可以使用reduce了,例子如下:constdataReducer=(prev,cur,idx)=>{letobj={};const{名称}=当前;obj[名称]=当前;return{...prev,...obj};};constreducedData=data.reduce(dataReducer,{});让newData=Object.values(reducedData);批量生成对象元素在鱼头的实际业务中,有一个操作需要类似于对以下对象进行操作:{a1:'data',a2:'data',...,an:'data'}像我这样的懒鱼肯定不会手写一个一个的,于是就有了下面这个方法constcreateList=(item,idx)=>{letobj={};obj[`a${idx}`]="数据";返回对象;};constlistReducer=(acc,cur)=>(!acc?{...cur}:{...cur,...acc});constobj=Array.from(newArray(20),createList).reduce(listReducer);今天的内容我就分享到这里,谢谢大家如果喜欢我的分享,请给我一个关注,点赞转发。您的支持是我分享的动力。以后我会继续分享代码片段。欢迎继续关注。