JavaScript实用代码小技巧


Posted in Javascript onAugust 23, 2018

在上次的 “Chrome DevTools 你可能不知道的小技巧” 文中,得到很多开发朋友的反馈确实不知道这些小技巧。今天,我们来聊一聊在 EcmaScript5/6+ 中的一些小技巧,欢迎评论区讨论下更多技巧。

JSON.stringify

我们平时经常会用到JSON 对象,比如当我们要实现对象的深拷贝时,我们可以用JSON 对象的JSON.stringify和JSON.parse 来拷贝一个完全一样的对象,而不会对原对象产生任何引用关系。在使用localStorage 时,也会用到它,因为localStorage 只能存储字符串格式的内容,所以,我们在存之前,将数值转换成JSON字符串,取出来用的时候,再转成对象或数组。

对于JSON.stringify 方法,它可以帮我们把一个对象或数组转换成一个JSON字符串。我们通常只会用到它的第一个参数,其实它还有另外两个参数,可以让它实现一些非常好用的功能。

首先来看语法:

JSON.stringify(value[, replacer [, space]])

参数:

  • value:将要被序列化的变量的值
  • replacer:替代器。可以是函数或者是数组,如果是一个函数,则value 每个属性都要经过这个函数的处理,该函数的返回值就是最后被序列化后的值。如果是一个数组,则要求该数组的元素是字符串,且这些元素会被当做value 的键(key)进行匹配,最后序列化的结果,是只包含该数组每个元素为key 的值。
  • space:指定输出数值的代码缩进,美化格式之用,可以是数字或者字符串。如果是数字(最大为10)的话,代表每行代码的缩进是多少个空格。如果是字符串的话,该字符串(最多前十个字符)将作显示在每行代码之前。

这时候,你应该知道了。我们可以用JSON.stringify 来做序列化时的过滤,相当于我们可以自定义JSON.stringify 的解析逻辑。

使用函数过滤并序列化对象:

// 使用“函数”当替代器
function replacer(key, value) {
 if (typeof value === "string") {
 return undefined;
 }
 return value;
}
var foo = {
 foundation: "Mozilla", 
 model: "box", 
 week: 45, 
 transport: "car", 
 month: 7
};
var jsonString = JSON.stringify(foo, replacer);
// {"week":45,"month":7}

使用数组过滤并序列化对象:

// 使用“数组”当替代器
const user = {
 name: 'zollero',
 nick: 'z',
 skills: ['JavaScript', 'CSS', 'HTML5']
};
JSON.stringify(user, ['name', 'skills'], 2);
// "{
// "name": "zollero",
// "skills": [
//  "JavaScript",
//  "CSS",
//  "HTML5"
// ]
// }"

还有一个有意思的东西,是对象的toJSON 属性。

如果一个对象有toJSON 属性,当它被序列化的时候,不会对该对象进行序列化,而是将它的toJSON 方法的返回值进行序列化。

见下面的例子:

var obj = {
 foo: 'foo',
 toJSON: function () {
 return 'bar';
 }
};
JSON.stringify(obj);  // '"bar"'
JSON.stringify({x: obj}); // '{"x":"bar"}'

用 Set 来实现数组去重

在ES6 中,引入了一个新的数据结构类型:Set。而Set 与Array 的结构是很类似的,且Set 和Array 可以相互进行转换。

数组去重,也算是一个比较常见的前端面试题了,方法有很多种,这里不多赘述。下面我们看看用Set 和...(拓展运算符)可以很简单的进行数组去重。

const removeDuplicateItems = arr => [...new Set(arr)];
removeDuplicateItems([42, 'foo', 42, 'foo', true, true]);
//=> [42, "foo", true]

用块级作用域避免命名冲突

在开发的过程中,通常会遇到命名冲突的问题,就是需要根据场景不同来定义不同的值来赋值给同一个变量。下面介绍一个使用ES6 中的块级作用域 来解决这个问题的方法。

比如,在使用switchcase 时,我们可以这样做:

