Open godbasin opened 7 years ago
本文介绍一些ES6/ES7好玩实用又简单的特性,或许对写代码的效率也有一定帮助噢。
ES6/ES7的出现已经有一段时间了,里面的一些新特性你们是否了解呢?本骚年将结合自身的一些使用经历介绍一些简单实用的新特性/语法糖。 基础常用的一些如let、const等这里就不详细介绍了,关于ES6/ES7的一些具体说明介绍大家可以参考ECMAScript 6 入门。
let
const
数组的变量的取值与位置相关,而对象的属性与变量名有关。
// 数组 let [a, b, c] = [1, 'abc', [3, 4]]; // a = 1, b = 'abc', c = [3, 4] // 对象 let { x, y } = { x: "a", y: 1 }; // x="a", y=1
数组和对象的解构赋值其实用得不多,毕竟这样代码阅读性可能不大好,尤其数组的解构赋值和变量顺序紧紧关联。
解构赋值允许指定默认值。我猜你们很多都用到对象的默认值,数组的用过吗?
// 数组 let [x, y = 'b', c = true] = ['a', undefined]; // x = 'a', y = 'b', c = true // 对象 let {x, y = 5, z = 3} = {x: 1, y: undefined, z: null}; // x=1, y=5, z=null let [x = f()] = [1]; // 这里的f()并不会执行 let [x = f()] = [undefined]; // 这里的f()会执行
从上面代码我们可以发现两点:
===
undefined
函数参数的解构就比较有趣了,当然应用场景会更多。
参数解构,同时设置默认值,再也不需要长长的if判断和处理了:
function plus({x = 0, y = 0}){ return (x + y); }
别小看这三个点...,身为拓展运算符,它们还是很方便的。
...
// 数组 const [a, ...b] = [1, 2, 3]; // a = 1, b = [2, 3] // 对象 let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; // x = 1, y = 2, z = { a: 3, b: 4 }
这里面需要注意的是:
__proto__
解构赋值配合拓展运算符,还可以很方便地扩展某个函数的参数,引入其他操作。
function newFunction({ x, y, ...restConfig }) { // 使用x和y参数进行操作 // 其余参数传给原始函数 return originFunction(restConfig); }
let z = { a: 1, b: 2 }; let n = { ...z }; // n = { a: 1, b: 2 }
let ab = { ...a, ...b };
我们会发现,使用拓展运算符...进行对象的拷贝和合并,其实与ES6中另外一个语法糖Object.assign()效果一致:
Object.assign()
// 上面的合并等同于 let ab = Object.assign({}, a, b);
需要注意的有:
ES6引入rest参数(形式为...rest),用于获取函数的多余参数,这样就不需要使用arguments对象了。 rest参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
...rest
arguments
function add(...values) { let sum = 0; values.forEach(x => {sum += x;}) return sum; } add(1, 2, 3) // 6
替换arguments:
// arguments变量的写法 function sortNumbers() { return Array.prototype.slice.call(arguments).sort(); } // rest参数的写法 const sortNumbers = (...numbers) => numbers.sort();
同样要注意的是,rest只能是最后一个参数。
说到arguments,这里插播一下尾调用优化。
递归非常耗费内存,因为需要同时保存成千上百个调用帧,很容易发生“栈溢出”错误(stack overflow)。 但对于尾递归来说,由于只存在一个调用帧,所以永远不会发生“栈溢出”错误。
ES6的尾调用优化只在严格模式下开启,正常模式是无效的。因为在正常模式下,函数内部有两个变量,可以跟踪函数的调用栈:
func.arguments
func.caller
对象拓展了一些很方便的属性,简化了我们很多的工作。常用的:
用于将所有可枚举的属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
Object.keys()
返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名。
听着好复杂,但是很多时候当我们需要遍历某个对象的时候就很方便了:
Object.keys(someObj).forEach((key, index) => { // 需要处理的操作 });
Object.values()
Object.entries
数组也拓展了一些属性:
Array.from()
Array.of()
entries()
keys()
values()
这里只介绍可能比较常用的:
Array.find()
参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined。
[1, 4, -5, 10].find((n) => n < 0); // -5
Array.findIndex():用法与find方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。
Array.findIndex()
Array.includes():返回一个布尔值,表示某个数组是否包含给定的值
Array.includes()
Set
它类似于数组,但是成员的值都是唯一的,没有重复的值。 Set本身是一个构造函数,用来生成Set数据结构。
从此我们的去重就可以这样写了:
let newArray = Array.from(new Set(oldArray));
Map
JavaScript的对象(Object),本质上是键值对的集合(Hash结构),但是传统上只能用字符串当作键。
Object
// 不信你可以试试看 const obj = {a: 123}; const a = []; a[obj] = 1; console.log(a["[object Object]"]);
原因是对象只接受字符串作为键名,所以obj被自动转为字符串[object Object]。
[object Object]
Map数据结构类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。 也就是说,Object结构提供了“字符串—值”的对应,Map结构提供了“值—值”的对应,是一种更完善的Hash结构实现。
ES6允许直接写入变量和函数,作为对象的属性和方法。
// 属性简写 function f(x, y) { return {x, y}; // 等同于 return {x: x, y: y}; } // 方法简写 var obj = { method() {} // 等同于 method: function() {} };
ES6允许使用“箭头”(=>)定义函数。
=>
var f = () => 5; // 等同于 var f = function () { return 5 };
箭头函数有几个使用注意点:
最关键的是第一点:this对象的指向是可变的,但是在箭头函数中,它是固定的。
function normalFunction() { setTimeout(function(){ console.log(this.name); }, 100); } function arrowFunction() { setTimeout(() => { console.log( this.name); }, 100); } var name = 'outer'; normalFunction.call({ name: 'inner' }); // 'outer' arrowFunction.call({ name: 'inner' }); // 'inner'
这里我们介绍了ES6/ES7一些基础比较普遍的点,像解构、拓展表达式(...)、数组对象等拓展属性等等,基本上是一些提高开发效率,减少冗余重复的代码的新特性和新语法。 而像改变我们设计思维、甚至是解决方案的则是一些较复杂的,像Class、Module、Promise、async/await等等,咱们分篇讲,或者查ECMAScript 6 入门手册吧哈哈。
Class
Module
Promise
async/await
我是来学习的
本文介绍一些ES6/ES7好玩实用又简单的特性,或许对写代码的效率也有一定帮助噢。
ES6/ES7的出现已经有一段时间了,里面的一些新特性你们是否了解呢?本骚年将结合自身的一些使用经历介绍一些简单实用的新特性/语法糖。 基础常用的一些如
let
、const
等这里就不详细介绍了,关于ES6/ES7的一些具体说明介绍大家可以参考ECMAScript 6 入门。「解构」知多少
解构赋值
数组的变量的取值与位置相关,而对象的属性与变量名有关。
数组和对象的解构赋值其实用得不多,毕竟这样代码阅读性可能不大好,尤其数组的解构赋值和变量顺序紧紧关联。
默认值
解构赋值允许指定默认值。我猜你们很多都用到对象的默认值,数组的用过吗?
从上面代码我们可以发现两点:
===
),如果一个数组成员不严格等于undefined
,默认值是不会生效的。函数参数的解构
函数参数的解构就比较有趣了,当然应用场景会更多。
参数解构,同时设置默认值,再也不需要长长的if判断和处理了:
牛逼的点--拓展运算符(...)
数组和对象
别小看这三个点
...
,身为拓展运算符,它们还是很方便的。这里面需要注意的是:
__proto__
的属性)。配合解构赋值
解构赋值配合拓展运算符,还可以很方便地扩展某个函数的参数,引入其他操作。
快速拷贝拓展对象
我们会发现,使用拓展运算符
...
进行对象的拷贝和合并,其实与ES6中另外一个语法糖Object.assign()
效果一致:需要注意的有:
rest参数
ES6引入rest参数(形式为
...rest
),用于获取函数的多余参数,这样就不需要使用arguments
对象了。 rest参数搭配的变量是一个数组,该变量将多余的参数放入数组中。替换
arguments
:同样要注意的是,rest只能是最后一个参数。
说到
arguments
,这里插播一下尾调用优化。递归非常耗费内存,因为需要同时保存成千上百个调用帧,很容易发生“栈溢出”错误(stack overflow)。 但对于尾递归来说,由于只存在一个调用帧,所以永远不会发生“栈溢出”错误。
ES6的尾调用优化只在严格模式下开启,正常模式是无效的。因为在正常模式下,函数内部有两个变量,可以跟踪函数的调用栈:
func.arguments
:返回调用时函数的参数。func.caller
:返回调用当前函数的那个函数。一起来「拓展」
对象的拓展
对象拓展了一些很方便的属性,简化了我们很多的工作。常用的:
Object.assign()
用于将所有可枚举的属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
Object.keys()
返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名。
听着好复杂,但是很多时候当我们需要遍历某个对象的时候就很方便了:
Object.values()
:与Object.keys()
相似,返回参数对象属性的键值Object.entries
:同上,返回参数对象属性的键值对数组数组的拓展
数组也拓展了一些属性:
Array.from()
:用于将两类对象转为真正的数组Array.of()
:用于将一组值,转换为数组entries()
、keys()
、values()
等这里只介绍可能比较常用的:
Array.find()
:用于找出第一个符合条件的数组成员参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回
undefined
。Array.findIndex()
:用法与find方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。Array.includes()
:返回一个布尔值,表示某个数组是否包含给定的值数据结构的拓展
Set
它类似于数组,但是成员的值都是唯一的,没有重复的值。
Set
本身是一个构造函数,用来生成Set
数据结构。从此我们的去重就可以这样写了:
Map
JavaScript的对象(
Object
),本质上是键值对的集合(Hash结构),但是传统上只能用字符串当作键。原因是对象只接受字符串作为键名,所以obj被自动转为字符串
[object Object]
。Map
数据结构类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。 也就是说,Object
结构提供了“字符串—值”的对应,Map结构提供了“值—值”的对应,是一种更完善的Hash结构实现。关于简写那些事
属性的简写
ES6允许直接写入变量和函数,作为对象的属性和方法。
箭头函数
ES6允许使用“箭头”(
=>
)定义函数。箭头函数有几个使用注意点:
最关键的是第一点:this对象的指向是可变的,但是在箭头函数中,它是固定的。
结束语
这里我们介绍了ES6/ES7一些基础比较普遍的点,像解构、拓展表达式(
...
)、数组对象等拓展属性等等,基本上是一些提高开发效率,减少冗余重复的代码的新特性和新语法。 而像改变我们设计思维、甚至是解决方案的则是一些较复杂的,像Class
、Module
、Promise
、async/await
等等,咱们分篇讲,或者查ECMAScript 6 入门手册吧哈哈。