3

1、单体模式下的对象

之前我们定义一个对象,使用的语法格式如下所示:

    <script>
        var name = 'qianqian';
        var age = 24;
        var person = {
            name:name,
            age:age,
            showName:function(){
                console.log(this.name);
            }
        };
        person.showName();
    </script>

在ES6当中声明定义一个对象的语法简洁化了。在ES6的对象语法当中,如果对象的属性名和属性值变量名相同,则只使用一个变量名即可,即使用name来代替name:name的写法。对象的方法定义可以从方法名:function(){}改为方法名(){}的写法。ES6当中单体模式下对象声明的语法格式如下所示:

    <script>
        let name = 'qianqian';
        let age = 24;
        let person = {
            name,
            age,
            showName(){
                console.log(this.name);
            }
        };
        person.showName();
    </script>

这两种写法的运行结果相同,均为输出qianqian

2、面向对象(class 和 constructor)

之前在面向对象当中类和构造函数的概念区分并不明显。示例代码如下所示:

    <script>
        //定义一个构造函数(类),在里面定义类的属性
        function Person(name,age){
            this.name = name;
            this.age = age;
        };
        //使用prototype定义类的方法
        Person.prototype.showName = function(){
            console.log(this.name);
        };
        //使用new来调用声明好的类,传入不同的实参来形成不同的实例对象。
        var p1 = new Person('qianqian',24);
        p1.showName();
    </script>

在ES6当中,类(class)和构造函数(constructor)的概念被区分开了。ES6当中使用面向对象的语法来定义一个类的示例代码如下所示:

    <script>
        //使用关键字class来定义一个Person类,在内部定义其属性与方法
        class Person{
            //在构造函数当中定义类的属性
            constructor(name,age){
                this.name = name;
                this.age = age;
            };
            //接下去分别定义类的方法,不需要再使用prototype
            showName(){
                console.log(this.name);
            };
        };
        //使用new来调用声明好的类,传入不同的实参,来生成不同的实例对象
        let p1 = new Person('qianqian',24);
        p1.showName();
    </script>

Person这个类生成的实例对象,都有一个默认的constructor属性,其属性值均为类名Person。示例代码如下所示:

    <script>
        class Person{
            constructor(name,age){
                this.name = name;
                this.age = age;
            };
            showName(){
                console.log(this.name);
            };
        };
        let p1 = new Person('qianqian',24);
        let p2 = new Person('meimei',23);
        console.log(p1.constructor == Person);
        console.log(p2.constructor == Person);
        console.log(p1.showName == p2.showName);
    </script>

其输出结果均为true

3、原型继承

假设有一个子类Worker类要继承父类Person类,在之前的面向对象的语法当中,我们在Worker类的构造函数当中,使用Person.apply(this,arguments);来完成对父类属性的继承。使用Worker.prototype = new Person();来实现对父类方法的继承。示例代码如下所示:

    <script>
        function Person(name,age){
            this.name = name;
            this.age = age;
        };
        Person.prototype.showName = function(){
            console.log(this.name);
        };
        function Worker(name,age){
            Person.apply(this,arguments);
        };
        //实现方法继承的语法格式为:子类.prototype = new 父类();
        Worker.prototype = new Person();
        //完成继承后,使用Worker类来生成实例
        var w1 = new Worker('qianqian',24);
        w1.showName();
    </script>

输出结果为qianqian

apply方法只接收两个参数,其中第二个参数必须是一个数组或者类数组,故可以将当前函数的arguments对象作为apply函数的第二个参数传入。apply方法改变的是函数的调用对象,此方法的第一个参数为改变后调用这个函数的对象。

而在ES6当中,实现原型继承的语法就相对简化了许多,我们使用class 子类 extends 父类{};即可完成子类继承父类全部属性和方法的功能。我们可以给继承的子类对象随意添加新的方法,但如果想要给子类添加新的属性,在其构造函数的内部,使用super(父类的形参列表);先调用一次父类的构造函数,避免覆盖父类的构造函数,然后再定义新的子类属性。示例代码如下所示:

    <script>
        class Person{
            constructor(name,age){
                this.name = name;
                this.age = age;
            };
            showName(){
                console.log(this.name);
            };
        };
        class Worker extends Person{
            constructor(name,age,job){
                //相当于先调用一次父类的构造函数,防止覆盖父类的构造函数
                super(name,age);
                //再定义新的子类属性
                this.job = job;
            };
            //可以随意给子类对象添加新的方法
            showName(){
                console.log(this.name);
            };
            showJob(){
                console.log(this.job);
            };
        };
        //调用子类生成实例对象
        let w1 = new Worker('qianqian',24,'student');
        w1.showName();
        w1.showJob();
    </script>

输出结果为qianqianstudent

4、模块化

