玩转ES6新特性

编程语言是向后兼容的,相对于ES5,ES6增加了一些新的特性,下面简单介绍一些

  • let 和 const 命令

  • 变量的解构赋值

  • 模板字符串

  • 数组新增的方法

  • 字符串新增的方法

  • class创建对象以及继承

  • 箭头函数

  • Set 和 Map


1. let 和 const 命令

首先我们要知道这两个命令是用来做什么的:
let:定义一个变量;
const:定义一个常量。
在ES6之前我们定义一个变量使用的是关键字var,那么有人会说ES6这样是不是多此一举呢?
当然不是,各有各的特点不能说谁一定好,要根据适应的环境来使用。它们的主要不同就是变量提升作用域。下面我们通过代码来具体感受一下。

变量提升

我们来看下面的代码来看一下var和let定义的变量。

console.log(b); //undefined
var b = 100;
复制代码

根据上面的代码,我们知道浏览器的js引擎线程是根据代码结构执行的,那么在执行的时候打印出来的应该是not defined,为什么是undefined?undefined是一个基本数据类型,是在我们定义了这个变量没有赋值的情况下才会打印出来。那么这里就存在一个我们在ES5中说的变量提升。什么是变量提升?变量提升可以分两个步骤:1、定义。2、执行。也就是说在代码开始执行的时候浏览器会先检测整个代码,将定义部分提前,然后再去完成执行部分。所以上面代码的实际运行:如下:

var b;
console.log(b);
b = 100;
复制代码

如果我们使用let来定义呢?

console.log(b)    //b is not defined
let b = 100
复制代码

打印出来 b is not defined,说明并没有之前的变量提升,这里严格按照先定义后执行的顺序。

作用域

变量或者函数都有自己的作用域。在ES6中新增了一个新的概念:块级作用域
在这之前只用全局作用域以及局部作用域。根据函数来区分,定义在函数里面的变量的作用域叫做局部作用域,定义在全局的变量叫做全局作用域。
那么块级作用域怎么区别呢?

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

上面的代码就是一个块级作用域,我们通过{}来区别。一个{}就是一个作用域。 下面我们来看一段代码来区别一下let 和 var 定义的变量的作用域。

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

我们希望的是a[0]()能够输出 0a[1]()能够输出 1,a[2]()能够输出 2,上面代码中,变量i只用来控制循环,但是循环结束后,它并没有消失,泄露成了全局变量也就是这个i会一直存在。这是我们很不希望见到的。

//代码二
    let a = []
     for(let i  = 0; i < 3; i ++ ){
         a[i] = function(){
             console.log(i)
         }
     }
     a[0]();   //0
     a[1]();   //1
     a[2]();   //2
复制代码

上面的代码很好理解,for循环下面是一个{}代码块,也就相当于一个作用域,每一个作用域里面的i值互不影响。画图理解一下两段代码。

在代码一中,使用var定义的i,当for循环执行完毕,i的值也随着变化,最后的i值等于3 那么之前a[i]中的i值也会变化.但是代码二使用let定义的i会在{ }中形成自己的作用域,不会因为父作用域数值的改变去改变自己本身的值,所以可以按照需求输出。

当然在块级作用域下使用函数声明定义的函数还是会提升的,这点要注意,不能混淆。

const

const 是用来定义一个常量,它的作用域和let是一样的,但是他们的区别在于,let可以先定义变量,在使用的过程中赋值,而const必须在定义的同时赋值,不能二次赋值。 如下:

//正确的用法
const p = 3.1;
console。log(p) //3.1
复制代码
//错误的用法
const a;
a = 2;
console.log(a) //
//Missing initializer in const declaration       
复制代码

如果是引用性数据类型的话,const定义的常量存储的是内存地址。这点要记住。

2. 变量的解构赋值

什么是解构赋值,简单点理解就是一次性给多个变量赋值。

平时我们赋值的时候一般是这样的

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

