ES6构造函数class 和 ES5构造函数语法的区别

3,031 阅读5分钟

ES5的构造函数语法

  1. 创建对象的方法有两种:
  • 字面量 const obj = {}

  • 构造函数 const obj = new Object()

    构造函数就是JavaScript程序定义好的构造函数,我们直接使用就可以了

    构造函数是专门用于生成、定义对象的

  1. 通过构造函数生成的对象称为实例化对象

    实例化对象就是通过构造函数,生成的对象,称为实例化对象

  2. 构造函数和普通函数的区别:

  • 构造函数一定要和关键词 new一起使用。

    new 关键词具有特殊的功能,会自动给构造函数中定义一个对象,并且返回这个对象;我们只要对这个对象设定属性和方法就可以

  • 构造函数的语法规范规定:构造函数的函数名称,第一个字母必须大写,使用大驼峰命名法。

  • 构造函数给对象定义属性和方法的语法与一般函数不同

代码展示:

        function CrtObj(name,age,gender){
               // 在构造函数中:使用this来指代对象
               // 这个对象就是我们使用构造函数生成的实例化对象    
            // 定义属性
            // 给实例化对象,添加name属性,属性值是输入的name参数
            this.name = name;
            this.age = age;
            this.gender = gender;
            // 定义方法
            this.fun = function(){
                console.log(this.name,this.age,this.gender )
            }
        }
        // 通过自定义构造函数生成实例化对象
        const obj = new CrtObj('王逸',20,'男');
        console.log(obj);
        // 调用 对象/实例化对象 中的方法
        obj.fun();

输出结果:

函数的prototype属性

不同的实例化对象中,定义的是不同的方法、函数,会占用过多的内存空间。所以,一般将构造函数需要定义给实例化对象的方法,定义在函数的 prototype 属性中。

  1. 定义在 prototype 中的属性,就是写在 prototype 中的,不会写在实例化对象中。所以实例化对象中要添加属性,都是通过 this关键词来指向实例化对象。
  2. 在 prototype 中定义的方法/函数,也不会定义在实例化对象上,只会出现在函数的prototype 中。

代码展示:

      function fun(){}
      // 向 fun 函数 中的 prototype 中,添加属性 name 属性值 张三
      fun.prototype.gender = '女';
      // 向 fun 函数 中的 prototype 中,添加函数,函数名为f
      fun.prototype.f = function(){console.log(年龄18)};
      console.dir( fun );

实例化对象的__proto__属性

  1. 构造函数在生成实例化对象时,会将自己 prototype 这个空间的地址赋值给实例化对象 的__proto__来存储。 实际上,构造函数的 prototype和生成的实例化对象的__proto__指向的是同一个存储空间,可以相互调用数据。
  2. 当调用实例化对象中定义在函数本身上的函数/数据时,其实实例化对象本身中是没有这个函数的,会继续在 __proto__中寻找是否有这个方法函数 /数据。__proto__实际上指向的就是构造函数的 prototype。因为构造函数的 prototype 中是有这个方法函数/数据的,所以就可以正常调用。

原型对象、原型属性、原型链三者的联系

  1. 原型对象

    每一个函数本身就存在的prototype 属性,称为原型对象;是一个专门用来存储数据、函数等内容的空间。

  2. 原型属性

    每一个对象本身就存在的 __proto__属性,称为原型属性。实例化对象的原型属性指向的是创建实例化对象的构造函数的 prototype。

  3. 原型链

    原型链就是将所有相互关联的变量使用__proto__ 属性串联起来, 在调用数据时,会通过__proto__ 将所有相互关联的变量串联,只要有一个变量中有相应的属性,就会调用成功。

图示:

ES5构造函数存在的一个问题

在ES5中定义 prototype是在函数之外定义的,并且调用构造函数、生成实例化对象时,一定要在定义 prototype之后;否则如果先调用构造函数,生成的实例化对象就只有属性没有函数方法,因为定义方法的步骤还没执行呢。

例如:

         // 如果先调用构造函数,只有属性没有方法
        // 因为定义方法的步骤还没执行
        const obj1 = new Fun('王毅');
        obj1.f()          // 提前调用,执行结果是报错的
        function Fun(name){
            this.name = name;
        }
        // 在定义函数外,定义prototype
        Fun.prototype.f = function(){
            console.log(this.name)
        }
        const obj2 = new Fun('李明');
        obj2.f();

以上代码的执行结果会报错。

ES6中新增语法形式: class 类

  1. 作用和原理与ES5语法完全相同,只是语法格式和书写方式不同
  2. ES5和ES6语法的对比
  • ES5语法代码展示
        function Fun1(name,age){
            this.name  = name;
            this.age = age;
        }
        Fun1.prototype.f1 = function(){     //在构造函数之外定义prototype
            console.log(this.name , this.age);     
        }
        const obj1 = new Fun1('王毅',18);
        console.log(obj1);

ES6代码展示

        class Fun2{    //class后面的Fun2是类名,不是函数名,所以Fun2后面没有()
            constructor(name,age){   //constructor是构造器,()中定义的是class类的参数
                this.name = name;
                this.age = age;   //在构造器中定义实例化对象:this.属性=属性值;
                                 //与ES5中定义实例化对象的属性和属性值的语法形式完全相同,只是书写格式和书写位置不同。
            }
            f2(){
                console.log(this.name , this.age);
            }     //f2(){ }是函数方法,在ES6语法中:写在构造函数内,也是定义在函数的Protype中
        }
        const obj2 = new Fun2('李明',20);
        console.log(obj2);

输出结果完全相同:

  1. 区别:
  • ES6语法中定义的class类,不是function函数,不会被JavaScript程序与解析。所以class不能提前调用
  • function可以提前调用,但是提前调用时,只有属性没有方法。