ES6自带模块化,不过我们在使用ES6的这个新语法特性时,必须引入编译文件,因为浏览器端还没有完全支持。比如我们定义一个模块a.js(一般一个js文件即代表一个模块),在其内部定义了变量和函数之后,可以使用export default {变量名,函数名};的方式来导出。a.js的示例代码如下所示:

let a = 5;
function sum(){
    return 'haha';
};
export default {a,sum};

我们在主文件index.html当中使用import 自定义模块名 from '模块文件的相对路径';来实现模块的导入。其中index.html的示例代码如下所示:

    <script src="https://google.github.io/traceur-compiler/bin/traceur.js"></script>
    <script src="https://google.github.io/traceur-compiler/bin/BrowserSystem.js"></script>
    <script src="https://google.github.io/traceur-compiler/src/bootstrap.js"></script>
    <script type="module">  
        import A from './a.js';
        console.log(A.a);
        console.log(A.sum());
    </script>  

若第一次运行报如下错误:

图片描述

是因为我们没有把项目文件放在服务器环境下运行。

输出结果为5haha

5、Promise 对象

promise是ES6当中一个新的语法点,这个对象主要用来传递和处理异步操作的数据。promise对象只有三种状态:pending(等待)、resolve(成功)、reject(失败),并且其状态变化只能是从pendingresolve,或者是从pendingreject。其基本使用语法的示例代码如下所示:

    <script>  
        //一般在异步操作回调函数当中,声明一个Promise对象
        let p1 = new Promise(function(resolve,reject){
            if(异步操作成功){
                resolve(成功的数据);
                //把成功的数据传递下去
            }else{
                reject(失败的原因);
                //把失败的原因传递下去
            };
        });
        //promise对象p1具有then方法,接收两个函数参数,该方法仍然返回promise对象
        p1.then(function(value){
            /*当p1的回调函数当中执行resolve(成功的数据)时,执行该函数,形参value接收由resolve传递下来的成功的数据。*/
        },function(err){
            /*当p1的回调函数当中执行reject(失败的原因)时,执行该函数,形参err接收由reject传递下来的失败的原因。*/
        });
    </script>  

我们在前端使用ajax异步操作数据时,可以使用promise对象,示例代码如下所示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <script src="jquery-1.10.2.js"></script>
    <script>  
       $(function(){
               $('#btn').on('click',function(){
                   let p1 = new Promise(function(resolve,reject){
                       $.ajax({
                           url:'http://localhost/demo/1.txt',
                           type:'GET',
                           dataType:'text',
                           success:function(data){
                               resolve(data);
                           },
                           error:function(){
                               reject('failed');
                           }
                       });
                   });
                   p1.then(function(value){
                       console.log(value);
                   },function(err){
                       console.log(err);
                   });
               });
       });
    </script>  
</head>
<body>
    <button id="btn">button</button>
</body>
</html>

我们也可以在node.js的异步操作的回调函数当中使用promise对象。示例代码如下所示:

'use strict';
const fs = require('fs');
const path = require('path');
let target = path.join(__dirname,'./1.txt');
fs.readFile(target,function(err,data){
    let p1 = new Promise(function(resolve,reject){
        if(err){
            reject(err);
        }else{
            resolve(data);
        };
    });
    p1.then(function(data){
        console.log(data.toString());
    },function(err){
        console.log(err);
    });
});
5.1、promise对象的方法

1、 .then()

该方法在前面有详细介绍,其示例代码如下所示:

<script>  
     let p1 = new Promise(function(resolve,reject){
         resolve(1);
     });
     p1.then(function(value){
         alert(value);
         return value + 1;
     },function(value){
         alert(value);
         return value + 2;
     }).then(function(value){
         alert(value);
     });
</script>  

先弹出1,再弹出2

2、.catch()

该方法用于捕获异常信息。其示例代码如下所示:

    <script>  
         let p1 = new Promise(function(resolve,reject){
             resolve(1);
         });
         p1.then(function(value){
             throw value;
         }).catch(function(e){
             alert(e);
         });
    </script>  

输出结果为弹出数字1

5.2、Promise类身上的方法

1、 Promise.resolve()

这个方法可以生成一个成功的promise对象。该方法的参数可以是一个单纯的值或数组,也可以是另一个promise的执行结果。示例代码如下所示:

    <script>  
         let p1 = Promise.resolve([1,2,3]);
         p1.then(function(value){
             console.log(value[2]);
         },function(err){
             alert('failed');
         });
    </script>  

输出结果为3

2、 Promise.reject()

这个方法可以生成一个失败的promise对象。示例代码如下所示:

    <script>  
         let p1 = Promise.reject('failed');
         p1.then(function(value){
             alert('success')
         },function(err){
             alert(err);
         });
    </script>  

弹出结果为'failed'

