es6

137 阅读10分钟

1. let声明变量

  • 变量不能重复声明(var可以重复声明),防止变量污染
  • 块级作用域(只在代码块里面有效)
// if else while for
{
    let girl ='emm';
}
console.log(girl); //此时会报错not define
  • 不存在变量提升
console.log(song);
let song = 'pink';
//报错
  • 不影响作用域链
{
    {
        let school = 'gdut';
        function fn() {
            console.log(school);
        }
        fn(); //输出gdut
    }
}

let经典实例

//遍历绑定事件
for (let i = 0; i < items.length; i++) {
        items[i].onclick = function () {
            items[i].style.color = 'pink';
     }
}
// !!改成let就可以直接用了

2. const定义常量

  • 一定要赋初始值
//声明常量
const SCHOOL = 'gdut';
  • 一般常量使用大写(潜规则)
  • 常量的值不能修改
  • 块级作用域
  • 对于数组和对象的元素修改,不算对常量的修改,不会报错/
const TEAM = ['A', 'B', 'C', 'D'];
        TEAM.push('MAC');
//地址没有变

3. 解构赋值

数组的解构

const F4 = ['A', 'B', 'C', 'D'];
let [a, b, c, d] = F4;
 console.log(a);
 console.log(b);
 console.log(c);
 console.log(d);

对象的解构

const zhao = {
    name: '赵本山',
    age: '18',
    xiaopin: function () {
        console.log('be able to');
    }
};

4. 模板字符串

ES6引入新的声明字符串的方式 `` , '' , ""

  • 声明
let str = '这也是一个字符串';
console.log(str,typeof str);
  • 内容中可以直接出现换行符

  • 变量拼接

let love = 'pink';
let out = `${love}是我最喜欢的颜色`;
console.log(out); //打印出: pink是我最喜欢的颜色

5. 简化对象

ES6允许在大括号里面,直接写入变量和函数,作为对象的属性和方法,使代码更加简洁

let name = 'pink';
let change = function () {
    console.log('changeyou');
}
const school = {
    name,
    change
    improve(){
    console.log('changeyou');
    }
}
console.log(school);

6. 箭头定义函数

ES6 允许使用[箭头] =>定义函数

  • this 是静态的, this时钟指向函数声明时所在作用域下的 this 的值
        function getName() {
            console.log(this.name);
        }
        let getName2 = () => {
            console.log(this.name);
        }

        window.name = 'pink';
        const school = {
            name: 'shang'
        }
        //直接调用
         getName();  //pink
         getName2(); //pink

        //call方法调用
        getName.call(school);   //shang
        getName2.call(school);  //pink
  • 不能作为构造实例化对象
let Person = (name, age) => {
            this.name = name;
            this.age = age;
        }
        let me = new Person('xiao', 30)
        console.log(me); //报错
  • 不能使用arguements变量

  • 箭头函数的简写

    1. 省略小括号,当形参有且只有一个的时候
let add = (n) => {
    return n+n;
}
console.log(add(9));

​ 2) 省略花括号,当代码体只有一条语句的时候,此时return必须省略,而且语句的执行结构就是函数的返回值

let add = (n) => return n+n;
console.log(add(9));

箭头函数的应用场景

箭头函数适合与this无关的回调,定时器,数组的方法回调。

箭头函数不适合与this有关的回调,事件回调,对象的方法

{
    name:'pink',
    getName:(){
        this.name;  //this指向的是这个对象
    }
}
************************
{
    name:'pink',
    getName:() => {
        this.name;  //this指向的是外层作用域this的值
    }
}

绑定事件

let items = document.getElementsById('item');

/*
items.addEventListener('click',function(){
    let _this = this;  //如果没这个语句,this指向window
    setTimeout(function(){
        console.log(this);
        //当前作用域找不到就往外层找
        _this.style.color = 'pink';
    },2000)
})
*/
items.addEventListener('click',function(){
    let _this = this;
    setTimeout(() => {
        console.log(this);
        //this的值是静态的指向声明时所在作用域this的值(即items)
        _this.style.color = 'pink';
    },2000)
})

  • 从数组中返回偶数的元素
const arr = [1, 6, 78, 4, 2, 99];
/*
const result = arr.filter(function (item) {
    if (item % 2 === 0) {
        return true;
    } else {
        return false;
    }
})
*/
const result = arr.filter(item => item % 2 === 0);
console.log(result);

