ES6的新特性:

  1. 变量
  2. 函数
  3. 数组
  4. 字符串
  5. 面向对象
  6. Promise
  7. generator
  8. 模块化

解决兼容性

  • 在线转换:使用相关库进行转换,每次用户加载的时候进行实时转换

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <head>
    <title></title>
    <!-— brower.js 就是babel.js的别名 -->
    <script src="browser.js" charset="utf-8"></script>
    <script type="text/babel">
    let a = 12;
    let b = 14;
    alert(a + b)
    </script>
    </head>
  • 提前编译

let和const

var的弊端

  1. 可以重复声明

    1
    2
    3
    4
    var a = 2
    var a = 3 // 注意不是 a = 3;a = 3是重新赋值

    alert(a) // 3
  2. 无法限制修改:没有常量定义

  3. 没有块级作用域:var是全局作用域

    1
    2
    3
    4
    if (true) {
    var a = 2
    }
    alert(a) // 2

let和const的特性

  1. 不能重复声明
  2. 限制修改
  3. 块级作用域

箭头函数

  1. 如果函数只有一个参数,()可以参略
  2. 如果函数的函数体只有一行return,{}可以省略

函数参数

  1. 参数扩展(Rest Parameter)

    • 就是python里的可变参数
    • 和python一样,args必须是最后一个参数
    1
    2
    3
    4
    def show(a, b, *args):
    print(a)
    print(b)
    print(args)
    1
    2
    3
    4
    5
    const show = (a, b, ...args) => {
    console.log(a)
    console.log(b)
    console.log(args)
    }
  2. 数组展开

    • 和python的元祖拆包一摸一样
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    const show = (a, b ,c) => {
    alert(a)
    alert(b)
    alert(c)
    }

    const arr = [1, 2, 3]

    show(1,2,3)
    // 上一行等价于
    show(...arr)
  3. 默认参数

    • 和python的默认参数一摸一样
    1
    2
    3
    const show = (a, b=2, c=5) => {
    console.log(a, b, c)
    }

解构赋值

和python的元祖赋值一摸一样,但是js的解构赋值更加智能:

  1. 左右两边的结构必须一样
  2. 声明和赋值不能分开
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let arr = [1, 2, 3]

let a = arr[0]
let b = arr[1]
let c = arr[2]

// 等价于
let [a, b, c] = [1, 2, 3]

// python只能拆包元祖,但是js还可以解构其他对象
let {a, b, c} = {a:12, b:5, c=90}

// 解构复杂对象
let [(a, b), [n1, n2, n3], num, str] = [{a:12, b:5}, [12, 5, 7], 8, "qwe"]
let [json, arr, num, str] = [{a:12, b:5}, [12, 5, 7], 8, "qwe"]

解构JS对象

1
2
3
4
5
6
7
8
9
10
11
12
const myfunc = ({name}) => {
console.log(name)
}

class User {
constructor(name) {
this.name = name
}
}

let u = new User("hyl")
myfunc(u) // hyl

组数的四个方法

  • map
  • reduce:相比于python,多了一个第三参数(index)
  • filter
  • forEach
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let arr = [1,2,3]

// map
let res1 = arr.map(item => item*2)

// reduce
let res2 = arr.reduce((a, b, index) => a+b)

// filter
let res3 = arr.filter(item => item % 2 === 0)

// forEach
let res4 = arr.forEach((item, index) => {
alert(index + " " + item )
})

字符串模版和字符串的两个方法

字符串的两个方法:

  • startsWith
  • endsWith
1
2
let mystr = "qwe123"
alert(mystr.startsWith("qwe"))

字符串模版:

1
2
let a = 12
let mystr = `my num is ${a}`

面向对象

class关键字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// JS传统面向对象
function User(name, psw) {
this.name = name
this.psw = psw
}

User.prototype.showName = function(){
alert(this.name)
}

// 使用class
class User {
constructor(name, psw){
this.name = name
this.psw = psw
}

showName(){
alert(this.name)
}
}

继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// JS传统继承
function User(name, psw) {
this.name = name
this.psw = psw
}

User.prototype.showName = function() {
alert(this.name)
}

function VIPUser(name, psw, VIPlevel) {
User.call(this, name, psw)
this.VIPlevel = VIPlevel
}

VipUser.prototype = new User()
VipUser.prototype.contructor = VipUser

VIPUser.prototype.showLevel = function() {
alert(this.level)
}

var v1 = VipUser("hyl", "123456", 3)
v1.showName()
v1.showLevel()

// 使用class的extends关键字
class VipUser extends User {
constructor(name, psw, level) {
super(name, psw)
this.level = level
}

showLevel(){
alert(this.level)
}
}

