阅读 76

关于JS你必须知道的事——ES6语法

前言

都2021年啦,无论你是已经工作多年的老大哥,还是一个刚入门前端的新人。ES6语法都必须成为你武器库的中重要的武器之一。但是有关于ES6语法的知识是庞大的,我们没有必须全部了解,只需要知道一些进程经常使用的即可。本文就是本着梳理一遍ES6中常用的知识点的目的而出发的。

何为ES6?学习它的意义何在?

经常听到别人说ES6,但是却并不知道是什么的同学有么有?我相信肯定是有的,那么ES6究竟是什么呢?

答:ES6是新一代的语言标准,对JS的核心部分进行了升级优化,规范了JS使用标准,新增了JS原生方法,使得JS更加规范,更加优雅,更适合与大型应用的开发。学习ES6是成为专业前端的必经之路。

ES6,ES5和ES2015有什么区别呢?

ES6是个泛指的概念,泛指下一代语言JS语言标准,包括了ES2015,ES2017,ES2018等。

ES2015则是特指,特指在2015年发布的新一代JS语言标准。

现阶段在绝大部分场景下,ES2015默认等同ES6。

ES5泛指上一代语言标准。ES2015可以理解为ES5和ES6的时间分界线。

var,let,const的区别

let,const的出现是为了解决ES5没有块级作用域的问题。没有块级作用域会带来一些问题,比如for循环var变量泄露,变量覆盖等。而let,const声明的变量拥有自己的作用域。并且解决了var变量提升的问题。

var与let,const的区别

  • let,const声明的变量拥有自己的块级作用域。
  • let,const声明的变量,不能在变量声明前被使用。存在暂时性死区。
  • let,const声明的变量不存在变量提升。
  • let和const声明的变量不能重复声明。
  • let ,const声明的全局变量不会挂在顶层对象下面。

let与const的区别

  • const声明的变量需要立刻赋值,let不需要。
  • const声明的变量如果是基本数据类型,赋值之后不能在更改,如果是引用数据类型可以更改内部数据但是不能更改直接赋值。

ES6中String的改变

模板字符串