7. ES6允许给函数参数赋值初始值

  1. 形参初始值,具有默认值的参数,一般位置要靠后(潜规则)
function add(a, b, c=10) {
            return a + b + c;
        }
        let result = add(1, 2, 3);
        //如果3不传递,返回NaN,可以给c赋初始值
        console.log(result);
  1. 与解构赋值结合
// function connect(options) {
//     let host = options.host;
//     let username = options.name;
// }

function connect({ host = '127.0.0.1', username, password, port }) {
    console.log(host);
    console.log(username);
}
connect({
    host: 'localhost',
    username: 'root',
    password: 'root',
    port: 3306
})

8. rest参数

  • ES6引入了rest参数,用于获取函数的实参,用来代替arguement
 // es5获取实参的方式
 function date() {
     console.log(arguments);
 }
 date('a', 'b', 'c');   //这个一个对象
 // es6 rest参数
 function date(...args) {
     console.log((args));  //可以用filter some every map
 }
 date('a', 'b', 'c');
 //这是一个数组 
  • rest参数必须要放到参数最后
function fn(a, b, ...args) {
            console.log(a);
            console.log(b);
            console.log(args);
        }
        fn(1, 2, 3, 4, 5, 6);
// 1给a,2给b, 3456给...args

9. ES6扩展运算符

  • [...] 扩展运算符能将【数组】转换为逗号分隔的【参数序列】
// 声明一个数组
const tfboys = ['yyqx', 'wjk', 'wy'];
// 声明一个函数
function chunwan() {
    console.log(arguments);
}
chunwan(tfboys); //一个参数['yyqx', 'wjk', 'wy']
chunwan(...tfboys);
//三个参数 0:yyqx; 1:wjk; 2:wy 相当于chunwan('yyqx', 'wjk', 'wy');

扩展运算符应用

  • 数组的合并
const kuaizi = ['zhangsan', 'lisi'];
const fenghuang = ['xiaoming', 'xiaohong'];
// const zuixuan = kuaizi.concat(fenghuang);
const zuixuan = [...kuaizi, ...fenghuang];  //返回一个合并数组
console.log(zuixuan);
  • 数组的克隆
const sanzhihua = ['E', 'F', 'G'];
const sanyecao = [...sanzhihua];
console.log(sanyecao);  //['E', 'F', 'G'] 
  // 如果数组中有引入数据类型就是浅拷贝,否则是深度拷贝
  • 将伪数组转换为真正的数组
const divs = document.querySelectorAll('div');
const divArr = [...divs];
console.log(divsArr);

10. Symbol的介绍和创建

ES6引入了一种新的初始数据类型Symbol,表示独一无二的值,类似于字符串的数据类型

  • Symbol的值是唯一的,用来解决命名冲突的问题
  • Symbol不能与其他数据进行运算
  • Symbol不能用 for...in 遍历
// 创建Symbol
let s = Symbol();
// console.log(s, typeof s);
let s2 = Symbol('pink');
let s3 = Symbol('pink');
console.log(s2 === s3); //false
let s4 = Symbol.for('pink');
let s5 = Symbol.for('pink');
console.log(s4 === s5); //true
//不能与其他数据进行运算,会报错

7种数据类型

  • you are so niubility

  • u undefined

  • s string

  • o object

  • n null number

  • b boolean

给对象添加方法

let game = {
}
let methods = {
    up: Symbol(),
    down: Symbol()
};
game[methods.up] = function () {
    console.log('up');
}
game[methods.down] = function () {
    console.log('down');
}
console.log(game);
let youxi = {
    name: '狼人杀',
    [Symbol('say')]: function () {
        console.log('fayan');
    },
    [Symbol('zibao')]: function () {
        console.log('zibao');
    }
}
console.log(youxi);

Symbol的内置值

a. Symbol.hasInstance

当其他对象使用instanceof运算符,判断是否为该对象实例时,会调用这个方法

class Person {
            static [Symbol.hasInstance](param) {
                console.log(param);  //{} 获取了o的值
                console.log('hello');
            }
        }
        let o = {};
        console.log(o instanceof Person);

b. Symbol.isConcatSpreadable

该属性等于的是一个布尔值,表示该对象用于Array.prototype.concat()时,是否会展开。

const arr = [1, 2, 3];
const arr2 = [4, 5, 6];
arr2[Symbol.isConcatSpreadable] = false;
console.log(arr.concat(arr2));
// 返回 [1,2,3,456]

11. 迭代器

