es6的一些骚操作
- 简洁高效的解构语法
- 遍历写法(数组与对象)
- 定义与获取对象属性描述
- 总结
前言
写博客,在犹豫一会,价值度不高,非知识开拓性,无非几十分钟,几个小时写完的作文一样,点击发布交卷,之后期待别人的评分点赞?技术重复分享,搞得像是无耻的事一样,不,我也这么这么做,反正也闲的蛋疼,嘻嘻嘻。其实想多了,纯粹的分享,才不会想或者在乎呢,分享个人经验与看法,或是分享已有的知识见解,都是个体情感产生的,万一有一个小弟看着,就与你产生共契合,帮助到别人,当然是很好的。写博客,其实想表达的,自己对知识点的见解而已,虽然粗陋,也是给自己看的,谁会嫌弃自己的佳作的呢。
简洁高效的语法
es6新增了很多简洁风格,使其代码清爽便捷了许多。
模版字符串
模版字符串很常用,分两类应用场景。
一,书写整齐的HTML片段,避免了‘一行到底’与字符串拼接;
二,应用于字符串与变量随性组合拼接。
比较常用,附上小例子
const name = '章';
$('.container').prepend(
'<div>' +
'<span> 额hi额黑' + name + '</span>' +
'</div>'
)
// 模版字符串
$('.container').prepend(`
<div>
<span>额hi额黑 ${name}</span>
</div>
`)
函数传参默认值
定义函数的时候,有时或者需求上需将形参设置为指定的备选值或叫默认值。
小例子,结合具名函数与匿名函数,以及用上模版字符串
function person (name,species) {
species = species || 'person';
console.log(species + ',It name is:' + name);
}
const person = function (name,species = 'person') {
console.log(`${species},It name is:${name}`);
}
注意:函数形参不能有同名参数,会报错。
也是,当然直接这么用,也体现不了多少简洁或是方便。函数默认赋值,一般与解构赋值结合
// 函数参数为对象
function foo({x,y=5}) {
console.log(x,y);
}
foo(); // 报错,实参不为对象肯定报错呗
foo({}); // undefind 5; 函数默认值为5
// 简单网络请求的封装函数,函数格式(字符串,对象)
function fetch(url,{ body = '', method = 'get', headers = {} }) {
console.log(method);
}
fetch('https://www.hp.com',{}); // 'get',函数默认值为get
fetch('https://www.hp.com'); // 传格式不对,报错
// 上述例子,格式定要传对象,否则缺少参数就会报错,可以改良,给对象也一个默认值
function fetch(url,{ body = '', method = 'get', headers = {} } = {}) {
console.log(method);
}
fetch('https://www.hp.com'); // ‘get’
// 若指定某个参数不能省略,又想自定义抛出错误(默认值应用)
function customError () {
throw new Error('必须传一个对象,否则我就报错这条错误信息。');
}
function foo({x,y=5} = customError()) {
console.log(x,y);
}
foo(); // 报错,必须传一个对象,否则我就报错这条错误信息
扩展运算符
扩展运算符,一般与es6新增的rest结合使用。rest参数就类似于arguments对象,收集实参信息,(形式...变量名),就想当于将实参里面每项罗列出来。
来个小例子,运行下
(function (){
console.log(arguments); //{ '0': 1, '1': 2, '2': 3, '3': 4, '4': 'a', '5': 2, '6': 3 }
Object.values(arguments).forEach(v => {
console.log(v);
});
})(1,2,3,4,'a',2,3);
(function (...values){
console.log(values); // [ 1, 2, 3, 4, 'a', 2, 3 ]
values.forEach(v => {
console.log(v);
})
})(1,2,3,4,'a',2,3);
(function (...values){
console.log(values); // [ { a: 1, b: true, c: 'hello' }, { b: 1 } ]
values.forEach(v => {
console.log(v);
})
})({a:1,b: true, c: 'hello'},{b: 1})
上述代码,写了个匿名函数传参自调用,可以看出arguments参数是一个实参对象。键值对形式,键为位置下标。而使用rest参数,可以获得实参选项对应数组,便于遍历。
遍历写法(数组与对象)
遍历,在平平常常的开发中,使用频率蛮高的。我们总会喜欢一种或几种写法,这无可厚非。但是常用不一定合适,或是不一定一次性代码解决需求问题。所以下面总结,遍历所有场景与方法,便于冲锋般的急促中,想起身上还有一个不常用但迅速杀一窝敌的手雷。崩————GG,阵亡
1. for循环
for 循环,想必大学听着基本语法结构。但是好像在实际开发中,没怎么用过。反正我是没用过,但是很有用滴~
写个例子
const arr = [1,2,1,'c',true];
for(let i =0; i < arr.length;i++) {
console.log(arr[i]); // 循环获取数组的值与下标
}
2. forEach循环
forEach循环,数组遍历常用的一种。注意,返回值为undefined;唯一能够跳出循环的,通过try{}catch(err) { throw ' Error Info'}类似抛出异常结构,终止循环(注意的是,将遍历循环代码放在try...catch结构内)。不会响应break、continue、return语句。其中break,结束循环的进程;continue,结束本轮循环;return,跳出函数并返回值。
写个例子
const traverseArr = ['1','2', '3', 'asdf',true, 2];
let resultStr = traverseArr.forEach((item,index,array) => {
console.log(item); // 数组当前选中值
console.log(index); // 数组当前选中的下标
if(item === 'asdf') {
console.log('数组里面的true,2不会打印!'); // 没有效果,不响应break语句
break;
}
console.log(array); // 数组本身
})
console.log(resultStr); // undefined
-----------
try {
let resultStr = traverseArr.forEach((item,index,array) => {
console.log(item);
if(item === 'asdf') {
throw 'asdf值以后的值,不会打印了。结束循环了'
}
})
} catch (err) {
console.log(err);
}
3.for... of遍历
for...of遍历数组 , 可以正确响应break、continue和return语句
写个例子
const traverseArr = ['1','2', '3', 'asdf',true, 2];
for(item of traverseArr) {
console.log(item);
if(item === 'asdf') {
console.log('确实不会打印asdf里面的值!');
break;
}
}
4.map遍历
map遍历是很常用的一种,支持返回值为处理后的数组,数组中的元素为原始数组元素调用函数处理后的值。 可以发现,返回值为深拷贝
写个例子
const traverseArr = ['1','2', '3', 'asdf',true, 2];
let resultArr = traverseArr.map((item,index,arr) => {
if(item === '3') {
return '2';
}
return item;
});
console.log(traverseArr); // [ '1', '2', '3', 'asdf', true, 2 ]
console.log(resultArr); // [ '1', '2', '2', 'asdf', true, 2 ]
5.filter遍历
filter遍历, 不会对空数组进行检测,不会改变原始数组,返回新数组。一般用于过滤数组
写个例子
const traverseArr = [
{name: 'yy',age: 24, denger: 'man',isFirst: true},
{name: 'lz', age: 23,denger: 'man',isFirst: false},
{name: 'laz', age: 23,denger: 'woman',isFirst: true},
]
let resultArr = traverseArr.filter((v,i,arr) => v.denger === 'woman');
console.log(traverseArr); // [ { name: 'yy', age: 24, denger: 'man', isFirst: true },{ name: 'lz', age: 23, denger: 'man', isFirst: false },
{ name: 'laz', age: 23, denger: 'woman', isFirst: true } ]
console.log(resultArr); // [ { name: 'laz', age: 23, denger: 'woman', isFirst: true } ]
6.every遍历
every遍历,用于检测数组所有元素是否都符合指定条件,如果所有元素都满足条件,则返回 true。其实蛮有作用的,一开始我们可能设置标志位,然后遍历每一项,来更改标志位状态。与some遍历相比,相当于逻辑与的操作
写个例子
const traverseArr = [
{name: 'yy',age: 24, denger: 'woman',isFirst: true},
{name: 'lz', age: 23,denger: 'woman',isFirst: false},
{name: 'laz', age: 23,denger: 'woman',isFirst: true},
];
let isAllWomen = traverseArr.every((v,i,arr) => {
if(v.denger === 'woman') {
return true;
}
return false;
})
console.log(isAllWomen); // true
7.some遍历
some遍历, 用于检测数组中的元素是否用满足指定条件的,如果有一个元素满足条件,剩余的元素不会再执行检测。返回值,若如果数组中有元素满足条件返回true,且终止循环
写个例子
const traverseArr = [
{name: 'yy',age: 24, denger: 'woman',isFirst: true},
{name: 'lz', age: 23,denger: 'man',isFirst: false},
{name: 'laz', age: 23,denger: 'man',isFirst: true},
];
let isHasWomen = traverseArr.some((v,i,arr) => {
console.log(v);
if(v.denger === 'woman') {
return true;
}
return false;
})
console.log(isHasWomen);
8.reduce遍历
reduce遍历,接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。返回值,为返回计算结果
写个例子
// 获取数组值得总和
const traverseArr = [
{name: 'yy',age: 24, denger: 'woman',isFirst: true},
{name: 'lz', age: 23,denger: 'man',isFirst: false},
{name: 'laz', age: 21,denger: 'man',isFirst: true},
];
let totalAge = traverseArr.reduce((total,v,i,arr) => {
return total + v.age;
},0);
console.log(totalAge); // 68
--------
// 获取数组最大值
const traverseArr = [
{name: 'yy',age: 24, denger: 'woman',isFirst: true},
{name: 'lz', age: 23,denger: 'man',isFirst: false},
{name: 'laz', age: 21,denger: 'man',isFirst: true},
];
let maxVal = traverseArr.reduce((prev,cur) => {
return Math.max(prev,cur.age)
},0);
console.log(maxVal); // 24
9.reduceRight遍历
reduceRight遍历,方法的功能和reduce()功能是一样的,不同的是reduceRight()从数组的末尾向前将数组中的数组项做累加。
10.for...in遍历
in 关键字遍历对象属性和原型上的属性(可遍历属性)。for...in遍历,一般用于遍历对象属性,但也可以遍历数组
写个例子
const traverseArr = [
{name: 'yy',age: 24, denger: 'woman',isFirst: true},
{name: 'lz', age: 23,denger: 'man',isFirst: false},
{name: 'laz', age: 21,denger: 'man',isFirst: true},
];
const objH = {
name: 'name',
age: 23,
gender: 'man'
}
for(is1 in traverseArr) {
console.log(traverseArr[is1]);
}
for(i in objH) {
console.log(traverseArr[is1]);
}
11.es6新增 keys,values,entries
ES6 提供三个新的方法 —— entries(),keys()和values() —— 用于遍历数组。它们都返回一个遍历器对象
写个例子
const arr = [2,true,'hello'];
console.log(arr.values()); // Object [Array Iterator] {}
console.log(arr.keys()); // Object [Array Iterator] {}
console.log(arr.entries()); // Object [Array Iterator] {}
for(let [v,i] of arr.entries()) {
console.log(v); // 下标
console.log(i); // 值
}
for(let v of arr.keys()) {
console.log(v); // 值
}
for(let v of arr.values()) {
console.log(v); // 值
}
12.find遍历
find遍历,返回通过测试(函数内判断)的数组的第一个元素的值,注意,当数组中的元素在测试条件时返回 true 时, find() 返回符合条件的元素。跟some遍历类似,符合条件停止遍历,但some遍历返回的状态
写个例子
const arr = [2,3,true,'hello','xixi',2];
let firstVal = arr.find((val,index,arr) => {
console.log(val);
if(val === 'hello') {
return true;
}
}); // 遍历打印: 2 3 true hello
console.log(firstVal); // hello
13.findIndex 遍历
findIndex遍历, 返回传入一个测试条件(函数)符合条件的数组第一个元素位置(下标)。
14.对象遍历 Object.keys()、Object.values()、Object.entries()
我们知道<code>in</code>关键字,遍历对象属性但也遍历该对象原型链上的可遍历属性。而现在介绍的属性,遍历的是本身对象可遍历的属性。
写个例子
const obj = {
name: 'yangyi',
age: 23,
gender: 'woman',
say() {
console.log('hello beatuify world!');
}
};
const parent = {
sex: true,
sayHei: function (name) {
console.log(`hello ${name}!`);
}
};
Object.setPrototypeOf(obj,parent); // 建立原型链
// Object.keys()
console.log(Object.keys(obj)); // [ 'name', 'age', 'gender', 'say' ]
Object.keys(obj).forEach(v => {
console.log(v); // 打印: name,age,gender,say
});
// for ... in 可遍历原型上的属性
for(key in obj) {
console.log(key); // 打印对象本身及原型上的key值
}
----------
// Object.values()
console.log(Object.values(obj));
Object.values(obj).forEach(v => {
console.log(v)
})
----------
// Object.entries()
console.log(Object.entries(obj)); // [ [ 'name', 'yangyi' ],[ 'age', 23 ],[ 'gender', 'woman' ],[ 'say', [Function: say] ] ]
for([k,v] of Object.entries(obj)) {
console.log(k);
console.log(v);
}
注意的是,使用Object.entries()返回二维数组格式。我们也可以通过Object.fromEntries()将一个键值对数组转为对象。
定义与获取对象属性描述
本小节,主要了解的是对象本身属性描述,定义描述与获取描述。其中,介绍一下,属性描述符主要分为两类,数据描述符和存取描述符。数据描述符是一个具有值的属性,而存取描述符是由getter-setter函数对描述的属性。
了解一下具体属性描述符:
- configurable,该值为 true 时,该属性描述符才能够被配置改变,否则无法重新设置。
- enumerable, 该值为true时,该属性才能够出现在对象的枚举属性中
- value, 该属性对应的值,默认为undefined。
- writable,该属性的writable值为true,value才能被修改。
- get, 属性提供 getter 的方法,如果没有 getter 则为 undefined。
- set, 属性提供 setter 的方法,如果没有 setter 则为 undefined.
注意,描述符(value或writable)和(get或set)关键字不能同时存在,否则会抛出一个错误。如果一个描述符不具有value,writable,get 和 set 任意一个关键字,那么它将被认为是一个数据描述符
大致了解了属性描述符,现在我们看看与它有关的方法:
Object.defineProperty()和Object.defineProperties(),定义对象的属性描述符
写个小例子,定义一个对象的属性的值不可修改,不可遍历,不可重新配置
let descriptorObj = {};
let descriptor = Object.create(null);
// 默认没有 enumerable,没有 configurable,没有 writable
descriptor.value = 'static';
Object.defineProperty(descriptorObj,'key',descriptor);
console.log(descriptorObj.key);
descriptorObj.key = 'write';
console.log(descriptorObj.key); // 打印static,不可修改
for(key in descriptorObj) {
console.log(key,'打印'); // 不可遍历
};
Object.defineProperty(descriptorObj,'key',{ // 报错
value: '重新修改这个值',
enumerable: true,
writable: true,
configurable: true
})
注意上述,通过 Object.create(null)将proto属性指向null,然后指定对象value描述符,其它描述符不指定,则默认false。如果想同时配置对象的多个属性的属性描述符,可以使用Object.defineProperties()方法
let descriptorObj = {
name: 'yangyi',
age: 24,
denger: 'woman'
};
Object.defineProperties(descriptorObj, {
name: {
value: 'yangyi1',
writable: true,
enumerable: false,
configurable: true
},
age: {
value: 25,
enumerable: true,
writable: false,
configurable: true
},
denger: {
value: 'man',
writable: false,
enumerable: true,
configurable: false
}
});
console.log(Object.getOwnPropertyDescriptors(descriptorObj));
Object.keys(descriptorObj).forEach(v => {
console.log(v); // age denger
});
console.log(descriptorObj.age); // 25
descriptorObj.age = 26; // age属性描述符不可重写
console.log(descriptorObj.age); // 25
Object.defineProperty(descriptorObj,'denger',{ // 报错
writable: true,
configurable: true
})
上述定义对象多个属性的描述符代码中,使用getOwnPropertyDescriptors获取对象属性的描述符。下面就介绍获取对象描述符的方法
Object.getOwnPropertyDescriptors() 和Object.getOwnPropertyDescriptor(),获取对象的属性描述符
let descriptorObj = {
name: 'yangyi',
age: 24,
denger: 'woman'
};
Object.defineProperties(descriptorObj, {
name: {
value: 'yangyi1',
writable: true,
enumerable: false,
configurable: true
},
age: {
value: 25,
enumerable: true,
writable: false,
configurable: true
},
denger: {
value: 'man',
writable: false,
enumerable: true,
configurable: false
}
});
console.log(Object.getOwnPropertyDescriptors(descriptorObj));
---打印值--
{ name:
{
value: 'yangyi1',
writable: true,
enumerable: false,
configurable: true
},
age:
{
value: 25,
writable: false,
enumerable: true,
configurable: true
},
denger:
{
value: 'man',
writable: false,
enumerable: true,
configurable: false
}
}
console.log(Object.getOwnPropertyDescriptor(descriptorObj,'denger'));
---打印值----
{
value: 'man',
writable: false,
enumerable: true,
configurable: false
}
总结
怎么说呢,分享的其实是技术面的扩展,便于记忆,以及工作开发效率。其实真正的技术,还是不断深究其里,每个技术的细枝末节。不过始终相信,保持热情、耐心,一点点的去进步,相信会获得更多。
爱代码,爱生活
参考
es6 阮一峰