编辑:[db:作者] 时间:2024-08-25 06:52:41
虽然 2020 的本日,各种前端框架、工具林立,而这些框架跟工具也帮我们提前办理了不少麻烦的问题,但是工具始终是工具,踏实的基本功才是最核心的,现在一起来通过几个实际的代码片段来提高我们原生 JS 的编码水平。
判断数据类型首先来提问一个:typeof是否能精确判断类型?
答案是:不可以,由于由于历史缘故原由,在判断原始类型时,typeof null会即是object。而且对付工具来说,除了函数,都会转换成object。例子如下:
typeof 1; // 'number'typeof "1"; // 'string'typeof null; //typeof []; // 'object'typeof {}; // 'object'typeof window.alert; // 'function'
再来提问一个,instanceof是否能精确判断类型?
答案是:还是不可以,虽然instanceof是通过原型链来判断的,但是对付工具来说,Array也会被转换成Object,而且也不能区分基本类型string和boolean。例如:
function Func() {}const func = new Func();console.log(func instanceof Func); // trueconst obj = {};const arr = [];obj instanceof Object; // truearr instanceof Object; // truearr instanceof Array; // trueconst str = "abc";const str2 = new String("abc");str instanceof String; // falsestr2 instanceof String; // true
以是该怎么办呢?
这时候我们可以利用:Object.prototype.toString.call()
所以为什么?
由于每个工具都有一个toString()方法,当要将工具表示为文本值或以预期字符串的办法引用工具时,会自动调用该方法。默认情形下,从Object派生的每个工具都会继续toString()方法。如果此方法未在自定义工具中被覆盖,则toString()返回[Object type],个中type是工具类型。以是就有以下例子:
Object.prototype.toString.call(new Date()); // [object Date]Object.prototype.toString.call("1"); // [object String]Object.prototype.toString.call(1); // [object Numer]Object.prototype.toString.call(undefined); // [object Undefined]Object.prototype.toString.call(null); // [object Null]
以是综合上述知识点,我们可以封装出以下通用类型判断方法:
var type = function(data) { var toString = Object.prototype.toString; var dataType = data instanceof Element ? 'element' // 为了统一DOM节点类型输出 : toString .call(data) .replace(/\[object\s(.+)\]/, ''$1') .toLowerCase() return dataType}
利用方法如下:
type("a"); // stringtype(1); // numbertype(window); // windowtype(document.querySelector("h1")); // element
通用的数组/类数组工具封装
如果我们利用 ES5/ES6+的数组 API,很随意马虎就能够对数组进行各种的循环操作,但是如果我们要循环一个类数组工具呢?
例如NodeList。直接循环是会报错的:
document.querySelectorAll("div").map(e => e); // Uncaught TypeError: document.querySelectorAll(...).map is not a function
当然我们可以用扩展运算符:
[...document.querySelectorAll("div")].map(e => e);
那如果我们不用扩展运算符呢?
那么我们就可以利用call的特性,将NodeList里的元素一个一个的插入到数组中,例子如下:
var listMap = function(array, type, fn) { return !fn ? array : Array.prototype[type]["call"](array, fn);};
利用方法如下:
var divs = document.querySelectorAll("div");listMap(divs, "forEach", function(e) { console.log(e);});
获取 dom 元素节点的偏移量
如果有用过jQuery的童鞋,就一定不会忘却$('').offset()这个 api 的强大功能,这个 api 可以轻易获取元素的偏移量,那么如果我们不用jQuery该怎么实现呢?
我们先来看看例子:
var getOffset = function(el) { var scrollTop = el.getBoundingClientRect().top + document.body.scrollTop + document.documentElement.scrollTop; var scrollLeft = el.getBoundingClientRect().left + document.body.scrollLeft + document.documentElement.scrollLeft; return { top: scrollTop, left: scrollLeft };};
首先我们先来看getBoundingClientRect()这个方法。
getBoundingClientRect()方法返回元素的大小及其相对付视口的位置。返回值是一个 DOMRect 工具,是与该元素干系的 CSS 边框凑集 。
然后便是document.body.scrollTop 跟 document.documentElement.scrollTop这两个是一个功能,只不过在不同的浏览器下会有一个始终为 0,以是做了以上的兼容性处理。以是当我们做拖拽功能的时候,就可以依赖上以上属性。
利用方法如下:
var el = document.querySelector(".moveBox");getOffset(el); // {top: xxx, left: xxx}
我们可以看上面的摇杆效果,这里便是利用了offset()去做位置判断。详细实当代码可以看:https://codepen.io/krischan77/pen/zYxPNPy
Fade 殊效// Fade invar fadeIn = function (el) { el.style.opacity = 0 var last = +new Date() var tick = function() { el.style.opacity = +el.style.opacity + (new Date() - last) / 400 last = +new Date() if (+el.style.opacity < 1) { requestAnimationFrame(tick)) } } tick()}// Fade outvar fadeOut = function (el) { el.style.opacity = 1 var last = +new Date() var tick = function() { el.style.opacity = +el.style.opacity - (new Date() - last) / 400 last = +new Date() if (+el.style.opacity > 0) { requestAnimationFrame(tick) } } tick()}
上述是淡入淡出效果的详细实现,这里是利用requestAnimationFrame对opacity通过递归的办法进行修正。
实在这里须要提一个观点,便是韶光分片。
这是一个非常主要的观点,例如 React 的 Fiber 核心实现便是韶光分片。它会将一个长任务切分成一个含有多少小任务的任务行列步队,然后一个接着一个的实行。
requestAnimationFrame便是这样一个 API,它可以根据系统来决定回调函数的实行机遇,实在也便是不才一次重绘之前更新动画帧,由于有这样的机制,以是能防止丢帧。
利用行列步队的观点进行数据操作行列步队(queue),是前辈先出(FIFO, First-In-First-Out)的线性表。在详细运用中常日用链表或者数组来实现。行列步队只许可在后端(称为 rear)进行插入操作,在前端(称为 front)进行删除操作。
虽然很多人以为理解数据构造对前端浸染不大,但是如果我们懂一些根本的观点,是否在编码时能够更加扩散我们的思维呢?我们看下面两个例子:
获取节点在该父节点下的坐标。如果我们要操作原生 DOM,那么是绕不开获取节点在该父节点的下标的这个功能的,那么我们该如何实现呢?
当然便是利用我们的循环啦,对子元素凑集进行遍历,直到确定下标为止,代码如下:
var index = function(el) { if (!el) { return -1; } var i = 0; while ((el = el.previousElementSibling)) { i++; } return i;};
清空子节点
如果我们要清空某个 DOM 节点的子节点,我们有以下的方法:
var empty = function(el) { while (el.firstChild) { el.removeChild(el.firstChild); }};
上面只是供应一个思路,实在el.innerHTML = ''会更简洁。
利用 reduce 进行数据优化数组去重没错,又是一个旧调重弹的问题,数组去重,但是我们这次去除的不仅仅是单个的数据,而是拥有某个相同键值的工具凑集。例如下面的例子,我们有以下的数据:
牛逼的 reduce数据去重首先我们来看看一个旧调重弹的问题,我们假设有这样的一个工具:
const data = [ { 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: "Kitty", age: "25" }];
现在我们要去重里面name重复的工具,这时候我们可以利用reduce,例子如下:
const dataReducer = (prev, cur, idx) => { let obj = {}; const { name } = cur; obj[name] = cur; return { ...prev, ...obj };};const reducedData = data.reduce(dataReducer, {});let newData = Object.values(reducedData);
批量天生工具元素
在鱼头的实际业务中,有一个操作是须要对类似以下的工具进行操作的:
{ a1: 'data', a2: 'data', ..., an: 'data'}
像我这么
const createList = (item, idx) => { let obj = {}; obj[`a${idx}`] = "data"; return obj;};const listReducer = (acc, cur) => (!acc ? { ...cur } : { ...cur, ...acc });const obj = Array.from(new Array(20), createList).reduce(listReducer);
文章来源:陈大鱼头
小节本日的内容就和大家分享到这里,感谢你的阅读。如果你喜好我的分享,麻烦给个关注、点赞加转发哦,你的支持,便是我分享的动力,后续会持续分享代码片段,欢迎持续关注。
本站所发布的文字与图片素材为非商业目的改编或整理,版权归原作者所有,如侵权或涉及违法,请联系我们删除,如需转载请保留原文地址:http://www.baanla.com/bgl/164800.html
上一篇:解决下场出行收纳 拖行密码箱 不错的密码收纳箱可以拖行
下一篇:返回列表
Copyright 2005-20203 www.baidu.com 版权所有 | 琼ICP备2023011765号-4 | 统计代码
声明:本站所有内容均只可用于学习参考,信息与图片素材来源于互联网,如内容侵权与违规,请与本站联系,将在三个工作日内处理,联系邮箱:123456789@qq.com