您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > javascript

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

时间:2020-03-09 11:16:19  来源:  作者:

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

 

虽然 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); // true
const obj = {};
const arr = [];
obj instanceof Object; // true
arr instanceof Object; // true
arr instanceof Array; // true
const str = "abc";
const str2 = new String("abc");
str instanceof String; // false
str2 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(/[objects(.+)]/, ''$1')                              
           .toLowerCase()      
  return dataType
}

使用方法如下:

type("a"); // string
type(1); // number
type(window); // window
type(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}
5 个提升你 JavaScript 编码水平的实例

 

我们可以看上面的摇杆效果,这里就是利用了offset()去做位置判断。具体实现代码可以看:https://codepen.io/krischan77/pen/zYxPNPy

Fade 特效

// Fade in
var 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 out
var 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);

文章来源:陈大鱼头

小节

今天的内容就和大家分享到这里,感谢你的阅读。如果你喜欢我的分享,麻烦给个关注、点赞加转发哦,你的支持,就是我分享的动力,后续会持续分享代码片段,欢迎持续关注。



Tags: JavaScript   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
千呼万唤的全球2020的JS报告终于出来了。 我们来看看这一个糟糕却又不平凡的一年,JS发生了什么样的变化。 尽管2020年很糟糕,但 JavaScript 作为一个整体仍然设法向前发展。随...【详细内容】
2021-01-14  Tags: JavaScript  点击:(248)  评论:(0)  加入收藏
逻辑赋值是对现有数学和二进制逻辑运算符的扩展。我们先复习一下,然后看看把它们结合在一起能得到什么。首先,我们来看下 JS 中条件运算符与无条件运算符之间的区别 。无条件...【详细内容】
2020-10-15  Tags: JavaScript  点击:(80)  评论:(0)  加入收藏
在 JavaScript 中使用循环时,需要理解两个关键点:可枚举的属性和可迭代的对象。可枚举的属性可枚举对象的一个定义特征是,当通过赋值操作符向对象分配属性时,我们将内部 enumera...【详细内容】
2020-09-22  Tags: JavaScript  点击:(79)  评论:(0)  加入收藏
作者:ConardLi转发链接:https://mp.weixin.qq.com/s/emJ_LjG7FNR81cxl8BnrMA前言分析你网页中的 JavaScript Bundles 大小,并限制网页中的 JavaScript 数量,可以减少浏览器花费...【详细内容】
2020-08-24  Tags: JavaScript  点击:(84)  评论:(0)  加入收藏
今年年初,我终于决定将自己的网站从基于 PHP 的 CMS 移植到基于 JavaScript 的静态网站生成器(SSG)了。原因如下: 虽然一开始我是“全栈”开发人员,但现在我只负责前端工作:如果我...【详细内容】
2020-07-29  Tags: JavaScript  点击:(62)  评论:(0)  加入收藏
这篇文章列举了一些技巧,可帮助你写出更好的 JavaScript 代码,从而提高性能。...【详细内容】
2020-07-21  Tags: JavaScript  点击:(50)  评论:(0)  加入收藏
在我们开发的许多应用程序都会用到某种日期功能,无论是内容的创建日期还是活动的时间戳等等。处理日期和时间戳格式可能会很麻烦。在本文中,我们将一起学习如何在 JavaScript...【详细内容】
2020-07-18  Tags: JavaScript  点击:(67)  评论:(0)  加入收藏
众所周知,JavaScript 一直在快速变化。在新的 ES2020 中,有很多很棒的特性,我们大都已经迫不及待尝试了。老实说,有时我们可以用不同角度来编写代码,同样也能达到相同的效果,而且...【详细内容】
2020-07-03  Tags: JavaScript  点击:(40)  评论:(0)  加入收藏
在 JS 没有提供一种简便的方法来替换所有指定字符。 在 Java 中有一个 replaceAll() ,replaceAll(String regex, String replacement))方法使用给定的参数 replacement 替换...【详细内容】
2020-06-24  Tags: JavaScript  点击:(38)  评论:(0)  加入收藏
Javascript 的很多扩展的特性是的它变得更加的犀利, 同时也给予程序员机会创建更漂亮并且更让用户喜欢的网站。 尽管很多的开发人员都乐于颂扬 javascript,但是仍旧有人看到它...【详细内容】
2020-06-17  Tags: JavaScript  点击:(45)  评论:(0)  加入收藏
▌简易百科推荐
1、通过条件判断给变量赋值布尔值的正确姿势// badif (a === &#39;a&#39;) { b = true} else { b = false}// goodb = a === &#39;a&#39;2、在if中判断数组长度不为零...【详细内容】
2021-12-24  Mason程    Tags:JavaScript   点击:(6)  评论:(0)  加入收藏
给新手朋友分享我收藏的前端必备javascript已经写好的封装好的方法函数,直接可用。方法函数总计:41个;以下给大家介绍有35个,需要整体文档的朋友私信我,1、输入一个值,将其返回数...【详细内容】
2021-12-15  未来讲IT    Tags:JavaScript   点击:(20)  评论:(0)  加入收藏
1. 检测一个对象是不是纯对象,检测数据类型// 检测数据类型的方法封装(function () { var getProto = Object.getPrototypeOf; // 获取实列的原型对象。 var class2type =...【详细内容】
2021-12-08  前端明明    Tags:js   点击:(23)  评论:(0)  加入收藏
作者:一川来源:前端万有引力 1 写在前面Javascript中的apply、call、bind方法是前端代码开发中相当重要的概念,并且与this的指向密切相关。本篇文章我们将深入探讨这个关键词的...【详细内容】
2021-12-06  Nodejs开发    Tags:Javascript   点击:(19)  评论:(0)  加入收藏
概述DOM全称Document Object Model,即文档对象模型。是HTML和XML文档的编程接口,DOM将文档(HTML或XML)描绘成一个多节点构成的结构。使用JavaScript可以改变文档的结构、样式和...【详细内容】
2021-11-16  海人为记    Tags:DOM模型   点击:(35)  评论:(0)  加入收藏
入口函数 /*js加载完成事件*/ window.onload=function(){ console.log("页面和资源完全加载完毕"); } /*jQuery的ready函数*/ $(document).ready(function(){ co...【详细内容】
2021-11-12  codercyh的开发日记    Tags:jQuery   点击:(36)  评论:(0)  加入收藏
一、判断是否IE浏览器(支持判断IE11与edge)function IEVersion() {var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串var isIE = userAgent.indexOf("comp...【详细内容】
2021-11-02  V面包V    Tags:Javascript   点击:(40)  评论:(0)  加入收藏
Null、Undefined、空检查普通写法: if (username1 !== null || username1 !== undefined || username1 !== &#39;&#39;) { let username = username1; }优化后...【详细内容】
2021-10-28  前端掘金    Tags:JavaScript   点击:(51)  评论:(0)  加入收藏
今天我们将尝试下花 1 分钟的时间简单地了解下什么是 JS 代理对象(proxies)?我们可以这样理解,JS 代理就相当于在对象的外层加了一层拦截,在拦截方法里我们可以自定义一些个性化...【详细内容】
2021-10-18  前端达人    Tags:JS   点击:(51)  评论:(0)  加入收藏
带有多个条件的 if 语句把多个值放在一个数组中,然后调用数组的 includes 方法。// bad if (x === "abc" || x === "def" || x === "ghi" || x === "jkl") { //logic } // be...【详细内容】
2021-09-27  羲和时代    Tags:JS   点击:(58)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条