ES6新增了字符串模板,在拼接大段字符串时,用反斜杠(`)取代以往的字符串相加的形式,能保留所有空格和换行,使得字符串拼接看起来更加直观,更加优雅。

新增方法

ES6在String原型上新增了includes()方法,用于取代传统的只能用indexOf查找包含字符的方法(indexOf返回-1表示没查到不如includes方法返回false更明确,语义更清晰), 此外还新增了startsWith(), endsWith(), padStart(),padEnd(),repeat()等方法,可方便的用于查找,补全字符串。

ES6中Number的改变

新增方法

ES6在Number原型上新增了isFinite(), isNaN()方法,用来取代传统的全局isFinite(), isNaN()方法检测数值是否有限、是否是NaN。ES5的isFinite(), isNaN()方法都会先将非数值类型的参数转化为Number类型再做判断,这其实是不合理的,最造成isNaN('NaN') === true的奇怪行为--'NaN'是一个字符串,但是isNaN却说这就是NaN。而Number.isFinite()和Number.isNaN()则不会有此类问题(Number.isNaN('NaN') === false)。(isFinite()同上)

ES6中Array的改变

数组结构赋值

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。

以前,为变量赋值,只能直接指定值。

let a = 1;
let b = 2;
let c = 3;
复制代码

ES6允许写成下面这样。

let [a, b, c] = [1, 2, 3];
复制代码

上面代码表示,可以从数组中提取值,按照对应位置,对变量赋值。

在声明较多变量时,不用再写很多let(var),且映射关系清晰,且支持赋默认值。

扩展运算符

ES6新增的扩展运算符可以轻松的实现数组和松散序列的相互转化。 扩展运算符的应用: 1.可以取代arguments对象和apply方法,轻松获取未知参数个数情况下的参数集合。

2.扩展运算符还可以轻松方便的实现数组的复制。

新增方法

ES6在Array原型上新增了find()方法,用于取代传统的只能用indexOf查找包含数组项目的方法,且修复了indexOf查找不到NaN的bug([NaN].indexOf(NaN) === -1).此外还新增了includes(), flat()等方法,可方便的用于字符串的查找,补全,转换等。

ES6中Object的改变

属性的简洁表示法

ES6允许直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。

var foo = 'bar';
var baz = {foo};
baz // {foo: "bar"}

// 等同于
var baz = {foo: foo};
复制代码

除了属性简写,方法也可以简写。

var o = {
  method() {
    return "Hello!";
  }
};

// 等同于

var o = {
  method: function() {
    return "Hello!";
  }
};
复制代码

结构赋值

对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

let { bar, foo } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"

let { baz } = { foo: "aaa", bar: "bbb" };
baz // undefined
复制代码

扩展运算符

对象的扩展运算符(...)。 ES6对象的扩展运算符和数组扩展运算符用法本质上差别不大,毕竟数组也就是特殊的对象。对象的扩展运算符一个最常用也最好用的用处就在于可以轻松的取出一个目标对象内部全部或者部分的可遍历属性,从而进行对象的合并和分解。

let {apple, orange, ...otherFruits} = {apple: 'red apple', orange: 'yellow orange', grape: 'purple grape', peach: 'sweet peach'};
// otherFruits  {grape: 'purple grape', peach: 'sweet peach'}
// 注意: 对象的扩展运算符用在解构赋值时,扩展运算符只能用在最后一个参数(otherFruits后面不能再跟其他参数)
let moreFruits = {watermelon: 'nice watermelon'};
let allFruits = {apple, orange, ...otherFruits, ...moreFruits};
复制代码

新增方法

a. ES6在Object原型上新增了is()方法,做两个目标对象的相等比较,用来完善'==='方法。'==='方法中NaN === NaN //false 其实是不合理的,Object.is修复了这个小bug。(Object.is(NaN, NaN) // true)

b. ES6在Object原型上新增了assign()方法,用于对象新增属性或者多个对象合并。

注意: assign合并的对象target只能合并source1、source2中的自身属性,并不会合并source1、source2中的继承属性,也不会合并不可枚举的属性,并且assign实现的只是浅拷贝。

c. ES6在Object原型上新增了getPrototypeOf()和setPrototypeOf()方法,用来获取或设置当前对象的prototype对象。这个方法存在的意义在于,ES5中获取设置prototype对像是通过__proto__属性来实现的,然而__proto__属性并不是ES规范中的明文规定的属性,只是浏览器各大产商“私自”加上去的属性,只不过因为适用范围广而被默认使用了,再非浏览器环境中并不一定就可以使用,所以为了稳妥起见,获取或设置当前对象的prototype对象时,都应该采用ES6新增的标准用法。

d. ES6在Object原型上还新增了Object.keys(),Object.values(),Object.entries()方法,用来获取对象的所有键、所有值和所有键值对数组。

ES6中Function的改变

箭头函数

箭头函数是ES6核心的升级项之一,箭头函数里没有自己的this,这改变了以往JS函数中最让人难以理解的this运行机制。

箭头函数内的this指向的是函数定义时所在的对象,而不是函数执行时所在的对象

a. ES5函数里的this总是指向函数执行时所在的对象,这使得在很多情况下this的指向变得很难理解,尤其是非严格模式情况下,this有时候会指向全局对象,这甚至也可以归结为语言层面的bug之一。ES6的箭头函数优化了这一点,它的内部没有自己的this,这也就导致了this总是指向上一层的this,如果上一层还是箭头函数,则继续向上指,直到指向到有自己this的函数为止,并作为自己的this。

b. 箭头函数不能用作构造函数,因为它没有自己的this,无法实例化。

c. 也是因为箭头函数没有自己的this,所以箭头函数 内也不存在arguments对象。(可以用扩展运算符代替)

函数默认赋值

函数默认赋值。ES6之前,函数的形参是无法给默认值得,只能在函数内部通过变通方法实现。ES6以更简洁更明确的方式进行函数默认赋值。

function es6Fuc (x, y = 'default') {
    console.log(x, y);
}
es6Fuc(4) // 4, default
复制代码

新增方法

ES6新增了双冒号运算符,用来取代以往的bind,call,和apply。(浏览器暂不支持,Babel已经支持转码)

foo::bar;
// 等同于
bar.bind(foo);

foo::bar(...arguments);
// 等同于
bar.apply(foo, arguments);
复制代码

新增数据结构Set

Set是ES6新增的集合数据结构。类似于数组,但是成员的值都是唯一的。这个特性可以轻松地实现数组去重。 MDN对于Set的定义

Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。

新增数据结构weakSet

WeakSet与Set类似,也是包含不重复成员的集合,但是与Set有两点不同。

首先,WeakSet的成员只能是对象,而不能是其他类型的值。

其次,WeakSet中的对象都是弱引用,即垃圾回收机制不考虑WeakSet对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于WeakSet之中。这个特点意味着,无法引用WeakSet的成员,因此WeakSet是不可遍历的。

新增数据结构Map

Map与Object很像,不同的是Object的key只能是字符串,而Map的key可以是任意数据类型。可以更加全面的描述对象的属性。

MDN对Map的定义

Map 对象保存键值对,并且能够记住键的原始插入顺序。任何值(对象或者原始值) 都可以作为一个键或一个值。

新增数据结构WeakMap

WeakMap结构与Map结构类似,也是用于生成键值对的集合

第一点:WeakMap的成员只能是可迭代对象,不能是其他类型的数据。

第二点:WeakMap中的对象都是弱引用

Promise

Promise是ES6引入的一个新的对象,他的主要作用是用来解决JS异步机制里,回调机制产生的“回调地狱”。它并不是什么突破性的API,只是封装了异步回调形式,使得异步回调可以写的更加优雅,可读性更高,而且可以链式调用。

iterator(遍历器)

Iterator是ES6中一个很重要概念,它并不是对象,也不是任何一种数据类型。因为ES6新增了Set、Map类型,他们和Array、Object类型很像,Array、Object都是可以遍历的,但是Set、Map都不能用for循环遍历,解决这个问题有两种方案,一种是为Set、Map单独新增一个用来遍历的API,另一种是为Set、Map、Array、Object新增一个统一的遍历API,显然,第二种更好,ES6也就顺其自然的需要一种设计标准,来统一所有可遍历类型的遍历方式。Iterator正是这样一种标准。或者说是一种规范理念。

可迭代对象

要成为可迭代对象, 一个对象必须实现 @@iterator 方法。这意味着对象(或者它原型链上的某个对象)必须有一个键为 @@iterator 的属性,可通过常量 Symbol.iterator 访问该属性:

如何判断一个类型是不是可迭代对象

let someString = "hi";
typeof someString[Symbol.iterator];          // "function"
复制代码
  • 常见的可迭代对象,有Array,Map, Set, String,TypeArray, arguments
  • 可以通过判断Symbol.iterator判断当前变量是否是可迭代对象

for...in和for..of的区别

我们直接从一段代码来看

console.log(this.length);
}
var myArray=[1,2,4,5,6,7]
myArray.name="数组"
for (var index in myArray) {
console.log(myArray[index]);
}
复制代码
  • index获取的是索引
  • 遍历的顺序可能不是按照顺序进行的
  • 使用for in 会遍历数组所有可枚举属性,包括原型。例如上面的method和name都会遍历
  • for in 更适合遍历对象,不要使用for in去遍历数组
Array.prototype.method=function(){
console.log(this.length);
  }
  var myArray=[1,2,4,5,6,7]
  myArray.name="数组";
  for (var value of myArray) {
  console.log(value);
  }
复制代码
  • for of语法遍历的是数组元素的值
  • for in 遍历的是索引
  • for of遍历的只是数组内的元素,而不包括数组的原型属性method和索引name

小结

  • for..of适用遍历数/数组对象/字符串/map/set等拥有迭代器对象的集合,不能遍历对象,因为没有迭代对象,与forEach()不同的是,它可以正确响应break、continue和return语句。
  • for in 可以遍历一个普通的对象,这样也是它的本质工作,for in会遍历原型以及可枚举属性,最好的情况下,使用hasOwnProperty判断是不是实例属性。
文章分类
前端
文章标签