博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ES6
阅读量:7221 次
发布时间:2019-06-29

本文共 12906 字,大约阅读时间需要 43 分钟。

ES6 入门

本文参考阮一峰老师的《es6 入门》

前言

如今,距离 ES6 的正式发布时间已经过去了 3 年,随着时间的推移,各大浏览器对 ES6 的支持度已经越来越高了,超过 90%的 ES6 语法特性都实现。掌握 ES6 已经是一名前端工程师必备的能力。

ES6 let 和 const 命令

let 命令

基本用法

ES6 新增了let命令,用来声明变量,但是let所声明的变量只能在自己的代码块内有效,也就是说,原本没有块级作用域的javascript现在也有了块级作用域。

{  let a = 1; }console.log(a); //a is not defined复制代码

正因为产生块级作用域这个特点,let十分适用于 for 循环

var a = [];for (let i = 0; i < 10; i++) {  a[i] = function () {    console.log(i);  };}a[6](); // 6复制代码

上面代码中,变量ilet 声明的,当前的 i 只在本轮循环有效,所以每一次循环的 i 其实都是一个新的变量,所以最后输出的是 6。

如果使用var命令,最后输出的是 10

var a = [];for (var i = 0; i < 10; i++) {  a[i] = function () {    console.log(i);  };}a[6](); // 10复制代码

不存在变量提升

let 不像 var 那样会发生“变量提升”现象。所以,变量一定要在声明后使用,否则报错。

console.log(a); // 输出 undefinedconsole.log(b); // 报错 ReferenceErrorvar a = 2;let b = 2;复制代码

上面代码中,变量avar 命令声明,会发生变量提升,即脚本开始运行时,变量 a 已经存在了,但是没有值,所以会输出undefined。变量 blet命令声明,不会发生变量提升。这表示在声明它之前,变量b 是不存在的,这时如果用到它,就会抛出一个错误。

暂时性死区

只要块级作用域内存在 let 命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。

ES6 明确规定,如果区块中存在 letconst 命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。

总之,在代码块内,使用 let 命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)

