ES6基础

作者: 贾里 | 来源:发表于2017-05-18 15:44 被阅读17次

    ECMAScript 6学习网站:http://es6.ruanyifeng.com/

    1.let和var的比较

    共同点:定义变量
    区别:
    1.范围不同

    • var变量可以跨代码块
    • let只在代码块内部有效
    {
        var a = "jarry";
        let b = 20;
    }
    
    console.log(a);
    if(typeof(b) == "undefined"){
        alert("undefined");
    }
    

    案例

    var a = [];
    for(let i = 0; i < 5; i++){
        a[i] = function(){
            console.log(i);
        }
    }
    
    a[2]();
    

    2.定义顺序

    console.log(a); //let 引用错误
    let a = "jarry";
    

    var 不会报错的原因是因为加载这个文件后,已经知道有这个变量,只是在执行的时候,还没有声明,所以不会报错,只是为undefined

    2.const常量

    只能一次赋值

    const PI = 3.14159;
    PI = 3.14;
    
    Paste_Image.png

    1.对象常量
    对象的属性可以修改,对象的引用不能修改

    const obj = {name:"jack"};
    obj.name = "jarry";
    

    2.冻结对象
    防止修改对象的属性

    const obj = Object.freeze({name:"jason"});
    obj.name = "jarry";
    console.log(obj.name);
    

    3.解构赋值

    1.数组解构赋值
    必须按照顺序

    let [a,b] = ["jack",20];
    console.log(a);
    console.log(b);
    

    old version

    var obj = {name:"jack",age:20};
    var a = obj.name;
    var b = obj.age;
    

    2.对象解构赋值
    可以乱序

    var {name,age} = {name:"jack",age:20};
    console.log(name);
    console.log(age);
    

    3.用途

    • 1.交换变量的值
    let x = 1;
    let y = 2;
    [x, y] = [y, x];
    
    • 2.从函数返回多个值
    // 返回一个数组
    function func1() {
        return [1, 2, 3];
    }
    let [a, b, c] = func1();
    //old version
    function func1() {
        return [1, 2, 3];
    }
    var arr = func1();
    let a = arr[0];
    let b = arr[1];
    let c = arr[2];
    
    • 3.返回一个对象
    function func2() {
        return {
            foo: 1,
            bar: 2
        };
    }
    let { foo, bar } = func2();
    

    4.参数有序和无序

    • 参数是一组有次序的值
    //数组解构赋值
    function func3([x, y, z]) {}
    func3([1, 2, 3]);
    
    • 参数是一组无次序的值
    //对象解构赋值
    function func4({x, y, z}) { }
    func4({z: 3, y: 2, x: 1});
    

    4.模板字符串(增强版的字符串)

    原始的字符串拼接方式:

    let name = "jack";
    let age = 20;
    let str = name + " is " + age + "years old.";
    

    模板字符串:

    • 嵌入变量
    let str2 = `${name} is ${age} years old.`;
    //str2.log + tab键
    console.log(str2);
    
    • 保持原来的字符串格式
    let str3 = `I love
        you!`;
    console.log(str3);
    

    5.箭头函数

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

    • 普通
    //原始方式
    let func = function(n){
        console.log(n);
    }
    func(2);
    //n =>代表function(n)
    let func1 = n => console.log(n);
    func1(3);
    
    • 带有返回值的例子:
    //原始方式
    let func1 = function(n){
        return n * 2;
    }
    //自动返回=>的值
    let func2 = n => n * 2;
    
    • 多个参数
    //原始方式
    let func1= function(a,b){
        a+=5;
        return a+b;
    }
    //多个参数
    let func2 = (a,b) => {
        a+=5;
        return a+b;
    };
    console.log(func3(3,4));
    
    • 箭头函数返回对象
    var initObj = id => ({id:id,name:"default"});
    console.log(initObj(2));
    
    • 对象解构赋值
    //拼接得到完整的名称
    let full = ({first, last}) => first + " " + last;
    console.log(full({first: "Michael", last: "Jackson"}));
    

    常见案例:

    • 数组的map遍历
    //原始方式
    var arr =[3,4,2,1].map(function (n) {
        return n*2;
    })
    console.log(arr);
    //箭头方式
    var arr2=[1,2,4].map(n=>n*2);
    console.log(arr2);
    
    • sort排序(升序)
    //原始方式
    var arr = [1,4,5,2].sort(function(a,b){
        return a - b;
    });
    //箭头方式
    var arr2 = [1,4,5,2].sort((a,b) => b - a);
    console.log(arr2);
    
    • 不传参数
      可以传多个也可以不传
    let func5 = () => 5;
    let func6 = (m,n) => m * n;
    function func4(a){
        //参数数组
        console.log(arguments[2]);
    }
    func4(6,9,10);
    

    6.Symbol 第七种数据类型

    表示独一无二的值,防止对象属性的覆盖

    • 类型
    let s1 = Symbol();
    console.log(s1);
    console.log(typeof s1);
    

    运行结果是:

    Symbol()
    symbol
    
    • 属性覆盖
    let obj = {name : "jack"};
    obj.name = function(){
        console.log("jack");
    }
    obj.name();
    
    • 使用Symbol给对象添加属性
    let obj = {name:"jason"};
    //另外一个模块
    let name = Symbol();
    let age = Symbol();
    //name是一个Symbol值,作为属性名
    obj[name] = function(){
        console.log("jack");
    };
    obj[age] = 10;
    console.log(obj.name);
    console.log(obj[age]);
    obj[name]();
    

    7.==(等于)与 ===(恒等于)的区别

    ==(等于)
    1、如果两个值类型相同,进行 === 比较。
    2、如果两个值类型不同,他们可能相等。根据下面规则进行类型转换再比较:

    • a、如果一个是null、一个是undefined,那么[相等]。
    • b、如果一个是字符串,一个是数值,把字符串转换成数值再进行比较。
    • c、如果任一值是 true,把它转换成 1 再比较;如果任一值是 false,把它转换成 0 再比较。
    • d、如果一个是对象,另一个是数值或字符串,把对象转换成基础类型的值再比较。对象转换成基础类型,利用它的toString或者valueOf方法。 js核心内置类,会尝试valueOf先于toString;例外的是Date,Date利用的是toString转换。
    // console.log({} == "abc");
    // console.log("1" == 1);
    // console.log("abc" == 'abc');
    // let a = null;
    // console.log(a == undefined);
    //
    // console.log(true == "1");
    

    ===(恒等于)
    1、如果类型不同,就[不相等]
    2、如果两个都是数值,并且是同一个值,那么[相等];(!例外)的是,如果其中至少一个是NaN,那么[不相等]。(判断一个值是否是NaN,只能用isNaN()来判断)
    3、如果两个都是字符串,每个位置的字符都一样,那么[相等];否则[不相等]。
    4、如果两个值都是true,或者都是false,那么[相等]。
    5、如果两个值都引用同一个对象或函数,那么[相等];否则[不相等]。
    6、如果两个值都是null,或者都是undefined,那么[相等]。

    8.class关键字

    class 语法糖
    在原有语法基础上修改语法,提高语法的可读写,原来的语法仍然可以使用

    • 老版本
    function User(name,age){
        this.name = name;
        this.age = age;
    }
    
    User.prototype.sayHi = function(){
        console.log(this.name);
    }
    
    • class 语法糖
    class User{
        //构造函数
        constructor(name,age){
            this.name = name;
            this.age = age;
        }
        sayHi(){
            console.log(this.name);
        }
    }
    
    let u1 = new User("jack",20);
    u1.sayHi();
    
    console.log(typeof User);
    

    事实上,类的所有方法都定义在原型的上的

    console.log(u1.sayHi === User.prototype.sayHi);
    

    返回结果是true

    9.继承

    var count = 0;
    class Point{
        constructor(x,y){
            this.x = x;
            this.y = y;
        }
        toString(){
            return this.x + " " + this.y;
        }
        //静态方法
        static count(){
            return count++;
        }
    }
    
    //本质上还是通过原型来实现继承
    class My3DPoint extends Point{
        constructor(x,y,z){
            super(x,y); //向父类构造函数传参
            this.z = z;
        }
        toString(){
            return "3D:"+this.z + " "+super.toString();
        }
    }
    
    let p1 = new My3DPoint(20,30,40);
    // console.log(p1.toString());
    //// console.log(p1 instanceof My3DPoint);
    // console.log(p1 instanceof Point);
    // console.log(p1.constructor === My3DPoint);
    
    My3DPoint.count();
    console.log(Point.count());
    console.log(Point.count());*/
    

    10.new.target

    //根据new.target是否返回undefined,来判断构造函数是怎么调用的
    function Person(name) {
        if (new.target !== undefined) {
            this.name = name;
        } else {
            throw new Error('必须使用new生成实例');
        }
    }
    
    // 另一种写法
    function Person(name) {
        if (new.target === Person) {
            this.name = name;
        } else {
            throw new Error('必须使用new生成实例');
        }
    }
    
    var p1 = new Person('张三'); // 正确
    var p2 = Person.call(person, '张三');  // 报错*/
    

    11.几种继承

    1.原型继承

    //父类型
    function SuperType(){
        this.flag = true;
    }
    
    SuperType.prototype.getXX = function(){
        return this.flag;
    }
    
    //子类型
    function SubType(){
        this.subFlag = false;
    }
    
    SubType.prototype = new SuperType();
    
    //拷贝过程(可以这么理解)
    //new SuperType() -> SubType.prototype -> s1
    
    //检查是否继承了父类型的属性
    var s1 = new SubType();
    console.log(s1.getXX());
    

    原型继承的问题:共享属性

    function SuperType(){
        this.x = 10;
        this.colors = ["red","green","blue"];
    }
    
    SuperType.prototype.getXX = function(){
        return "xx";
    }
    
    //子类型
    function SubType(){
        this.subFlag = false;
    }
    //继承
    //原型的问题:当原型包含引用类型的属性时,这些属性会被所有实例共享
    SubType.prototype = new SuperType();
    
    var s1 = new SubType();
    s1.colors.push("white");
    s1.x = 9;
    console.log(s1.colors);
    
    var s2 = new SubType();
    console.log(s2.colors);
    console.log(s2.x);
    

    这个结果:s2也会有white

    2.构造函数继承

    function SuperType(){
        this.colors = ["red","green","blue"];
    }
    
    function SubType(){
        //继承属性
        SuperType.call(this);
        //相当于
        /!*function SuperType(){
            s1.colors = ["red","green","blue"];
        }*!/
    }
    
    var s1 = new SubType();
    s1.colors.push("white");
    console.log(s1.colors);
    
    var s2 = new SubType();
    console.log(s2.colors);*/
    
    

    构造函数继承的问题:
    方法都在构造函数中定义,函数复用是个问题,而且在父类原型中定义的函数,对于子类也是不可见的。

    3.组合继承(综合有点,避免缺点)

    //原型+构造函数
    function SuperType(name){
        this.name = name;
        this.colors = ["red","green","blue"];
    }
    
    SuperType.prototype.sayHi = function(){
        console.log("sayHi");
    }
    
    function SubType(name,age){
        //继承属性
        SuperType.call(this,name);
        this.age = age;
    }
    
    //继承函数
    SubType.prototype = new SuperType();
    //构造函数不能错
    SubType.prototype.constructor = SubType;
    
    //子类自己的函数
    SubType.prototype.sayAge = function(){
        console.log(this.age);
    }
    
    var s1 = new SubType("jack",20);
    s1.sayHi();
    s1.sayAge();
    s1.colors.push("white");
    console.log(s1.colors);
    
    var s2 = new SubType("jason",20);
    console.log(s2.colors);
    
    //根据constructor判断,当前对象由哪一个构造函数实例化出来的
    console.log(s2.constructor === SubType);
    

    12.Generator函数

    Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同
    和普通函数的区别

    • 1.返回值function*
    • 2.yield
      传统函数,一旦调用,从头至尾执行,根本停不下来

    从语法上,首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态

    function* func(){
        yield "step1";  //状态
        console.log("step1");
    
        yield "step2";
        console.log("step2");
    
        return "result";
    }
    

    调用Generator函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,也就是遍历器对象(Iterator Object)

    let state = func();
    

    执行流程:
    next方法:第一次调用,Generator函数开始执行,直到遇到第一个yield语句为止。

    state.next();
    

    next方法返回一个对象,它的value属性就是当前yield语句的值step1。

    state.next();
    state.next();
    console.log(state.next());
    

    上面代码返回对象的内容:{ value: 'step1', done: false }
    其中:done属性的值false,表示遍历还没有结束。

    ** Symbol.iterator 迭代器**

    let arr = ['a', 'b', 'c'];
    //数组迭代器对象
    let iter = arr[Symbol.iterator]();
    //迭代器iter.next()函数,返回值:{ value: 'a', done: false }
    console.log(iter.next());
    
    //遍历数组的所有元素
    while(true){
        var obj = iter.next();
        if(obj.done === true){
            break;
        }
        console.log(obj.value);
    }
    

    for of循环

    for(let item of iter){
        console.log(item);
    }
    

    案例
    显示进度条->请求数据->获取数据成功,隐藏进度条

    • 普通方式
    //显示进度条
    function showLoadingProgress(){
        //不断刷新进度条
        //DOM
        var progress = document.getElementsByTagName("progress")[0];
        //定时器,每隔500毫秒,进度累加
        var interval = setInterval(function(){
            progress.value += 10;
            if(progress.style.display === "none"){
                clearInterval(interval); //取消定时器
            }
        },500);
    }
    
    //请求数据
    function loadUIDataAsynchronously(callback){
        //模拟网络延时
        setTimeout(function(){
            //拿到数据了
            let dataNode = document.getElementById("data");
            dataNode.innerText = "假装从服务器拿到了数据,显示在这里...";
            //隐藏进度条
            callback();
        },3000);
    }
    
    //隐藏进度条
    function hideLoadingProgress(){
        var progress = document.getElementsByTagName("progress")[0];
        progress.style.display = "none";
    }
    
    function loadUI(){
        //1.显示进度条
        showLoadingProgress();
        //2.请求数据
        loadUIDataAsynchronously(hideLoadingProgress);
    
    }
    //当页面加载完成之后,执行loadUI
    window.onload = loadUI;
    
    • 使用Generator函数
    //显示进度条
     function showLoadingProgress(){
         //不断刷新进度条
         //DOM
         var progress = document.getElementsByTagName("progress")[0];
         //定时器,每隔500毫秒,进度累加
         var interval = setInterval(function(){
            progress.value += 10;
             if(progress.style.display === "none"){
                clearInterval(interval); //取消定时器
             }
         },500);
     }
    
    //请求数据
    function loadUIDataAsynchronously(){
        //模拟网络延时
        setTimeout(function(){
            //拿到数据了
            let dataNode = document.getElementById("data");
            dataNode.innerText = "假装从服务器拿到了数据,显示在这里...";
            //隐藏进度条
            loader.next();
        },3000);
    }
    
    //隐藏进度条
    function hideLoadingProgress(){
        var progress = document.getElementsByTagName("progress")[0];
        progress.style.display = "none";
    }
    
    //异步操作的同步化表达
    function* loadUI(){
        //1.显示进度条
        showLoadingProgress();
        //2.请求数据
        yield loadUIDataAsynchronously();
        //3.隐藏进度条
        hideLoadingProgress();
    }
    var loader;
    
    window.onload = function(){
        loader = loadUI();
        loader.next();
    }
    
    

    next传参
    yield句本身没有返回值,或者说总是返回undefined
    next方法可以带一个参数,该参数就会被当作上一个yield语句的返回值。

    Generator 函数从暂停状态到恢复运行,它的上下文状态(context)是不变的。通过next方法的参数, 就有办法在 Generator 函数开始运行之后,继续向函数体内部注入值。 也就是说,可以在 Generator 函数运行的不同阶段,从外部向内部注入不同的值,从而调整函数行为。

    function* func2(){
        console.log("started");
        let r1 = yield ;
        console.log(r1); //输出yield返回值
        let r2 = yield ;
        console.log(r2);
    }
    
    let state = func2();
    state.next();
    state.next("a");
    state.next();
    
    //循环输出,通过传参,随时让循环重新开始
    function* func3(){
        for(let i=0; i < 5; i++){
            let reset = yield i;
            console.log(reset);
            if(reset) i = -1;
        }
    }
    
    let state = func3();
    console.log(state.next());
    console.log(state.next());
    //通过next传参,让yield有返回值
    console.log(state.next(true));
    console.log(state.next());
    console.log(state.next());
    
    

    案例2
    按照流程执行:step1(value1) -> step2(value2) -> step3(value3) -> step4(value4)

    • 普通方式:
    function step4(value3,callback){
        var value4 = `step4_${value3}`;
        callback(value4);
    }
    
    function step3(value2,callback){
        var value3 = `step3_${value2}`;
        callback(value3);
    }
    
    function step2(value1,callback){
        var value2 = `step2_${value1}`;
        callback(value2);
    }
    
    function step1(callback){
        var value1 = `step1_start `;
        callback(value1);
    }
    
    //给什么人看?
    //回调嵌套
    step1(function (value1) {
        step2(value1, function(value2) {
            step3(value2, function(value3) {
                step4(value3, function(value4) {
                    console.log(value4);
                });
            });
        });
    });*/
    
    
    • Generator 方式
    function step4(value3){
        return `step4_${value3}`;
    }
    
    function step3(value2){
        return `step3_${value2}`;
    }
    
    function step2(value1){
        return `step2_${value1}`;
    }
    
    function step1(){
        return `step1_start `;
    }
    
    //控制流管理
    function* stepFunc () {
        let value1; yield value1 = step1();
        let value2; yield value2 = step2(value1);
        let value3; yield value3 = step3(value2);
        let value4; yield value4 = step4(value3);
        console.log(value4);
    }
    
    //顺序执行
    for(var i of stepFunc());
    

    13.Promise

    Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大
    例子
    要求:
    Ajax请求网络,json数据
    请求成功:显示数据
    请求失败:抛出异常
    局部刷新

    Promise对象的三种状态
    Pending(进行中)、Resolved(已完成,又称 Fulfilled)和Rejected(已失败)

    function ajax(url){
        var promise = new Promise(function(resolve,reject){
            var request = new XMLHttpRequest();
            request.open("GET",url)
            request.onreadystatechange = handler;
            request.responseType = "json"; //服务器响应数据的类型 json
            request.setRequestHeader("Accept","application/json");
            request.send();
    
            //回调
            function handler(){
                //4(完成)响应内容解析完成
                if(this.readyState !== 4){
                    return;
                }
                if(this.status == 200){
                    //请求成功:显示数据
                    resolve(this.response);
                }
                else{
                    reject(new Error(this.statusText));
                }
            }
        });
    
        return promise;
    }
    
    //指定resolve状态、reject状态的回调函数
    ajax('test1.json').then(
        //resolve
        json => alert(json.message),
        //reject,可选的
        e => console.log(e.message)
    );
    
    

    相关文章

      网友评论

          本文标题:ES6基础

          本文链接:https://www.haomeiwen.com/subject/ohtsxxtx.html