这样赋值没问题但是却增加了代码量,在ES6中允许

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

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

本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。下面是一些使用嵌套数组进行解构的例子。

let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3

let [ , , third] = ["foo", "bar", "baz"];
third // "baz"

let [x, , y] = [1, 2, 3];
x // 1
y // 3

let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]

let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []

复制代码

如果解构不成功,变量的值就等于undefined。

let [foo] = [];
let [bar, foo] = [1];
复制代码

左右结构要一一对应

let [x, y] = [1, 2, 3];
x // 1
y // 2

let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4
复制代码

可以设置默认值,如果后面继续赋值的话会被覆盖掉。

let [a,b=2] = [1]
a //1
b //2
let [c,d = 3] = [1,5]
c //1
d //5
复制代码
给对象解构赋值

对象是一个无序的属性集合,所以在给对象解构赋值的时候要和属性名字一一对应。

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

变量之间的赋值

let [x = 1, y = x] = [];     //x=1, y=1
let [x = y, y = ] = [];      //报错
复制代码

上面的代码提示我们变量之间互相赋值的时候,赋值的变量必须是已经定义好的。 一个小的应用变量直间相互赋值的特性一个小的敲门

//将x,y的值调换
let x = 1;
let y = 2;
[x,y] = [y,x]
复制代码

字符串之间的赋值

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
复制代码

总而言之,在使用解构赋值的时候一定要一一对照

3. 模板字符串

模板字符串使用反引号 () 来代替普通字符串中的用双引号和单引号。模板字符串可以包含特定语法(${})的占位符

let obj = {
    name : "xiaoxiao",
    age  : 15
}
console.log(`我叫${obj.name}今年${obj.age}岁了`)
复制代码

4. 数组新增的方法

Array.isArray()

作用:判断是否是数组

let arr = [1,2,3]
console.log(Array.isArray(arr))    //true
复制代码
Array.from()

这个方法是Array构造器的静态方法,作用:将类数组对象转化成真正的数组

let obj = "hello"
console.log(Array.isArray(obj))   //false
let arr = Array.from(obj)         //[ 'h', 'e', 'l', 'l', 'o' ]
console.log(arr)
console.log(Array.isArray(arr))   //true

复制代码
Array.of()

作用:将一组值转换为数组

let arr1 = Array.of(3)
let arr2 = Array.of("3")
let arr3 = Array.of(1,2,3)
console.log(arr1,arr2,arr3)  //[ 3 ] [ '3' ] [ 1, 2, 3 ]
复制代码
find和findlndex

find:用于找出第一个符合条件的数组元素。找不到则是 undefined ;只要找到一个就会终止。如果需要全部找出来需要用filter();

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

和indexof有异曲同工之妙,indexOf返回的是索引


let arr = [4,3,2,1]
let rs = arr.find(function(item,index){

    return item ==2;
})
let rt = arr.findIndex(function(item,index){
    return item == 3
})
console.log(rs)    //2
console.log(rt) //1
复制代码

indexOf

//indexof
let arr = [1,2,6,8]
console.log(arr.indexOf(6))   //2
复制代码
includes

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

let arr = [1,2,6,8]
console.log(arr.includes(6))   //true
复制代码
fill

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

let arr1 = new Array(5)
arr1.fill("*")
console.log(arr1)    //[ '*', '*', '*', '*', '*' ]
//覆盖原有数据
let arr2 = [1,2,3]
arr2.fill("*")
console.log(arr2)  //[ '*', '*', '*' ]
复制代码
数组的扩展运算符

功能:把数据结构转成数组。和Array.from()的功能相似

let arr = "hello"
let arr2 = [...arr]
console.log(arr2)    //[ 'h', 'e', 'l', 'l', 'o' ]
console.log(Array.isArray(arr2))  //true

复制代码

扩展运算符链接数组