this

  • constructor里面的this指向实例对象,方法里面的this指向这个方法的调用者
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Star {
constructor(name, age) {
this.name = name
this.age = age

this.btn = document.querySelector("button")
this.btn.onCilck = this.sing
}

sing() {
// 这个sing方法里面的this指向的是btn这个按钮,因为是这个按钮调用了这个函数(当用户click的时候触发btn的onClick函数)
console.log(this.name)
}

dance() {
// 这个dance里面的this指向的是实例对象,因为是实例对象调用了这个方法
console.log(this.name)
}
}

配合React使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<head>
<title></title>
<script src="react.js" charset="utf=8"></script>
<script src="react-dom.js" charset="utf=8"></script>
<script src="brower.js" charset="utf=8"></script>

<script type="text/babel">
class Item extends React.Component{
constructor(...args){
super(args)
}

render(){
return <li>{this.props.msg}</li>
}
}

class List extends React.Component {
constructor(...args){
super(args)
}

render() {
return <ul>{this.props.arr.map(item => <Item msg="{item}"></Item>)}</ul>
}
}

window.onload = function() {
ReactDom.render(
<List arr={['fitstItem','SecondItem','ThirdItem']}></List>,
document.getElementById("div1")
)
}
</script>
</head>

<body>
<div id="div1">
</div>
</body>

json

  1. JSON对象的序列化方法和反序列化方法
  2. json简写
    • 名字一样时的简写
    • 方法的简写

JSON对象的序列化方法和反序列化方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let json = {a:12, b:5}

// 序列化
const res1 = JSON.stringify(json)
alert(res1) // {a:12, b:5}

// 反序列化
let mystr = '{"a":12, "b":5}'
const res2 = JSON.parse(mystr)
alert(res2) // Object{a:12, b:5}

// encodeURIComponent函数
const res3 = "http://baidu.com?" + encodeURIComponent(JSON.stringify(json))
alert(res3) // http://baidu.com?a=12&b=5

简写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
let a = 12
let b = 5

// 值和键相同时的传统写法
let json = {a:a, b:b}
console.log(json)

// 值和键相同时可以简写
let json = {a, b, c:22}


// json方法的传统写法
let json = {
a: 12,

show: function(){
alert(this.a)
}
}

// json方法的简写
let json = {
a: 12,
show(){
alert(this.a)
}
}

Promise

  • 以同步的方式编写异步代码

简单使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
let p = new Promise(function(resovle, reject){
// 异步代码
// resovle:成功时的回调函数;
// reject:失败时的回调函数;
$.Ajax({
url:"http://baidu.com",
dateType:"json",
success(data){
resovle();
},
error(err){
reject(err);
}
})
})

// then:当promise有结果了(成功或失败)时,执行某些函数,第一个为成功时执行的函数,第二个为失败时执行的函数
p.then(function(data){
alert("成功了")
},function(err){
alert("失败了")
})

多个promise对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
let p1 = new Promise(function(resovle, reject){
$.Ajax({
url:"http://baidu.com",
dateType:"json",
success(data){
resovle();
},
error(err){
reject(err);
}
})
})

let p2 = new Promise(function(resovle, reject){
$.Ajax({
url:"http://taobao.com",
dateType:"json",
success(data){
resovle();
},
error(err){
reject(err);
}
})
})

Promise.all([
p1,p2
]).then(function(data){
alert("p1和p2都成功了")
},function(err){
alert("至少有一个失败了")
})

进一步简化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const createPromise = (url) => {
return new Promise(function(resovle, reject){
$.Ajax({
url,
dateType:"json",
success(data){
resovle();
},
error(err){
reject(err);
}
})
})
}

Promise.all([
createPromise('http://baidu.com'),
createPromise("htpp://taobao.com")
]).then(function(data){
alert("p1和p2都成功了")
},function(err){
alert("至少有一个失败了")
})

其实,对于高版本的JQuery来说,$.Ajax()的返回值就是Promise对象

1
2
3
4
5
6
7
8
Promise.all([
$.Ajax({url:"http://baidu.com",dataType:"json"}),
$.Ajax({url:"http://taobao.com",dataType:"json"}),
]).then(results => {
alert("全部成功了")
},err => {
alert("至少有一个失败了")
})

Promise对象的其他方法

  • all():全部都执行
  • race():竞速,就是都是发出多个请求,哪一个先执行完毕就哪一个执行then函数,其余的放弃