switch (record.type) {
 case 'added': {
 const li = document.createElement('li');
 li.textContent = record.name;
 li.id = record.id;
 fragment.appendChild(li);
 break;
 }
 case 'modified': {
 const li = document.getElementById(record.id);
 li.textContent = record.name;
 break;
 }
}

函数参数值校验

我们知道,在ES6 中,为函数增加了参数默认值的特性,可以为参数设定一些默认值,可以让代码更简洁,可维护。

其实,我们可以通过这个特性来做函数参数值的校验。

首先,函数的参数可以是任意类型的值,也可以是函数,比如下面这个:

function fix(a = getA()) {
 console.log('a', a)
}
function getA() {
 console.log('get a')
 return 2
}
fix(1);
// a 1
fix();
// get a
// a 2

可以看出,如果在调用fix 时传了参数a ,则不会执行函数getA,只有当不传递参数a 时,才会执行函数getA。

这时候,我们可以利用这一特性,为参数a 添加一个必传的校验,代码如下:

function fix(a = require()) {
 console.log('a', a)
}
function require() {
 throw new Error('缺少了参数 a')
}
fix(1);
// a 1
fix();
// Uncaught Error: 缺少了参数 a

用解构赋值过滤对象属性

在前面我们介绍了使用JSON.stringify 来过滤对象的属性的方法。这里,我们介绍另外一种使用ES6 中的解构赋值 和拓展运算符 的特性来过滤属性的方法。

比如,下面这段示例:

// 我们想过滤掉对象 types 中的 inner 和 outer 属性
const { inner, outer, ...restProps } = {
 inner: 'This is inner',
 outer: 'This is outer',
 v1: '1',
 v2: '2',
 v4: '3'
};
console.log(restProps);
// {v1: "1", v2: "2", v4: "3"}

用解构赋值获取嵌套对象的属性

解构赋值 的特性很强大,它可以帮我们从一堆嵌套很深的对象属性中,很方便地拿到我们想要的那一个。比如下面这段代码:

// 通过解构赋值获取嵌套对象的值
const car = {
 model: 'bmw 2018',
 engine: {
  v6: true,
  turbo: true,
  vin: 12345
 }
};
// 这里使用 ES6 中的简单写法,使用 { vin } 替代 { vin: vin }
const modalAndVIN = ({ model, engine: { vin }}) => {
 console.log(`model: ${model}, vin: ${vin}`);
}
modalAndVIN(car);
// "model: bmw 2018, vin: 12345"

合并对象

ES6 中新增的拓展运算符,可以用来解构数组,也可以用来解构对象,它可以将对象中的所有属性展开。

通过这个特性,我们可以做一些对象合并的操作,如下:

// 使用拓展运算符合并对象,在后面的属性会重写前面相同属性的值
const obj1 = { a: 1, b: 2, c: 3 };
const obj2 = { c: 5, d: 9 };
const merged = { ...obj1, ...obj2 };
console.log(merged);
// {a: 1, b: 2, c: 5, d: 9}
const obj3 = { a: 1, b: 2 };
const obj4 = { c: 3, d: { e: 4, ...obj3 } };
console.log(obj4);
// {c: 3, d: {a: 1, b: 2, e: 4} }

使用 === 代替 ==

在JavaScript 中,=== 和== 是有很大的不同的,== 会将两边的变量进行转义,然后将转义后的值进行比较,而=== 是严格比较,要求两边的变量不仅值要相同,它们自身的类型也要相同。

JavaScript 经常被调侃成一个神奇的语言,就是因为它的转义的特性,而用== 可能会引入一些深埋的bug。远离 bug,还是要用===:

[10] == 10  // true
[10] === 10  // false
'10' == 10  // true
'10' === 10  // false
 [] == 0  // true
 [] === 0  // false
 '' == false // true
 '' === false // false

当然,在用=== 时,也会出问题,比如:

NaN === NaN // false

ES6 中提供了一个新的方法:Object.is(),它具有=== 的一些特点,而且更好、更准确,在一些特殊场景下变现的更好:

Object.is(0 , ' ');   //false
Object.is(null, undefined); //false
Object.is([1], true);  //false
Object.is(NaN, NaN);  //true

