zoukankan      html  css  js  c++  java
  • ES6

    1.Class类的介绍

    在ES6中新增了Class类的概念,让语法看起来更像是面向对象编程,其实这可以说是一个语法糖,ES5可以做到Class绝大部分功能,但也有一些不同。在ES6以前,可以通过构造函数来模拟类的概念,如下所示

    function Student(name,age){
    	this.name = name;
    	this.age  = age;
    }
    Student.prototype = {
    	constructor:Student,
    	show:function(){
    		console.log(this.name,this.age);
    	}
    };
    var xiaoming = new Student("xiaoming",20);
    xiaoming.show();
    xiaoming 20
    

    在引入了Class关键字后,可以这样做,如下所示

    class Person{
    	constructor(name,age){ //构造函数,默认返回this对象,如果强制返回其他对象也是被允许的
    		this.name = name;
    		this.age  = age;
    	}
    	show(){
    		console.log(this.name,this.age);
    	}
    }
    var s = new Person('test',30);
    s.show();
    test 30
    

    如上所示,便是ES6中类的定义,上面的constructor函数是类的构造函数,如果不写,则会自动创建一个constructor空构造函数,并且方法之间不允许有逗号,否则会报错,如下所示

    class Person{
    	show(){
    		alert("show");
    	},
    	hide(){
    		alert("hide");
    	}
    }
    var s = new Person();
    s.show();
    SyntaxError: invalid property id
    

    其实类的数据类型就是函数,类本身就指向构造函数,如下所示

    class Person{
    	constructor(name,age){
    		this.name = name;
    		this.age  = age;
    	}
    	show(){
    		console.log(this.name,this.age);
    	}
    }
    typeof Person
    "function"
    Person.prototype.constructor===Person
    true
    var p = new Person('test',20);
    undefined
    p.constructor
    function Person()
    p.constructor == Person
    true
    

    prototype属性在类上依旧存在,且类的方法都定义在类的prototype上面,如下所示

    var person = new Person('person',100);
    person.constructor === Person.prototype.constructor
    true
    

    因此可以在类的prototype上面定义的新方法为类扩展方法,如下所示

    Object.assign(Person.prototype,{show(){console.log(this.name);}});
    person.show();
    var a = new Person('nihao',20);
    a.show();
    
    person
    nihao
    

    但是类内部定义的方法是不可枚举的,这和ES5的构造函数还是有很大的区别,如下所示

    Object.getOwnPropertyNames(Person.prototype)
    Array [ "constructor", "show" ]
    Object.keys(Person.prototype)
    Array [  ]
    

    类的属性名可以使用表达式来定义,如下所示

    var show = 'show';
    class Test{
    	constructor(){
    		console.log("class test constructing...");
    	}
    	[show](){
    		console.log('show');
    	}
    }
    var test = new Test();
    test[show]();
    class test constructing...
    show
    

    在生成类的实例对象时,必须使用new关键字,如果直接像调用函数那样调用类,则会报错,如下所示

    var t1 = Test();
    TypeError: class constructors must be invoked with |new|
    

    类的所有实例共享一个原型,实例对象可以通过__proto__属性来访问原型,因此可以通过该属性为原型添加方法,如下所示

    test.__proto__.say = () => "hello prototype!";
    test.say();
    new Test().say();
    class test constructing...
    "hello prototype!"
    test.say()
    

    类Class也可以像Function一样,采用表达式形式来定义,如下所示

    var Aclass = class Bclass{
        constructor(){
            console.log(Bclass.name);//只有在类的内部才能访问到Bclass
        }
        show(){
            console.log('Aclass...');
        }
    };
    var a = new Aclass();
    a.show();
    Bclass
    Aclass...

    因此我们可以写出类似立执行函数的立执行类,如下所示

    var iifeInstance = new class{
        constructor(text){
            this.text = text;
        }
        show(){
            console.log(this.text);
        }
    }('iife testing...');
    iifeInstance.show();
    iife testing...

    类的定义不存在变量声明提升,这和ES5函数不同,如下图所示

    var a = new Dclass();
    class Dclass{
        
    }
    ReferenceError: can't access lexical declaration `Dclass' before initialization

    2.Class类的继承

    Class类的继承通过关键字extends来实现,和ES5通过修改原型链实现继承不同,如下所示

    class Person{
        constructor(name,age){
            this.name = name;
            this.age  = age;
        }
        print(){
            console.log(this.name,this.age);
        }
    }
    class Student extends Person{
        constructor(name,age,sno){
            super(name,age); //调用父类的构造函数,必须存在且需放在子类使用this对象之前,否则将报错
            this.sno = sno;
        }
        print(){
            super.print();
            console.log(this.sno);
        }
    }
    var s = new Student('xiaoming',20,"21014130217");
    s.print();
    xiaoming 20
    21014130217

    值得注意的是在定义子类构造函数时,一定要调用父类的构造函数且必须在子类使用this对象之前,因为子类不存在this对象,需要使用super得到父类的this对象,然后对其进行改写加工。如果缺省构造函数,则会自动创建一个默认的构造函数并调用父类的构造函数

    子类的原型prototype是父类的实例,有点像原型链继承,子类__proto__指向父类,这和函数的默认继承不同。如下所示

    Student.prototype instanceof Person
    true
    Student.prototype.__proto__ === Person.prototype
    true
    s.__proto__ === Student.prototype
    true
    Student.__proto__ === Person
    true

    可以使用Object.getPrototypeOf获取子类的父类,如下所示

    Object.getPrototypeOf(Student) === Person
    true

    3.原生构造函数的继承

    在ES5中不能继承原生的构造函数,例如Array,Date,Object,Function等等,但是在ES6中可以实现对原生构造函数的继承,如下所示

    class MyArray extends Array{
        constructor(){
            super();
            this.sign = "myArray";
        }
    }
    var myArr = new MyArray();
    console.log(myArr);
    myArr.push(1,2,3);
    console.log(myArr);
    Array [  ]
    Array [ 1, 2, 3 ]
    console.log(myArr.sign);
    "myArray"

    但是在继承Object时,有一点差异就是调用super给Object构造函数传参时会被忽略,这是ES6在实现时检测到不是以new Object形式调用构造函数,则忽略参数,如下所示

    class MyObj extends Object{
        constructor(arg){
            super(arg);
            this.sign = "MyObj";
        }
    }
    var myObj = new MyObj({x:1});
    console.log(myObj.x);
    undefined

    3.类的getter和setter函数,与ES5中的一样,都是对类属性存取行为的拦截,如下所示

    class Xclass{
        constructor(){
            console.log('Xclass initializing...');
        }
        set x(val){
            console.log(val);
        }
        get x(){
            return 2;
        }
    }
    
    var xIns = new Xclass();
    xIns.x = 4;
    console.log(xIns.x);
    Xclass initializing...
    4
    2

    4.类的静态方法与静态属性

    静态方法与属性不能被实例对象调用,静态方法可以在类内部定义,但静态属性则不能,静态方法可以被子类继承,如下所示

    class StaticTest{
        static test(){
            console.log('static...');
        }
    }
    class SubStatic extends StaticTest{
        show(){
            console.log('substatic show...');
        }
    }
    StaticTest.test();
    SubStatic.test();
    new SubStatic().show();
    new StaticTest().test();
    static...  2次
    substatic show...
    TypeError: (intermediate value).test is not a function

     静态属性的定义则是直接使用ClassName.prop形式来定义,如下所示

    class StaticTest{
        static test(){
            console.log('static...');
        }
    }
    StaticTest.xxx = "hello class static variable";
    StaticTest.xxx;
    "hello class static variable"

    5.new.target

    在ES6中为new命令添加了一个target属性,该属性在构造函数中返回new命令作用于的那个函数,如果不是以new命令调用构造函数则返回undefined,如下所示

    class Target{
        constructor(){
            console.log(Object.is(new.target,Target));
        }
    }
    var target = new Target();
    true

    有了这个属性,我们可以强制构造函数必须以new命令实例化,如下所示

    function Animal(name){
        if(!new.target) throw new Error('必须使用new实例化Animal');
        this.name = name;
    }
    var duck1 = new Animal('duck1');
    console.log(duck1.name);
    var duck2 = Animal('duck2');
    duck1
    Error: 必须使用new实例化Animal

    也可以用来模仿抽象类,不能被实例化,只能被继承使用

    class Car{
        constructor(brand){
            if(new.target === Car) throw new Error('Car类不能被实例化');
            this.brand = brand;
        }
    }
    class Baoma extends Car{
        constructor(brand){
            super(brand);
        }
        showBrand(){
            console.log(this.brand);
        }
    }
    var baoma = new Baoma('baoma');
    baoma.showBrand();
    baoma
    var car = new Car('car');
    Error: Car类不能被实例化

    在实例化子类时,父类的new.target指向的是子类。

      

     

  • 相关阅读:
    Jenkins tomcat 一键发布 (三)
    Jenkins docker 一键发布 (二)
    Jenkins docker 一键发布 (一)
    jenkins构建maven项目:找不到本地依赖包的解决办法
    Linux socket编程示例
    Linux虚拟机环境搭建
    Linux vim 配置
    vs2013 Qt5.7.0环境安装搭建
    Linux下如何生成core dump 文件
    QT5新建工程错误->无法打开源文件QtWidgets/QApplication
  • 原文地址:https://www.cnblogs.com/zmxmumu/p/5588431.html
Copyright © 2011-2022 走看看