let arr1 = [1,2]
let arr2 = [3,4]
let arr = [...arr1,...arr2]
console.log(arr)    [ 1, 2, 3, 4 ]
复制代码

注意:在使用扩展运算符的时候必须要用容器将其包括起来。

map

获取一个新的数组

//将成绩加10并返回
let arr = [
    {name:"aa",score:11},
    {name:"bb",score:22},
    {name:"cc",score:22},
    {name:"dd",score:52},
    {name:"ee",score:45},
    {name:"ff",score:34},
    {name:"gg",score:77},
    {name:"hh",score:88},
]

let rs = arr.map((item,index,arr) => {
    return item.score += 10 
})
// let rs =arr.map((item,index,arr) => {
//     return arr

// })

console.log(rs)   //[ 21, 32, 32, 62, 55, 44, 87, 98 ]
复制代码

5. 字符串新增的方法

includes(),startWith(),endsWith()

includes():返回布尔值,表示是否找到了参数字符串。
startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。。
endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。。

 let s = 'Hello world!';

s.startsWith('Hello') // true
s.endsWith('!') // true
s.includes('o') // true

复制代码

这三个方法都支持第二个参数,表示开始搜索的位置。

let s = 'Hello world!';

s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false
复制代码

上面代码表示,使用第二个参数n时, endsWith的行为与其他两个方法有所不同。 它针对前n个字符,而其他两个方法针对从第n个位置直到字符串结束。

repeat()

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

'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // ""

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

'na'.repeat(2.9) // "nana"
复制代码
padStart(),padEnd()

padStart()用于头部补全,padEnd()用于尾部补全。

'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab'
复制代码

上面代码中,padStart和padEnd一共接受两个参数,第一个参数用来指定字符串的最小长度,第二个参数是用来补全的字符串。

如果原字符串的长度,等于或大于指定的最小长度,则返回原字符串。

'xxx'.padStart(2, 'ab') // 'xxx'
'xxx'.padEnd(2, 'ab') // 'xxx'
复制代码

如果用来补全的字符串与原字符串,两者的长度之和超过了指定的最小长度,则会截去超出位数的补全字符串。

'abc'.padStart(10, '0123456789')
// '0123456abc'
复制代码

如果省略第二个参数,默认使用空格补全长度。

'x'.padStart(4) // '   x'
'x'.padEnd(4) // 'x   '
复制代码

padStart的常见用途是为数值补全指定位数。下面代码生成 10 位的数值字符串。

'1'.padStart(10, '0') // "0000000001"
'12'.padStart(10, '0') // "0000000012"
'123456'.padStart(10, '0') // "0000123456"
复制代码

另一个用途是提示字符串格式。


'12'.padStart(10, 'YYYY-MM-DD') // "YYYY-MM-12"
'09-12'.padStart(10, 'YYYY-MM-DD') // "YYYY-09-12"
复制代码

6. class创建对象以及继承

我们我们创建一个对象有一下几种方法

字面量方法 工厂模式方法 构造器方法 class创建一个对象 这里重点说一下class创建一个对象。 关键字class可以定义一个类,我们通过这个类可以创建一个对象。
class Num{
    constructor(name){
        this.name = name
    }
    say(){
        console.log(`我是${this.name}`)
    }
}


let ra = new Num("小强")
ra.say()        //我是小强
复制代码

也就是说我们可以直接通过一个类来直接new一个对象。
注意:

class 是关键字,后面紧跟类名,类名首字母大写,采取的是大驼峰命名法则。类名之后是{}。
在{}中,不能直接写语句,只能写方法,方法不需要使用关键字
方法和方法之间没有逗号。不是键值对

下面就是我们在做项目的时候所必须的--继承。
根据需求的不同我们所需要的对象的属性或者方法也可能不同,或者多点属性或者方法,难道我们需要将之前所写的属性在重新写一次吗?如果需要100个对象,每一个对象都多一个属性或者方法呢?这时候我们就用到了--继承,让子类继承父类的方法和属性的同时还可以有自己的属性和方法。这也是我们现在最常用的创建对象的方式。

