原文: Check out these useful ECMAScript 2015 (ES6) tips and tricksjavascript
有任何错误请在评论指出,感激涕零。html
EcmaScript 2015 (ES6) 已经出现了不少年了,咱们可使用它的一些新特性。java
ES6 提供了 默认的参数值,可让你在函数的参数中指定默认值当参数没有传递其值的时候。es6
const required = () => {throw new Error('Missing parameter')};
//The below function will trow an error if either "a" or "b" is missing.
const add = (a = required(), b = required()) => a + b;
add(1, 2) //3
add(1) // Error: Missing parameter.
复制代码
在这个例子中,咱们对函数 add
的参数 a
和 b
设置了一个默认值,这个默认值为一个函数。当函数 add
被执行时,且参数 a
和 b
有一个没有传递值的时候,这个 required
函数就会执行,咱们就会获得一个报错 Error: Missing parameter.
数组
Array
的方法 reduce
是一个有很是多用处的函数。 它一个很是具备表明性的做用是将一个数组转换成一个值。可是你能够用它来作更多的事。promise
🔥 Tip: 这些小技巧的的初始值都是一个数组或者一个对象而不是一个像字符串之类的简单的值闭包
假设有这样的一个场景,你有一个list,里面有一些item, 你须要更新这些item, 更新完之后你须要使用filter来过滤掉你不须要的item。可是这样的话你须要遍历这个数组两次!ecmascript
const numbers = [10, 20, 30, 40];
const doubledOver50 = numbers.reduce((finalList, num) => {
num = num * 2; //double each number (i.e. map)
//filter number > 50
if (num > 50) {
finalList.push(num);
}
return finalList;
}, []);
doubledOver50; // [60, 80]
复制代码
在这个例子里面,咱们想要让数组里面的值翻倍,而后咱们只想要里面大于 50
的元素。注意一下咱们是如何使用 reduce
方法作到同时有让元素的值翻倍,而后过滤的。async
在原文中没有体现这部分代码,只说了注意2.1的代码。在这里我添加一下这部分代码:函数
function map(arr, exec) {
var res = arr.reduce((res, item, index) => {
var newItem = exec(item, index)
res.push(newItem)
return res
}, [])
return res
}
[1, 2, 3].map((item) => item * 2) // [2, 4, 6]
map([1, 2, 3], item => item * 2) // [2, 4, 6]
复制代码
function filter(arr, exec) {
var res = arr.reduce((res, item, index) => {
if (exec(item, index)) {
res.push(item)
}
return res
}, [])
return res
}
[1, 2, 3].filter((item, index) => index < 2) // [1, 2]
filter([1, 2, 3], (item, index) => index < 2) // [1, 2]
复制代码
这也是个例子来讲明 reduce
这个函数功能的强大。给你一串字符串,你想要知道这串字符串的括号是不是匹配的。
常规的作法是使用栈来匹配,可是这里咱们使用 reduce
就能够作到,咱们只须要一个变量 counter
,这个变量的初始值是 0 , 当遇到 (
的时候,counter ++
当遇到 )
的时候, counter --
。 若是括号是匹配的,那么这个 counter
最终的值是0
//Returns 0 if balanced.
const isParensBalanced = (str) => {
return str.split('').reduce((counter, char) => {
if(counter < 0) { //matched ")" before "("
return counter;
} else if(char === '(') {
return ++counter;
} else if(char === ')') {
return --counter;
} else { //matched some other char
return counter;
}
}, 0); //<-- starting value of the counter
}
isParensBalanced('(())') // 0 <-- balanced
isParensBalanced('(asdfds)') //0 <-- balanced
isParensBalanced('(()') // 1 <-- not balanced
isParensBalanced(')(') // -1 <-- not balanced
复制代码
若是你想计算数组中元素出现的次数或者想把数组转为对象,那么你可使用 reduce
来作到。
var cars = ['BMW','Benz', 'Benz', 'Tesla', 'BMW', 'Toyota'];
var carsObj = cars.reduce(function (obj, name) {
obj[name] = obj[name] ? ++obj[name] : 1;
return obj;
}, {});
carsObj; // => { BMW: 2, Benz: 2, Tesla: 1, Toyota: 1 }
复制代码
做者建议前往MDN学习,查看更多例子MDN
// 我也去看了一眼MDN,发现reduce真是个黑科技,promise串行这个应用很是秒啊。
有时候你想要移除对象中的一些不须要的属性,这个对象多是包含了某些敏感的信息或者只是由于这个对象太大了。咱们可使用解构来代替去遍历这些属性。
let {_internal, tooBig, ...cleanObject} = {el1: '1', _internal:"secret", tooBig:{}, el2: '2', el3: '3'};
console.log(cleanObject); // {el1: '1', el2: '2', el3: '3'}
复制代码
在这个例子中,咱们想要移除 _internal
和 tooBig
这两个属性,咱们能够将他们分配给变量 _internal
和 tooBig
中,剩下的属性存放在 cleanObject
中,这就是咱们想要的。
var car = {
model: 'bmw 2018',
engine: {
v6: true,
turbo: true,
vin: 12345
}
}
const modelAndVIN = ({model, engine: {vin}}) => {
console.log(`model: ${model} vin: ${vin}`);
}
modelAndVIN(car); // => model: bmw 2018 vin: 12345
复制代码
在这个例子中 engine
是一个嵌套在 car
里面的对象,若是咱们只须要 engine
里面的属性 vin
咱们能够这样作。
ES6 新增了一个扩展运算符,...
使用三个点来表示,它常常用来解构数组的值, 可是它也能够用在对象中。
在这个例子中,咱们在一个新的对象中使用扩展运算符,后面一个对象的属性值会把前面一个对象的属性值覆盖。
第二个对象中的属性 b
和 c
的值把第一个对象中属性 b
与 c
的值覆盖掉了
let object1 = { a:1, b:2,c:3 }
let object2 = { b:30, c:40, d:50}
let merged = {…object1, …object2} //spread and re-add into merged
console.log(merged) // {a:1, b:30, c:40, d:50}
复制代码
在ES6能够很方便的使用Set来对数组去重,由于Set表示的是一个集合,一个元素会在集合里面出现过一次。
let arr = [1, 1, 2, 2, 3, 3];
let deduped = [...new Set(arr)] // [1, 2, 3]
复制代码
能够经过(...)扩展运算符将 Set
转换成 Array
这样咱们就能够在 Set
使用全部 Array
的方法了。
这个例子展现了如何在 Set
中使用 filter
方法
let mySet = new Set([1,2, 3, 4, 5]);
var filtered = [...mySet].filter((x) => x > 3) // [4, 5]
复制代码
let param1 = 1;
let param2 = 2;
//swap and assign param1 & param2 each others values
[param1, param2] = [param2, param1];
console.log(param1) // 2
console.log(param2) // 1
复制代码
async function getFullPost(){
return await Promise.all([
fetch('/post'),
fetch('/comments')
]);
}
// const [post, comments] = getFullPost();
const [post, comments] = await getFullPost();
// 注释掉的那一行是做者写的,可是我跑不通,我以为getFullPost是个Promise,因此须要加await。
复制代码
咱们使用 async\await
来获取2个接口的数据 /post
和 /comments
, 函数返回的是一个数组,因此可使用解构来得到这两个接口的返回值。
做者原文章的内容就到这里,可是我想补充一下map。
在对象中的 key
只能是 string
没办法接受一个 Object
看成 key
会被自动转换成字符串,例子以下:
const data = {};
const element = document.getElementById('myDiv');
data[element] = 'metadata';
data['[object HTMLDivElement]'] // "metadata"
复制代码
因此对于键值对
的数据解构,map
比 Object
更加合适。
const M = new Map()
let o = {p: 'Hello World'}
M.set(o, 'hello world')
M.get(o) // hello world
let O = {p: 'Hello World'}
M.get(O) // undefined
复制代码
注意: O != o
因此这个 M.get(O)
是 undefined
在普通的map中,若是一个 object
被看成 key
引用了,当除了map之外,其余的变量都丢掉对这个 object
的引用,那map仍是会阻止垃圾回收机制去回收这个 object
这就会致使内存泄漏。因此就有了WeakMap。
字面意思,WeakMap里面的key是弱引用,而且 WeakMap中只能以 Object
看成 key
由于其余的你均可以用 Map搞啊~~那么 WeakMap的几个小技巧。
let myElement = document.getElementById('logo');
let myWeakmap = new WeakMap();
myWeakmap.set(myElement, {timesClicked: 0});
myElement.addEventListener('click', function() {
let logoData = myWeakmap.get(myElement);
logoData.timesClicked++;
}, false);
复制代码
以上例子来自 Ruanyifeng
咱们用WeakMap来存DOM节点的某些状态,当这个DOM节点被删除时,myElement失去了引用,全世界都失去了引用,WeakMap里面所存的状态就会消失,因此不会存在内存泄漏的问题。
咱们都知道,在JS中实现实例的私有属性是比较困难的,有个办法是使用闭包,可是闭包有个问题,实例被强引用,不能被垃圾回收机制处理。以下代码:
var Person = (function() {
var privateData = {},
privateId = 0;
function Person(name) {
Object.defineProperty(this, "_id", { value: privateId++ });
privateData[this._id] = {
name: name
};
}
Person.prototype.getName = function() {
return privateData[this._id].name;
};
return Person;
}());
复制代码
privateData对每一个实例都是强引用,因此垃圾回收机制是处理不了的。
咱们能够用weakMap很好的解决这个问题。
var privateData = new WeakMap();
var Person = (function() {
function Person(name) {
privateData.set(this, { name: name });
}
Person.prototype.getName = function() {
return privateData.get(this).name;
};
return Person;
}());
复制代码
以上代码weakMap不会对实例形成强引用,也就是说,垃圾回收机制是可能把这个实例回收掉的,若是没有其余人对这个实例保持着引用,是会被回收的,也就不会致使内存泄露了。
以上例子来自JavaScript实现私有属性