下图,是关于==、=== 和Object.is 的对比:

JavaScript实用代码小技巧

Javascript 相关文章推荐
js批量设置样式的三种方法不推荐使用with
Feb 25 Javascript
jQuery之过滤元素操作小结
Nov 30 Javascript
JavaScript极简入门教程(二):对象和函数
Oct 25 Javascript
jQuery中change事件用法实例
Dec 26 Javascript
jQuery实现的五子棋游戏实例
Jun 13 Javascript
JavaScript获取页面中超链接数量的方法
Nov 09 Javascript
JavaScript基础知识点归纳(推荐)
Jul 09 Javascript
如何提高Dom访问速度
Jan 05 Javascript
JavaScript中常见的八个陷阱总结
Jun 28 Javascript
详解Vue学习笔记入门篇之组件的内容分发(slot)
Jul 17 Javascript
JavaScript实现简单图片轮播效果
Aug 21 Javascript
vue组件(全局,局部,动态加载组件)
Sep 02 Javascript
jQuery实现鼠标移到某个对象时弹出显示层功能
Aug 23 #jQuery
使用JS实现导航切换时高亮显示的示例讲解
Aug 22 #Javascript
Vue 菜单栏点击切换单个class(高亮)的方法
Aug 22 #Javascript
Vue.js点击切换按钮改变内容的实例讲解
Aug 22 #Javascript
Vue2.0点击切换类名改变样式的方法
Aug 22 #Javascript
vuejs选中当前样式active的实例
Aug 22 #Javascript
详解如何在webpack中做预渲染降低首屏空白时间
Aug 22 #Javascript
You might like
php str_pad() 将字符串填充成指定长度的字符串
2010/02/23 PHP
JS 毫秒转时间示例代码
2013/09/22 Javascript
DOM基础教程之事件类型
2015/01/20 Javascript
常用jQuery代码分享
2015/07/14 Javascript
你一定会收藏的Nodejs代码片段
2016/02/04 NodeJs
JavaScript模版引擎的基本实现方法浅析
2016/02/15 Javascript
jQuery判断是否存在滚动条的简单方法
2016/09/17 Javascript
JavaScript每天必学之事件
2016/09/18 Javascript
async/await与promise(nodejs中的异步操作问题)
2017/03/03 NodeJs
Nodejs读取文件时相对路径的正确写法(使用fs模块)
2017/04/27 NodeJs
javaScript产生随机数的用法小结
2018/04/21 Javascript
js前端面试之同步与异步问题详解
2019/04/03 Javascript
vue跳转方式(打开新页面)及传参操作示例
2020/01/26 Javascript
python 字典(dict)遍历的四种方法性能测试报告
2014/06/25 Python
python中元类用法实例
2014/10/10 Python
Python验证码识别处理实例
2015/12/28 Python
Python3 模块、包调用&路径详解
2017/10/25 Python
Django配置celery(非djcelery)执行异步任务和定时任务
2018/07/16 Python
python mysql断开重连的实现方法
2019/07/26 Python
python爬虫 模拟登录人人网过程解析
2019/07/31 Python
Python制作词云图代码实例
2019/09/09 Python
python生成器推导式用法简单示例
2019/10/08 Python
Python中求对数方法总结
2020/03/10 Python
Jupyter加载文件的实现方法
2020/04/14 Python
python爬虫智能翻页批量下载文件的实例详解
2021/02/02 Python
CSS3制作翻转效果_动力节点Java学院整理
2017/07/11 HTML / CSS
CSS3实现银灰色动画效果的导航菜单代码
2015/09/01 HTML / CSS
意大利比基尼品牌:MISS BIKINI
2019/11/02 全球购物
教师岗位聘任书范文
2014/03/29 职场文书
交通安全责任书范本
2014/07/24 职场文书
上班离岗检讨书
2014/09/10 职场文书
公司收款委托书范本
2014/09/20 职场文书
医生个人自我剖析材料
2014/10/08 职场文书
2014年村委会工作总结
2014/11/24 职场文书
小学生毕业评语
2014/12/26 职场文书
2015年团队工作总结范文
2015/05/04 职场文书