1
2
3
4
5
6
7
8
// 同时请求m1-m4,哪个最先成功了就处理哪个,其余放弃
// 特别适用于爬虫
Promise.race([
$.Ajax(url:"http://m1.taobao.com/users"),
$.Ajax(url:"http://m2.taobao.com/users"),
$.Ajax(url:"http://m3.taobao.com/users"),
$.Ajax(url:"http://m4.taobao.com/users"),
]).then()

generator

  • 和python的生成器一摸一样
1
2
3
4
5
6
7
8
9
function *show(){
alert("A")
yield;
alert("B")
}

let genObj = show()
genObj.next() // A
genObj.next() // B

yield

  • 和python一样,既可以传参,也可以返回
1
2
3
4
5
6
7
8
9
10
11
12
function *show(){
alert("A")
let a = yield;
alert(a)
}

let genObj = show()
genObj.next() // 激活生成器
genObj.next(5)

// A
// 5

ES6的yield返回值和python些许不同,ES6返回的是对象,包含done属性

1
2
3
4
5
6
7
8
9
10
11
12
13
function *show() {
alert("A")
yield 12;
alert("B")
return 5
}

let genObj = show()
let res1 = gen.next()
console.log(res1) // {value:12, done:false}

let res2 = gen.next()
console.log(res2) // {value:5, done:true}

yield使用

  • 和python的ascync和await一摸一样
1
2
3
4
5
6
7
8
9
// runner是runner.js的函数
runner(function *(){
// 当执行$.ajax的时候切换程序执行权
let data1 = yield $.ajax(url:"http://baidu.com",dateType:"json")
let data2 = yield $.ajax(url:"http://taobai.com",dateType:"json")
let data3 = yield $.ajax(url:"http://tencent.com",dateType:"json")
})

console.log(data1,data2,data3)

async和await使用

1
2
3
4
5
6
7
8
9
10
// 上面代码可以改成async和await关键字
async function ReadData() {
let data1 = await $.ajax("http://baidu.com", dataType:"json")
let data2 = await $.ajax("http://taobao.com", dataType:"json")
let data3 = await $.ajax("http://tencent.com", dataType:"json")

console.log(data1, data2, data3)
}

ReadData()

还可以使用箭头函数:

1
2
3
4
5
6
7
8
9
10
// 上面代码可以改成async和await关键字
const ReadData = async () => {
let data1 = await $.ajax("http://baidu.com", dataType:"json")
let data2 = await $.ajax("http://taobao.com", dataType:"json")
let data3 = await $.ajax("http://tencent.com", dataType:"json")

console.log(data1, data2, data3)
}

ReadData()

模块化之export和import的用法

ES6中export和import一般的用法有两种

  • 命名导出(Named exports)
  • 默认导出(Default exports)

命名导出(Named exports)

  • 每一个需要导出的数据类型都要有一个name,统一引入一定要带有{},即便只有一个需要导出的数据类型。
  • 这种写法清爽直观,是推荐的写法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//------ lib.js ------
const sqrt = Math.sqrt;
function square(x) {
return x * x;
}
function diag(x, y) {
return sqrt(square(x) + square(y));
}

export {sqrt, square, diag}

//------ main.js ------
import { square, diag } from 'lib';
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5

把export直接加到声明前面就可以省略{}

1
2
3
4
5
6
7
8
9
10
11
12
13
//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
return x * x;
}
export function diag(x, y) {
return sqrt(square(x) + square(y));
}

//------ main.js ------
import { square, diag } from 'lib';
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5

无论怎样导出,引入的时候都需要{}

别名引入(Aliasing named imports)

当从不同模块引入的变量名相同的时候,这些写法显然会造成混乱

1
2
3
4
5
6
import {speak} from './cow.js'
import {speak} from './goat.js'

// 正确的方法
import {speak as cowSpeak} from './cow.js'
import {speak as goatSpeak} from './goat.js'

命名空间引入(Namespace imports)

1
2
3
4
5
import * as cow from './cow.js'
import * as goat from './goat.js'

cow.speak() // moo
goat.speak() // baa

默认导出(Default exports)

默认导出就不需要name了,但是一个js文件中只能有一个export default

1
2
3
4
5
6
//------ myFunc.js ------
export default function () { ... };

//------ main1.js ------
import myFunc from 'myFunc';
myFunc();

其实这种导出方式可以看成是命名导出的变种,只不过把命名写成了default。

虽然export default只能有一个,但也可以导出多个方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
export default {
speak () {
return 'moo'
},
eat () {
return 'cow eats'
},
drink () {
return 'cow drinks'
}
}

// 引入与命名空间引入类似:
import cow from './default-cow.js'
import goat from './default-goat.js'

cow.speak() // moo
goat.speak() // baa