迭代器是一种接口,为各种不同的数据结构提供统一的访问机制,任何数据结构只要部署Iterator接口,就可以完成遍历操作

  • ES6创造了一种新的遍历命令 for...of循环,Iterator接口主要供for...of 消费
  • 原生具备iterator接口的数据,可以用for of遍历
    1. Array
    2. Arguments
    3. Set
    4. Map
    5. String
    6. TypedArray
    7. NodeList
// 声明一个数组
const zimu = ['A', 'B', 'C', 'D'];
for (var v of zimu) {
     console.log(v);  //ABCD  保存键值
}
for (var v in zimu) {
     console.log(v);  //0123  保存键名
}

const zimu = ['A', 'B', 'C', 'D'];

let iterator = zimu[Symbol.iterator]();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

结果:

迭代器的应用

//声明一个对象
 const banji = {
     name: 'yiban',
     stus: [
         'zhangsan',
         'lisi',
         'xiaoming',
         'xiaohong'
     ],
     [Symbol.iterator]() {
         // 索引变量
         let index = 0;
         let _this = this;
         return {
             next: function () {
                 if (index < _this.stus.length) {
                     const result = { value: _this.stus[index], done: false };
                     // 返回false 疯狂输出 没有完成
                     // 下标自增
                     index++;
                     return result;
                 } else {
                     return { value: undefined, done: true };
                 }
             }
         };
     }
 }
 // 遍历这个对象
 for (let v of banji) {
     console.log(v);
 }
 // banji.stus.forEach(); 不是面向对象

12. 生成器

生成器函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同

生成器其实就是一个特殊的函数

function* gen() {
     console.log('nihao');
 }
 let iterator = gen();
 console.log(iterator);  //一个迭代器对象,有一个next的方法
 console.log(iterator.next());  //nihao
//遍历
 for (let v of gen()) {
     console.log(v);  //每次返回结果是yield后的表达式或者自变量的值
 }
function* gen() {
    yield '一只';  //函数代码的分隔符
    yield '两只';
    yield '三只';
}
let iterator = gen();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
// 返回值如下 false表示遍历还没结束

生成器的函数参数

next方法可以传入实参,而且参数作为上一个yield语句的整体返回结果

function* gen(arg) {
    console.log(arg);
    let one = yield 111;
    console.log(one);
    let two = yield 222;
    console.log(two);
    let three = yield 333;
    console.log(three);
}
// 执行获取迭代器对象
let iterator = gen('AAA');
console.log(iterator.next());
console.log(iterator.next('BBB'));
console.log(iterator.next('CCC'));
console.log(iterator.next('DDD'));

生成器函数实例

这样子就不用疯狂嵌套函数啦!

第一个实例~关于定时器,隔1s获取一个数据

 // 异步编程 文件操作 网络操作(ajax request) 数据库操作
function one() {
     setTimeout(() => {
         console.log(111);
         iterator.next();
     }, 1000);
 }
 function two() {
     setTimeout(() => {
         console.log(222);
         iterator.next();
     }, 2000);
 }
 function three() {
     setTimeout(() => {
         console.log(333);
         iterator.next();
     }, 3000);
 }
 function* gen() {
     yield one();
     yield two();
     yield three();
 }
 // 调用生成器函数
 let iterator = gen();
 iterator.next();

第二个实例

看起来是同步获取数据,实际上是异步噢~

// 模拟获取 用户数据 订单数据 商品数据
function getUsers() {
    setTimeout(() => {
        let data = '用户数据';
        // 调用next方法并且将数据传入
        iterator.next(data);
    }, 1000);
}
function getOrder() {
    setTimeout(() => {
        let data = '订单数据';
        iterator.next(data);
    }, 1000);
}
function getGoods() {
    setTimeout(() => {
        let data = '商品数据';
        iterator.next(data);
    }, 1000);
}
function* gen() {
    let users = yield getUsers();
    console.log(users);
    let order = yield getOrder();
    console.log(order);
    let goods = yield getGoods();
    console.log(goods);
}
// 调用生成器函数
let iterator = gen();
iterator.next();

13. Promise

Promise是ES6引入的异步编程的新解决方案。语法上Promise是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果

  • Promise构造函数:Promise(excutor){}
  • Promise.prototype.then方法
  • Promise.prototype.catch方法
