ECMAScript 6.0简介 #

ECMAScript 6.0我们简称ES6,ES6的第一个版本是在2015年6月进行发布,所以我们把它称为《ECMAScript 2015 标准》(简称 ES2015)
JavaScript是ECMAScript的一种实现,也就是说JavaScript是遵循ECMAScript标准的。现在主流浏览器已经可以完美使用ES6。

http://babeljs.io/repl

1.let 和 const #

ES6新增了let和const来声明变量,来解决以前var声明变量所出现的问题。

1.1 重复定义变量 #

let name = 'zfpx';
let name = 'zfpx'; // Identifier 'name' has already been declared

let和const都不支持在同一个作用域下重复定义变量

1.2 不存在变量提升 #

console.log(name);
let name = 'zfpx';// ReferenceError: name is not defined

在使用name变量时需要先定义才能进行使用

1.3 块级作用域 #

在用var定义变量的时候,变量是通过闭包进行隔离的,现在用了let,不仅仅可以通过闭包隔离,还增加了一些块级作用域隔离。 块级作用用一组大括号定义一个块,使用 let 定义的变量在大括号的外面是访问不到的,并且let声明的变量不会污染全局作用域

if(true){
    let name = 'zfpx';
}
console.log(name); // ReferenceError: name is not defined

1.4 定义常量 #

const PI = 3.14;
PI = 3.15; // TypeError: Assignment to constant variable

const SCHOOL = {name:'zfpx'};
SCHOOL.name = 'jiang';

不能给常量重新赋值,如果是引用空间的话可以进行修改

1.5 应用场景 #

for (let i = 0; i < 3; i++) {
    setTimeout(function () {
        console.log(i);
    });
}// 1 2 3

我们可以将以前需要闭包实现的功能进行简化。

2.解构赋值 #

分解一个对象的结构。

2.1 数组的解构 #

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

2.2 对象的解构 #

let { name, age } = { name: 'zfpx', age: 9 };
console.log(name, age); // zfpx 9

2.3 解构的重命名 #

let { name: myName, age: myAge } = { name: 'zfpx', age: 9 }
console.log(myName, myAge); // zfpx 9

2.4 复杂的解构 #

let [
    { name: myName, age: myAge },
    { hobby: [sleep] },
    address
] = [
        { name: 'zfpx', age: 9 },
        { hobby: ['sleep', 'coding'] },
        '回龙观'
    ]
console.log(myName, myAge, sleep, address);

2.5 默认解构 #

let { name, age = 8 } = { name: 'zfpx' };
console.log(name, age);

当对象中没有此属性时会采用默认值

2.6 省略解构 #

let [, , address] = ['zfpx', 9, '回龙观 '];
console.log(address);

2.7 应用场景 #

function ajax(options) {
    var method = options.method || "get";
    var data = options.data || {};
    //.....
}
function ajax({ method = "get", data }) {
    console.log(method, data);
}
ajax({
    method: "post",
    data: { "name": "zfpx" }
});

3.字符串 #

3.1 模板字符串 #

模板字符串用反引号(数字1左边的那个键)包含,其中的变量用${}括起来

let name = 'JiangWen';
let age = 28;
let result = `My name is ${name} . I am ${age} years old`;
console.log(result); // My name is JiangWen . I am 28 years old

3.2 模板字符串实现 #

let name = 'JiangWen';
let age = 28;
let result = 'My name is ${name} . I am ${age} years old';
result = result.replace(/\$\{([^}]*)\}/g,function(){
    return eval(arguments[1]);
});
console.log(result);

3.3 模板字符串换行 #

let name = 'JiangWen';
let age = 28;
let userInfo = [name, age];
let lis = userInfo.map(function (info) {
    return `<li>${info}</li>`
});
let ul = `
    <ul>
        ${lis.join('')}
    </ul>
`;
console.log(ul);

3.4 模板标签 #