继承

格式:

下面使用一个小案例,更进一步的了解一下。
定义一个NBAplayer类,然后让mvp这个类继承NBAplayer,可以可以使用父类的方法


    class NBAplayer{
        constructor(name,age,height){
            this.name = name
            this.age = age
            this.height = height

        }
        say(){
            alert(`姓名${this.name}年龄${this.age}身高${this.height}`)
        }
        static jump(){   //静态方法    只能使用类名去掉用。
            alert("我是静态函数。。。。。对象无法调用")
        }
    }
    


    class mvp extends NBAplayer{
        constructor(name,age,height,year){
            super(name,age,height)
            this.year = year
        }
        showmvp(){
            alert(`我是${this.year}年的mvp`)
        }

    }

    let r2 = new mvp("xiaong",15,5,2222)
    // r2.say();     //正常执行
    // r2.showmvp()  //正常执行
    // NBAplayer.jump()     //调用静态函数。
    mvp.jump()   
复制代码

在继承的时候有两点要注意:

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

7. 箭头函数

箭头函数只是一个函数的简写,在做项目的时候这个可以很大程度降低代码量

//没有参数的时候
function f(){console.log("....")} //写为箭头函数
var f1 = () => {console.log("....")}

var x = 10,y = 11;
//有一个参数x
var f2 = x => {console.log(x+x)}

//有两个参数及以上的时候必须加括号
var f3 = (x,y) => {console.log(x+y)}

f1()      //.......
f2(x)      //20
f3(x,y)    //21
复制代码

要注意的是使用箭头函数的时候不能使用this,这两个老死不相往来。

8. Set 和 Map

Set

set和数组差不多但不是数组,它是一种集合,它和数组的区别在于:set里面的值都是唯一的,没有重复的。 看下面一段代码:在放入基本数据类型的时候需要使用[]包起来

let arr = [1,1,1,2,5,5,6,9]
let s1 = new Set([1,1,1,2,5,5,6,9])
console.log(arr)  //[ 1, 1, 1, 2, 5, 5, 6, 9 ]
console.log(s1)  //Set { 1, 2, 5, 6, 9 }
console.log(Array.isArray(s1))  //false

复制代码

上面的代码我们很容易的看出来Set不是数组,只是一个类数组,那么我们可以使用之前的知识将其转化为数组

let r2 = [...s1]
console.log(r2)    //[ 1, 2, 5, 6, 9 ]
console.log(Array.isArray(r2))  //true
复制代码

在创建set的时候如果要放入对象需要使用add()方法

let s1 = new Set();
s1.add({name:"ddd"})
s1.add({age:15})
s1.add({year:2018})
for(let item of s1){
    console.log(item)
}
复制代码

根据set里面数据的唯一性可以做一个小的案例---数组

let arr = [1,2,5,45,9,NaN,true,NaN]
let rs = [...(new Set(arr))]
console.log(rs)    //[ 1, 2, 5, 45, 9, NaN, true ]

复制代码
Map

它类似于对象,里面存放也是键值对,区别在于:对象中的键名只能是字符串,但是使用map,它里面的键可以是任意值。

创建一个Map

let m = new Map([
["name","xiaoming"],
["age","16"]
])
m.set(false,"sss")
m.set([],"a")
console.log(m)     //Map { 'name' => 'xiaoming', 'age' => '16', false => 'sss', [] => 'a' }

复制代码

那么很好理解Map是一个强大的类数组,我们可以通过扩展运算符将其转换为数组,然后进行数据的处理等等。 Set和Map都可以转换为数组,需要注意的是它们的各自的添加元素的方法。

 

 

ES6的特性还有很多,这里只是简单的介绍了几种我们比较常见的,如果大家在开发的过程中有什么新的东西,多多留言.

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值