// 1. 引入fs模块
const fs = require('fs');
// 2. 调用方法读取文件
fs.readFile('./es6/test.md', (err, data) => {
    // 如果失败,抛出错误
    if (err) throw err;
    // 如果成功
    console.log(data.toString());
})
// 3. 使用Promise封装
const p = new Promise(function (resolve, reject) {
    fs.readFile('/es6/test.md', (err, data) => {
        // 判断如果失败  reject 调用 then 方法的第二个回调函数
        if (err) reject(err);
        // 如果成功  resolve 调用 then 方法的第一个回调函数
        resolve(data);
    })
})
p.then(function (value) {
    console.log(value.toString());
}, function (reason) {
    console.log('读取失败');
})
Promise封装ajax
// 接口地址:http://api.apiopen.top/getJoke
const p = new Promise((resolve, reject) => {
    // 1. 创建对象
    const xhr = new XMLHttpRequest();
    // 2. 初始化
    xhr.open("get", "http://api.apiopen.top/getJoke", true);
    // 3. 发送
    xhr.send();
    // 4. 绑定事件,处理响应结果
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
            if (xhr.status >= 200 && xhr.status < 300) {
                // 表示成功
                console.log(xhr.response);
            } else {
                console.error(xhr.status);
            }
        }
    }
})
// 指定回调
p.then(function (value) {
    console.log(value);
}, function (reason) {
    console.error(reason);
})
promise then方法
  • 创建promise对象
const p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('用户数据');
    }, 1000);
    // 成功了就执行then的第一个回调函数
})
  • 调用then方法 then方法的返回结果是 Promise 对象,对象状态由回调函数的执行结果决定
// 1. 如果回调函数中返回的结果是 非Promise 类型的属性,状态为成功,返回值为对象成功的值
p.then(value => {
    console.log(value);  // 用户数据
    // 1. 非promise类型的属性
    // return 123;
    // 2. 是promise对象 如果这个promise返回成功,则then方法返回成功,反之成立
    return new Promise((resolve, reject) => {
        resolve('ok');
    })
    // 3. 抛出错误
    // throw new Error('出错了');
}, reason => {
    console.warn(reason);
})

// 链式调用
p.then(value => {

}).then(value => {

})
console.log(result);
promise链式调用
// 引入fs模块
const fs = require("fs");
// 使用promise实现
const p = new Promise((resolve, reject) => {
    fs.readFile('es6/test1.md', (err, data) => {
        resolve(data);
    });
});
// p.then(value => {
//     console.log(value.toString());
// })
// then成功失败都可,catch只能是失败的
p.then(value => {
    return new Promise((resolve, reject) => {
        fs.readFile('es6/test1.md', (err, data) => {
            resolve([value, data]);
        });
    })
}).then(value => {
    return new Promise((resolve, reject) => {
        fs.readFile('es6/test3.md', (err, data) => {
            // 压入
            value.push(data);
            resolve(value);
        });
    });
}).then(value => {
    console.log(value.join('\r\n'));
})
promise catch
const p = new Promise((resolve, reject) => {
    setTimeout(() => {
        // 设置p对象的状态为失败,并设置失败的值
        reject('出错了');
    }, 1000);
})
p.catch(function (reason) {
    console.warn(reason);
})

14. set()

let s = new Set();
let s2 = new Set(['1','2','3','4','4']);
// 元素个数
console.log(s2.size);  // 4  元素去重
// 添加元素
s2.add('5');
// 删除元素
s2.delete('6');
// 检测
console.log(s2.has('5'));  //true
// 清空
s2.clear();
// 遍历
for(let v of s2){
    console.log(v);  //遍历(也会去重)
}

Set集合事件

1.数组去重

let arr = [1,2,3,4,5,4,3,2,1];
let result = new Set(arr);  // 此时result是一个集合
let result = [...new Set(arr)];  // 数组去重

2.交集

let arr = [1,2,3,4,5,4,3,2,1];
// 2. 交集
let arr2 = [4,5,6,5,6];
let result = [...new Set(arr)].filter(item => {
    let s2 = new Set(arr2); // 4 5 6
    if(s2.has(item)){
        return true;
    }else{
        return false;
    }
})
//或者也可以写成
// let result = [...new Set(arr)].filter(item => new Set(arr2).has(item))
console.log(result);  // [4,5] 

3. 并集

let union = new Set([...arr,...arr2]);//合并
console.log(union);  // [1,2,3,4,5,6]

4. 差集

// 谁是主体结果是不一样的  arr有arr2没有的
let diff = [...new Set(arr)].filter(item => !(new Set(arr2).has(item)));
console.log(diff);    // [1,2,3]

15. Map()