let name = 'JiangWen';
let age = 28;
function tag(strings) {
    let values = Array.prototype.slice.call(arguments, 1);
    let result = '';
    for (let key in values) {
        result += strings[key] + values[key].toString().toUpperCase();
    }
    result += strings[strings.length - 1];
    return result;
}
let result = tag`My name is ${name} . I am ${age} years old`;
console.log(result);

我们可以自定义模板字符串的呈现方式

3.5 字符串的新方法 #

4.函数 #

4.1 默认参数 #

function ajax(url, method = 'GET', dataType = "json") {
    console.log(url);
    console.log(method);
    console.log(dataType);
}

4.2 剩余运算符 #

let rest = function(a,...b){
    console.log(a,b);
}
rest(1,2,3);

4.3 箭头函数 #

箭头函数简化了函数的的定义方式,一般以 "=>" 操作符左边为输入的参数,而右边则是进行的操作以及返回的值inputs=>output

[1,2,3].forEach(val => console.log(val));

输入参数如果多于一个要用()包起来,函数体如果有多条语句需要用{}包起来。

箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。 正是因为它没有this,从而避免了this指向的问题。并且箭头函数中没有arguments

var person = {
    name:'zfpx',
    getName:function(){
-        setTimeout(function(){console.log(this);},1000); //在浏览器执行的话this指向window
+        setTimeout(() => console.log(this),1000);//在浏览器执行的话this指向person
    }
}j
person.getName();

4.4 对象不是作用域 #

let result = 'jw'
let obj = {
    result: 'zfpx',
    fn: () => {
        console.log(this.result);// undefined
    }
}
let fn = obj.fn;
fn();

这里的this指代的是window,let声明的变量不会放在window上

5.展开运算符 #

5.1 展开数组 #

let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];
let result = [...arr1, ...arr2];
console.log(result); // [ 1, 2, 3, 4, 5, 6 ]

5.2 对象展开 #

let name = {name:'zfpx'};
let age = {age:8};
let result = {...name,...age}
console.log(result);// { name: 'zfpx', age: 8 }

5.3 应用场景 #

function max() {
    console.log(Math.max(...arguments));
}
max(1, 3, 4);

将类数组进行展开,当然我们也可以用这种方式将类数组转化成数组

6.对象的拷贝 #

6.1 浅拷贝 #

6.2 深拷贝 #

7.数组的新方法 #

7.1 Array.from() #

将一个数组或者类数组变成数组,会复制一份(浅拷贝)

let newArr = Array.from(oldArr);

7.2 Array.of() #

of是为了将一组数值,转换为数组

console.log(Array(3), Array(3).length);
console.log(Array.of(3), Array.of(3).length);

7.3 copyWithin() #

Array.prototype.copyWithin(target, start = 0, end = this.length) 覆盖目标的下标 开始的下标 结束的后一个的下标,原数组改变

[1, 2, 3, 4, 5].copyWithin(0, 1, 2);

7.4 fill() #

就是填充数组的意思 会更改原数组 Array.prototype.fill(value, start, end = this.length);

let arr = [1, 2, 3, 4, 5, 6];
arr.fill('a', 1, 2);
console.log(arr);

7.5 常用方法 #

find/map/reduce/filter/forEach/findIndex/every/some

8.对象 #

8.1 属性简写 #

如果你想在对象里添加跟变量名一样的属性,并且属性的值就是变量表示的值就可以直接在对象里加上这些属性,对象中的函数属性可以进行简写

let name = 'zfpx';
let age = 8;
let person = {
    name,
    age,
    getName(){
        console.log(this.name);
    }
}
person.getName();

8.2 Object.is #

对比两个值是否相等

console.log(Object.is(NaN,NaN));

8.3 Object.setPrototypeOf #

将一个指定的对象的原型设置为另一个对象或者null

let obj = { name: 'zfpx' }
let obj2 = {};
Object.setPrototypeOf(obj2, obj);
let obj3 = {
    __proto__: obj
}
console.log(obj2.name);
console.log(obj3.name);