3、 Promise.all()

该方法默认接收一个数组,其中数组元素均为promise对象。这个方法可以将多个promise对象组合,包装成一个全新的promise对象。

这个全新的promise对象也有then方法,当其参数当中所有的promise对象都成功时,才会执行then方法当中的第一个参数函数,此时该函数的形参代表一个数组,里面的值按顺序出现。示例代码如下所示:

    <script>  
         let p1 = Promise.resolve(1);
         let p2 = Promise.resolve(2);
         let p3 = Promise.resolve(3);
         Promise.all([p1,p2,p3]).then(function(value){
             console.log(value);
         },function(err){
             console.log('failed');
         });
    </script>  

其输出结果为[1,2,3]

在其参数数组当中只要出现失败的promise对象,就会执行then方法当中的第二个参数函数,形参仅包含最先出现的那个失败的promise对象当中的值。示例代码如下所示:

    <script>  
         let p1 = Promise.resolve(1);
         let p2 = Promise.reject(2);
         let p3 = Promise.reject(3);
         Promise.all([p1,p2,p3]).then(function(value){
             console.log('success' + value);
         },function(err){
             console.log('failed' + err);
         });
    </script>  

其输出结果为'failed2'

4、 Promise.race()

该方法默认接收一个数组,其中数组元素均为promise对象。这个方法选取最先到达的那个promise结果,该方法的返回结果也为一个promise对象。示例代码如下所示:

    <script>  
         let p1 = new Promise(function(resolve,reject){
             setTimeout(resolve('one'),50);
         });
         let p2 = new Promise(function(resolve,reject){
             setTimeout(resolve('two'),100);
         });
         Promise.race([p1,p2]).then(function(value){
             console.log(value);
         },function(err){
             console.log(err);
         });
    </script>  

其输出结果为'one'

6、Generator(生成器)

生成函数与普通函数在语法格式上的区别为,在函数名前面有*号,一般紧跟在function的后面。在生成器函数的内部,有一种类似与return的语法,关键字yieldyield语句可以用于遍历函数内部的状态)。二者的区别是,普通函数只能return一次,而生成器函数可以yield多次。在生成器函数的执行的过程中,遇到yield表达式立即暂停,后续可以恢复执行状态。示例代码如下所示:

    <script> 
        //声明一个生成器函数show 
         function* show(){
             yield 'hello';
             yield 'world';
             yield 'ES6';
             return 'all';
         };
         //生成器函数先调用一次,用变量res来接收该函数执行的返回值
         let res = show();
         /*这个返回值身上自带方法.next(),类似于开始进行状态遍历,该方法每调用一次,都会返回一个对象,有value和done这两个属性,value的属性值为每次yield后面对应的值,done的属性值是一个布尔值,代表状态遍历是否结束。*/
         console.log(res.next());
         console.log(res.next());
         console.log(res.next());
         console.log(res.next());
         console.log(res.next());
    </script>  

其输出结果为:

图片描述

生成器函数可以放在对象内部,作为对象的一个方法。其示例代码如下所示:

    <script> 
        var json1 = {
            *show(){
                yield 'hello';
                yield 'world';
                return 'all';
            }
        };
        var json2 = {
            show:function*(){
                yield 'xixi';
                yield 'haha';
                return 'so';
            }
        };
        var res1 = json1.show();
        console.log(res1.next());
        console.log(res1.next());
        console.log(res1.next());
        var res2 = json2.show();
        console.log(res2.next());
        console.log(res2.next());
        console.log(res2.next());
    </script>  

其输出结果为:

图片描述

我们可以使用for...of来循环生成器函数,示例代码如下所示:

    <script> 
        function* show(){
            yield 'hello';
            yield 'world';
            yield 'ES6';
            return 'all';
        };
        for(let v of show()){
            console.log(v);
        };
    </script>  

其输出结果为:

图片描述

生成器函数的yield表达式语句本身没有返回值,或者说总是返回undefinednext()方法可以带一个参数,该参数会被当做上一条yield语句的返回值。示例代码如下所示:

    <script> 
        function* show1(){
            let a = yield 'hello';
            return a;
        };
        let res1 = show1();
        console.log(res1.next());
        console.log(res1.next());
        function* show2(){
            let a = yield 'hello';
            return a;
        };
        let res2 = show2();
        console.log(res2.next());
        console.log(res2.next('world'));
        function* show3(){
            for(let i = 0; i < 10; i++){
                let a = yield i;
                if(a){
                    i = -1;
                };
            };
        };
        let res3 = show3();
        console.log(res3.next());
        console.log(res3.next());
        console.log(res3.next(true));
        console.log(res3.next());
    </script>  

其输出结果为:

图片描述


倩儿爱甜食
477 声望62 粉丝

一切都是最好的安排 ^-^ !