Map也实现了iterator接口,可以用扩展运算符和【for...of】进行遍历

// 声明Map
let m = new Map();
// 添加元素
m.set('name', 'pink');
m.set('change', function () {
    console.log('改变你');
})
let key = {
    school: 'pink'
};
m.set(key, ['guangzhou', 'shanghai', 'shenzhen']);
console.log(m.size);
console.log(m);
// 删除
m.delete('name'); m.get('change');
// 获取
console.log();
// 清除
m.clear();
// 遍历
for (let v of m) {
    console.log(v);
}

16. class类

通过class关键字,可以定义类,新的class写法只是让对象原型的语法更加清晰

// es5
// 手机
function Phone(brand, price) {
    this.brand = brand;
    this.price = price;
}
// 添加方法
Phone.prototype.call = function () {
    console.log('打电话');
}
let Huawei = new Phone('华为', 666);
Huawei.call();
console.log(Huawei);
//class
class Shouji {
    // 构造方法 名字不能修改
    constructor(brand, price) {
        this.brand = brand;
        this.price = price;
    }
    // 方法必须使用该语法,不能使用es5的对象完整形式
    call() {
        console.log('打电话');
    }
}
let onePlus = new Shouji('1+', 999);
console.log(onePlus);

class静态成员

function Phone() {
}
Phone.name = '手机';
Phone.change = function () {
    console.log('changethings');
}
let nokia = new Phone();
console.log(nokia.name);  
// 实例对象和构造函数的原型对象是相通的,但是和函数对象是不通的
// 函数对象的属性是属于函数对象的,并不属于实例对象,这样称为静态成员
class Phone {
    // 静态属性
    static name = '手机';
    static change() {
        console.log('改变');
    }
}
let nokia = new Phone();
console.log(nokia.name); // undefined
console.log(Phone.name); // 手机
// static标注的属性和方法,属于类,而不属于对象

类继承

es5
 // 手机
 function Phone(brand, price) {
     this.brand = brand;
     this.price = price;
 }
 Phone.prototype.call = function () {
     console.log('打电话');
 }
 // 智能手机
 function SmartPhone(brand, price, color, size) {
     Phone.call(this, brand, price);
     // this指向smartphone
     this.color = color;
     this.size = size;
 }
 // 设置子级构造函数的原型
 SmartPhone.prototype = new Phone;
 SmartPhone.prototype.constructor = SmartPhone;
 // 声明子类的方法
 SmartPhone.prototype.photo = function () {
     console.log('拍照');
 }
 SmartPhone.prototype.playGame = function () {
     console.log('玩游戏');
 }
 const chuizi = new SmartPhone('锤子', 999, '黑色', '5.5');
 console.log(chuizi);
// 输出结果

es6
class Phone {
    //构造方法
    constructor(brand, price) {
        this.brand = brand;
        this.price = price;
    }
    // 父类的成员属性
    call() {
        console.log('打电话');
    }
}
class SmartPhone extends Phone { // 必须写extends
    // 构造方法
    constructor(brand, price, color, size) {
        super(brand, price)  //super就是父类的contructor方法
        this.color = color;
        this.size = size;
    }
    phone() {
        console.log('拍照');
    }
    playGame() {
        console.log('玩游戏');
    }
}
const chuizi = new SmartPhone('锤子', 999, '黑色', '5.5');
console.log(chuizi);
// 输出结果和上面是一样的~代码简洁了许多

class中的get和set

  • get:通常是用来对动态属性进行封装,随着数据的变化而变化
  • set:添加更多的控制和判断,是否合法。成功就赋值,失败则不赋值2
// get和post
class Phone {
    get price() {
        console.log('价格属性被读取了');
        return '111';
    }
    set price(newVal) {
        console.log('价格属性被修改了');
    }
}
// 实例化对象
let s = new Phone();
console.log(s.price);  //price()里面return的值
s.price = 'free';   // 触发set price()方法

17. 数值拓展

1. Object.is 判断两个值是否完全相等 跟===很像
2. Object.assiign(obj1,obj2) //合并 如果都有,后面覆盖前面的 如果前面没有就加上去
3. Object.setPrototypeof(school,cities) //设置原型对象
 const school = {
     name: 'shang'
 }
 const cities = {
     xiaoqu: ['beijing', 'shanghai', 'shenzhen']
 }
 Object.setPrototypeOf(school, cities);
 console.log(Object.getPrototypeOf(school));
 console.log(school);
// 输出结果