8.4 super #

通过super可以调用prototype上的属性或方法

let obj = { name: 'zfpx' }
let obj2 = {
    __proto__: obj,
    name: 'jw',
    getName() {
        return super.name
    }
}
console.log(obj2.getName());

9.类 #

9.1 类的定义 #

在以前我们定义类是通过构造函数来定义,es6新增了class关键字

class Parent {
    constructor(name) {
        this.name = name;
    }
    getName(){
        return this.name
    }
}
let p = new Parent('zfpx');
console.log(p.getName())

9.2 静态属性 #

类上的属性,通过类来调用

class Parent {
    constructor(name) {
        this.name = name;
        return {}
    }
    static a() {
        console.log('abc')
    }
    getName() {
        return this.name
    }
}
Parent.a();

9.3 类的继承 #

class Parent {
    constructor(name) {
        this.name = name;
    }
    static a() {
        console.log('abc')
    }
    getName() {
        return this.name
    }
}
class Child extends Parent {
    constructor(name, age) {
        super(name);
        this.age = age
    }
    getAge() {
        return this.age
    }
}
let c = new Child('zfpx','9');
console.log(c.getName())

10.Generator #

Generator是一个特殊的函数,执行它会返回一个Iterator对象。 通过遍历迭代器, Generator函数运行后会返回一个遍历器对象,而不是普通函数的返回值。

10.1 Iterators模拟 #

迭代器有一个next方法,每次执行的时候会返回一个对象 对象里面有两个属性,一个是value表示返回的值,还有就是布尔值done,表示是否迭代完成

function readBook(books) {
    let index = 0;
    return {
        next() {
            return {
                value: books[index++],
                done: index <= books.length ? false : true
            }
        }
    }
}
let it = readBook(['vue','angular','react']);
let flag = true
do {
    let { done, value } = it.next();
    console.log(value,done)
    flag = done;
} while (!flag)

10.2 使用Generator #

function * readBook(books) {
    for(let key in books){
        yield books[key]
    }
}
let it = readBook(['vue','angular','react']);
let flag = true
do {
    let { done, value } = it.next();
    console.log(value,done)
    flag = done;
} while (!flag)

11.Proxy&&Reflect #

这里来说一下如何利用Proxy实现双向数据劫持,我们利用Proxy拦截对象的set方法,利用Reflect给对象赋值。

function $set(obj, fn) {
    let p = new Proxy(obj, {
        set(target, property, value, r) {
            if (obj[value] !== value) {
                console.log('数据变化');
                return Reflect.set(target,property,value,r)
            }
            return true
        }
    })
    fn(p);
}

let obj = { name: 'zfpx', age: 9 ,arr:[1,2,3]};
$set(obj.arr, function (o) {
    o.push('hello')
    console.log(o);
});

12.集合 #

12.1 Set #

一个Set是一堆东西的集合,Set有点像数组,不过跟数组不一样的是,Set里面不能有重复的内容

var books = new Set();
books.add('js');
books.add('js');//添加重复元素集合的元素个数不会改变
books.add('html');
books.forEach(function(book){//循环集合
    console.log(book);
})
console.log(books.size);//集合中元数的个数
console.log(books.has('js'));//判断集合中是否有此元素
books.delete('js');//从集合中删除此元素
console.log(books.size);
console.log(books.has('js'));
books.clear();//清空 set
console.log(books.size);

12.2 Map #

可以使用 Map 来组织这种名值对的数据

var books = new Map();
books.set('js',{name:'js'});//向map中添加元素
books.set('html',{name:'html'});
console.log(books.size);//查看集合中的元素
console.log(books.get('js'));//通过key获取值
books.delete('js');//执照key删除元素
console.log(books.has('js'));//判断map中有没有key
books.forEach((value, key) => { //forEach可以迭代map
    console.log( key + ' = ' + value);
});
books.clear();//清空map