if (true) {// TDZ 开始tmp = 'abc'; // ReferenceErrorconsole.log(tmp); // ReferenceErrorlet tmp; // TDZ 结束console.log(tmp); // undefinedtmp = 123;console.log(tmp); // 123}复制代码

上面代码中,在 let 命令声明变量 tmp之前,都属于变量 tmp 的“死区”。

ES6 规定暂时性死区和 let、const语句不出现变量提升,主要是为了减少运行时错误,防止在变量声明前就使用这个变量,从而导致意料之外的行为。这样的错误在 ES5 是很常见的,现在有了这种规定,避免此类错误就很容易了。

总之,暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。

不允许重复声明

let不允许在相同作用域内,重复声明同一个变量。

// 报错function () {  let a = 10;  var a = 1;}// 报错function () {  let a = 10;  let a = 1;}复制代码

因此,不能在函数内部重新声明参数。

do 表达式

本质上,块级作用域是一个语句,将多个操作封装在一起,没有返回值。

{  let t = f();  t = t * t + 1;}复制代码

上面代码中,块级作用域将两个语句封装在一起。但是,在块级作用域以外,没有办法得到 t 的值,因为块级作用域不返回值,除非t是全局变量。

现在有一个提案,使得块级作用域可以变为表达式,也就是说可以返回值,办法就是在块级作用域之前加上do,使它变为do表达式。

let x = do {  let t = f();  t * t + 1;};复制代码

上面代码中,变量x会得到整个块级作用域的返回值。

const 命令

const声明一个只读的常量。一旦声明,常量的值就不能改变。

const PI = 3.1415;PI // 3.1415PI = 3;// TypeError: Assignment to constant variable.复制代码

上面代码表明改变常量的值会报错。

const命令大致特点和let相似,不再一一列举

ES6 数组的扩展

Array.from()

这个方法是 Array 构造器的静态方法

作用:将把类数组对象转成真正的数组。

格式:

Array.from(类数组对象)Array.from(类数组对象,function(item,index){  return;//})复制代码

代码如下

var lis = document.getElementsByTagName("li")var rs  = Array.from(lis)console.log(Array.isArry(rs))//true复制代码

Array.of()

作用:将一组值转换为数组。与 Array.from 功能相似,理解用来创建数组。 主要目的是弥补构造器 Array()的不足

var arr1 = new Array.of(3)  //[3]var arr2 = new Array.of("3")//['3']复制代码

find 和 findIndex

find:用于找出第一个符合条件的数组元素。找不到则是 undefined 。注意,它是不会返回多 个,只找一个,找到了就返回。如果你要把所有的满足条件的数组元素素都找出来,你应该用filter()

findIndex:返回第一个符合条件的数组元素的索引。找不到则是-1;

格式:

arr.find(function(item,index){  return 条件;//})复制代码
var arr = [  {name:"zs1",score:90}  {name:"zs2",score:90}  {name:"zs3",score:90}]var rs = Array.find(item =>item.name=="zs1")// {name:"zs1",score:90}复制代码

includes

作用:判断元素是否在数组中存在。返回值是 true|false

代码如下:

var myarr = [1,2,3]myarr.includes(1)//truemyarr.includes(0)//flase复制代码

fill

作用:给数组填充指定值。fill方法用于空数组的初始化非常方便。已有数据会被覆盖。 fill 方法还可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置

格式:

arr.fill(值)arr.fill(值,起点,终点) 包括起点,不包括终点复制代码
var arr = new Array(5)arr.fill("*") //["*","*","*","*","*"]复制代码

数组的扩展运算符

功能:把数据结构转成数组。

代码如下:

var arr1 = [1,2,3]var arr2 = [...arr1] //[1,2,3]复制代码

函数的扩展

函数参数的默认值

基本用法

ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。

function log(x, y = 'World') {  console.log(x, y);}log('Hello') // Hello Worldlog('Hello', 'China') // Hello Chinalog('Hello', '') // Hello复制代码

箭头函数

ES6 允许使用“箭头”(=>)定义函数。

var f = v => v;复制代码

上面的箭头函数等同于:

var f = function(v) {  return v;};复制代码

如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。

var f = () => 5;// 等同于var f = function () { return 5 };var sum = (num1, num2) => num1 + num2;// 等同于var sum = function(num1, num2) {  return num1 + num2;};复制代码

箭头函数使得表达更加简洁。如果不用箭头函数,可能就要占用多行,而且还不如现在这样写醒目。

箭头函数的一个用处是简化回调函数。

// 正常函数写法[1,2,3].map(function (x) {  return x * x;});// 箭头函数写法[1,2,3].map(x => x * x);复制代码

注意

(1)函数体内的 this 对象,就是定义时所在的对象,而不是使用时所在的对象。

(2)不可以当作构造函数,也就是说,不可以使用 new 命令,否则会抛出一个错误。

(3)不可以使用 arguments 对象,该对象在函数体内不存在。如果要用,可以用 Rest 参数代替。

(4)不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数。

ES6 对象的扩展

属性的简洁表示法

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

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

上面代码表明,ES6允许在对象之中,直接写变量。这时,属性名为变量名, 属性值为变量的值。下面是另一个例子。

function f(x, y) {  return {x, y};}// 等同于function f(x, y) {  return {x: x, y: y};}f(1, 2) // Object {x: 1, y: 2}复制代码

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

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

()

比较两个值是否相等

Object.is(+0, -0) // falseObject.is(NaN, NaN) // true复制代码

Object.assign()

Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象

注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。

var str  = { a: 1, b: 1 };var str1 = { b: 2, c: 2 };var str2 = { c: 3 };Object.assign(str, str1, str2);str // {a:1, b:2, c:3}复制代码
var v1 = 'abc';var v2 = true;var v3 = 10;var obj = Object.assign({}, v1, v2, v3);console.log(obj); // { "0": "a", "1": "b", "2": "c" }复制代码

上面代码中,v1、v2、v3分别是字符串、布尔值和数值,结果只有字符串合入目标对象(以字符数组的形式),数值和布尔值都会被忽略。这是因为只有字符串的包装对象,会产生可枚举属性。

Object.getOwnProertyDescriptor();

获取一个对象中某个属性的详细信息。

var a = 1 console.log(object.getOwnProertyDescriptor(window,"a")复制代码

getOwnPropertyNames()

获取自的属性,以数组的格式返回的。

var obj = {    name:xiaoli    age:22}console.log(object.getOwnPropertyNames(obj))//["name","age"]复制代码

Object.keys()

var obj = {    name:xiaoli    age:22}console.log(object.keys(obj))//["name","age"]复制代码

使用Object.getOwnPropertyNames()和Object.keys()都可以得到一个对象的属性名,属性名是放在一个数组中的。

对于对象的遍历目前有三种方式:

for in

Object.keys()
Object.getOwnPropertyNames()

for in : 会输出自身以及原型链上可枚举的属性。

Object.keys() : 用来获取对象自身可枚举的属性键
Object.getOwnPropertyNames() : 用来获取对象自身的全部属性名

__proto__属性,Object.setPrototypeOf(),Object.getPrototypeOf()

(1)__proto__属性

隐式原型属性,用来设计对象的隐式原型

(2)Object.setPrototypeOf()

Object.setPrototypeOf方法的作用与__proto__相同,用来设置一个对象的prototype对象。它是ES6正式推荐的设置原型对象的方法。

// 格式Object.setPrototypeOf(object, prototype)// 用法var o = Object.setPrototypeOf({}, null);复制代码
let proto = {};let obj = { x: 10 };Object.setPrototypeOf(obj, proto);proto.y = 20;proto.z = 40;obj.x // 10obj.y // 20obj.z // 40复制代码

(3)Object.getPrototypeOf()

该方法与setPrototypeOf方法配套,用于读取一个对象的prototype对象。

Object.getPrototypeOf(obj);复制代码

ES6 变量的解构赋值

数组的解构赋值

基本用法

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

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

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

ES6 允许写成下面这样。

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

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

默认值

解构赋值允许指定默认值。

var [f = true] = [];f // true[x, y = 'b'] = ['a']; // x='a', y='b'[x, y = 'b'] = ['a', undefined]; // x='a', y='b'复制代码

注意,ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,如果一个数组成员不严格等于undefined,默认值是不会生效的。

对象的解构赋值

解构不仅可以用于数组,还可以用于对象。

var { f, b } = { f: "aaa", b: "bbb" };f // "aaa"b // "bbb"复制代码

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

var { b, f } = { f: "aaa", b: "bbb" };f // "aaa"b // "bbb"var { baz } = { f: "aaa", b: "bbb" };baz // undefined复制代码

字符串的解构赋值

字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。

const [a, b, c, d, e] = 'hello';a // "h"b // "e"c // "l"d // "l"e // "o"复制代码

类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值。

let {length : len} = 'hello';len // 5复制代码

函数参数的解构赋值

函数的参数也可以使用解构赋值。

function add([x, y]){  return x + y;}add([1, 2]); // 3复制代码

上面代码中,函数add的参数表面上是一个数组,但在传入参数的那一刻,数组参数就被解构成变量xy。对于函数内部的代码来说,它们能感受到的参数就是xy

ES6 字符串的扩展

repeat()

repeat方法返回一个新字符串,表示将原字符串重复n次。

'x'.repeat(3) // "xxx"'hello'.repeat(2) // "hellohello"'a'.repeat(0) // ""复制代码

参数如果是小数,会被取整。

'a'.repeat(2.9) // "aa"复制代码

如果repeat的参数是负数或者Infinity,会报错。

'na'.repeat(Infinity)// RangeError'na'.repeat(-1)// RangeError复制代码

trim()

除去字符串空格的。

trim 左右空格都是去掉

trimLeft 左空格去掉

trimRight 右空格去掉

var str       = "  ab ab abc  "str.trim      = "ab ab abc"str.trimLeft  = "ab ab abc  "str.trimRight = "  ab ab abc"复制代码

includes

var str = "abc"str.includes("a")//truestr.includes("e")//flase复制代码

startsWith

var str = "abc def"str.startsWith("abc")//truestr.startsWith("abcd")//false复制代码

padStart

var str = "abc def"str.padStart(15,"*")//"********abc def"复制代码

padEnd

var s = 4s.toFixed(2) "4.00"s.toFixed(2).padStart"04.00" 复制代码

模板字符串

传统的JavaScript语言,输出模板通常是这样写的。

$('#result').append(  'There are ' + basket.count + ' ' +  'items in your basket, ' +  '' + basket.onSale +  ' are on sale!');复制代码

上面这种写法相当繁琐不方便,ES6 引入了模板字符串解决这个问题。

$('#result').append(`  There are ${basket.count} items   in your basket, ${basket.onSale}  are on sale!`);复制代码

模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。

模板字符串中嵌入变量,需要将变量名写在${}之中。

function authorize(user, action) {  if (!user.hasPrivilege(action)) {    throw new Error(      // 传统写法为      // 'User '      // + user.name      // + ' is not authorized to do '      // + action      // + '.'      `User ${user.name} is not authorized to do ${action}.`);  }}复制代码

ES6 数值的扩展

Number.parseInt(), Number.parseFloat()

ES6 将全局方法parseInt()parseFloat(),移植到Number对象上面,行为完全保持不变。

// ES5的写法parseInt('12.34') // 12parseFloat('123.45#') // 123.45// ES6的写法Number.parseInt('12.34') // 12Number.parseFloat('123.45#') // 123.45复制代码

这样做的目的,是逐步减少全局性方法,使得语言逐步模块化。

Number.isInteger()

Number.isInteger()用来判断一个值是否为整数。需要注意的是,在JavaScript内部,整数和浮点数是同样的储存方法,所以 3 和 3.0 被视为同一个值。

Number.isInteger(25) // trueNumber.isInteger(25.0) // trueNumber.isInteger(25.1) // falseNumber.isInteger("15") // falseNumber.isInteger(true) // false复制代码

Number.EPSILON

ES6 在Number对象上面,新增一个极小的常量Number.EPSILON

Number.EPSILON// 2.220446049250313e-16Number.EPSILON.toFixed(20)// '0.00000000000000022204'复制代码

引入一个这么小的量的目的,在于为浮点数计算,设置一个误差范围。我们知道浮点数计算是不精确的。

Math 对象的扩展

ES6 在Math对象上新增了 17 个与数学相关的方法。所有这些方法都是静态方法,只能在 Math 对象上调用。

Math.trunc()

Math.trunc方法用于去除一个数的小数部分,返回整数部分。

Math.trunc(4.1) // 4Math.trunc(4.9) // 4Math.trunc(-4.1) // -4Math.trunc(-4.9) // -4Math.trunc(-0.1234) // -0复制代码

Math.cbrt()

Math.cbrt方法用于计算一个数的立方根。

Math.cbrt(-1) // -1Math.cbrt(0)  // 0Math.cbrt(1)  // 1Math.cbrt(2)  // 1.2599210498948734复制代码

Math.clz32()

JavaScript 的整数使用 32 位二进制形式表示,Math.clz32方法返回一个数的 32 位无符号整数形式有多少个前导 0。

Math.clz32(0) // 32Math.clz32(1) // 31Math.clz32(1000) // 22Math.clz32(0b01000000000000000000000000000000) // 1Math.clz32(0b00100000000000000000000000000000) // 2复制代码

Math.imul()

Math.imul方法返回两个数以 32 位带符号整数形式相乘的结果,返回的也是一个 32 位的带符号整数。

Math.imul(2, 4)   // 8Math.imul(-1, 8)  // -8Math.imul(-2, -2) // 4复制代码

Math.fround()

Math.fround方法返回一个数的单精度浮点数形式。

Math.fround(1.337) // 1.3370000123977661复制代码

对于整数来说,Math.fround 方法返回结果不会有任何不同,区别主要是那些无法用 64 个二进制位精确表示的小数。这时,Math.fround 方法会返回最接近这个小数的单精度浮点数。

Math.hypot()

Math.hypot方法返回所有参数的平方和的平方根。

Math.hypot(3, 4);        // 5Math.hypot(3, 4, 5);     // 7.0710678118654755Math.hypot();            // 0Math.hypot(NaN);         // NaNMath.hypot(3, 4, 'foo'); // NaNMath.hypot(3, 4, '5');   // 7.0710678118654755Math.hypot(-3);          // 3复制代码

上面代码中,3 的平方加上 4 的平方,等于 5 的平方。

如果参数不是数值,Math.hypot 方法会将其转为数值。只要有一个参数无法转为数值,就会返回 NaN。

ES6 set和map数据结构

Set 基本用法 ES6提供了新的数据结构Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。

Set本身是一个构造函数,用来生成Set数据结构。

var s = new Set();[2, 3, 5, 4, 5, 2, 2].map(x => s.add(x));for (let i of s) {  console.log(i);}// 2 3 5 4复制代码

上面代码通过add方法向Set结构加入成员,结果表明Set结构不会添加重复的值。

Set函数可以接受一个数组(或类似数组的对象)作为参数,用来初始化。

// 例一var set = new Set([1, 2, 3, 4, 4]);[...set]// [1, 2, 3, 4]// 例二var items = new Set([1, 2, 3, 4, 5, 5, 5, 5]);items.size // 5// 例三function divs () {  return [...document.querySelectorAll('div')];}var set = new Set(divs());set.size // 56// 类似于divs().forEach(div => set.add(div));set.size // 56复制代码

上面代码中,例一和例二都是Set函数接受数组作为参数,例三是接受类似数组的对象作为参数。

// 去除数组的重复成员[...new Set(array)]复制代码

class

从形式上,向主流的面向对象的语言靠拢。

我们之前写对象方式可以用 Class 用进行优化

前面我们都是创建构造器,然后去new构造器,构造器就相当于一个类,在ES6中,就可以使用class来创建对象了。

1,class创建对象 格式:

class 类名{    constructor(参数){        this.属性 = 参数;    }    method(){            }}复制代码

注意:

1.class 是关键字,后面紧跟类名,类名首字母大写,采取的是大驼峰命名法则。类名之后是

2.在{}中,不能直接写语句,只能写方法,方法不需要使用关键字

3.方法和方法之间没有逗号。不是键值对

class NBAPlayer{    constructor(name,age,height){        this.name = name;        this.age = age;        this.height = height;    }    say(){        console.log("`我是${this.name},我今年${this.age}岁,身高${this.height}`")    }    }var p1 = new NBAPlayer("库里","25","190")复制代码

使用extends实现继承

格式:

class 子类 extend 父类 {    constructor (参数){        super(参数)        this.属性=值    }}复制代码

注意:

使用 extends 关键字来实现继承,在子类中的构造器 constructor 中,必须要显式调用父类的 super 方法,如果不调用,则 this 不可用

class NBAPlayer{    constructor(name,age,height){        this.name = name;        this.age = age;        this.height = height;    }    say(){        console.log("`我是${this.name},我今年${this.age}岁,身高${this.height}`")    }    }class MVP extends NBAPlayer{    constructor(name,age,height,year){        super(name,age,height)        this.year = year;    }     showMvp(){        console.log("`我是${this.name},是${this.year}年的MVP`")    }    }var p1 = new MVP("库里","25","190",2016)复制代码

类的静态方法 static

直接通过类名来访问的方法就是静态方法。如:Math.abs();这里的 abs()是静态方法。 Array.isArray();isArray()是静态方法. 在方法名前加 static 就可以了

后记

花一天的时间总结了阮一峰老师的《es6 入门》,其中还是有很多不懂的地方,还要继续学习。

转载于:https://juejin.im/post/5b6e3f5ce51d45348813cbb0

你可能感兴趣的文章
实例讲解JQuery中this和$(this)区别
查看>>
centos 7 静态ip地址模板
查看>>
影响系统性能的20个瓶颈
查看>>
shell的详细介绍和编程(上)
查看>>
软件开发性能优化经验总结
查看>>
面试题编程题05-python 有一个无序数组,如何获取第K 大的数,说下思路,实现后的时间复杂度?...
查看>>
kendo grid序号显示
查看>>
Spring 教程(二) 体系结构
查看>>
Indexes
查看>>
2.Web中使用iReport 整合----------创建html格式的
查看>>
异常备忘:java.lang.UnsupportedClassVersionError: Bad version number in .class file
查看>>
最全三大框架整合(使用映射)——applicationContext.xml里面的配置
查看>>
初步理解Java的三大特性——封装、继承和多态
查看>>
知识点积累(一)
查看>>
iphone-common-codes-ccteam源代码 CCFile.m
查看>>
python:浅析python 中__name__ = '__main__' 的作用
查看>>
修改tomcat端口后不能IP访问问题
查看>>
review board
查看>>
URAL 1495 One-two, One-two 2
查看>>
牛客国庆集训派对Day3 G Stones
查看>>