ES6 的类提供了几点明显的好处:

兼容当前大量的代码。
相对于构造器和构造器继承,类使初学者更容易入门。
子类化在语言层面支持。
可以子类化内置的构造器。
不再需要继承库;框架之间的代码变得更加轻便。
为将来的高级特性奠定了基础: traits (或者 mixins ), 不可变实例,等等。
使工具能够静态分析代码( IDE ,类型检测器,代码风格检测器,等等)。

ES6 类掩盖了 JavaScript 继承的本质;
类会禁锢你,因为强制性的 new。

  1. function Point(x, y){
  2. this.x = x;
  3. this.y = y;
  4. }
  5. Point.prototype.toString = function(){
  6. return "(" + this.x + "," + this.y + ")";
  7. }
  8. const p = new Point(1,2);
  9. console.log(p);//Point {x: 1, y: 2}
  10. console.log(p.toString());//(1,2)

主要缺点是,比较复杂,用到了this和prototype,编写和阅读都很费力。
上面的式子可以如下简单的理解:

  1. function Point(x, y) {
  2. this.x = x;
  3. this.y = y;
  4. }
  1. const p = new Point(1,2);
  1. Point.prototype.toString = function(){
  2. return "(" + this.x + "," + this.y + ")";
  3. }

上面代码的改用class来写

  1. class Points {
  2. constructor(x, y) {
  3. this.x = x;
  4. this.y = y;
  5. }
  6. toString(){
  7. return '(' + this.x + ',' + this.y + ')'; }
  8. }
  9. const ps = new Points(1, 2);
  10. console.log(ps);//Points {x: 1, y: 2}
  11. console.log(ps.toString());//(1,2)

ES6的类可以看作构造函数的另一种写法

  1. class Cty{
  2. //....
  3. }
  4. console.log(typeof Cty);//function
  5. console.log(Cty === Cty.prototype.constructor);//true
  6. //类的数据类型是函数,类本身就指向构造函数

上面可以理解为:类的数据类型是函数,类本身就指向构造函数

使用的时候,也是直接对类使用new命令,跟构造函数的用法完全一致

  1. class Bar {
  2. doStuff(){
  3. console.log('stuff');
  4. }
  5. }
  6. const b =new Bar();
  7. b.doStuff();//stuff

类的实例上面的方法,其实就是调用原型上的方法

  1. class B {};
  2. const BS = new B();
  3. console.log(BS.constructor === B.prototype.constructor);//true
  1. class Poin{
  2. constructor(x,y){
  3. this.x = x;
  4. this.y = y;
  5. }
  6. toString(){
  7. return `(${this.x},${this.y})`;
  8. }
  9. }
  10. class ColorPoin extends Poin{
  11. constructor(x,y,color){
  12. super(x,y);
  13. this.color = color;
  14. }
  15. toString(){
  16. return super.toString() + " in " + this. color;
  17. }
  18. }
  19. // 类型
  20. console.log(typeof Poin);//function
  21. //news实例
  22. const cp = new ColorPoin(25,8,'green');
  23. console.log(cp.toString());//(25,8) in green
  24. console.log(cp instanceof ColorPoin);//true
  25. console.log(cp instanceof Poin);//true
  26. // instanceof测试构造函数的prototype属性是否出现在对象的原型链中的任何位置

Javascript还提供了一个instanceof运算符,验证原型对象与实例对象之间的关系(instanceof测试构造函数的prototype属性是否出现在对象的原型链中的任何位置)。

下面是一些方法:

  1. class ObjAssign {
  2. constructor(name, age){
  3. this.name = name;
  4. this.age = age;
  5. }
  6. }
  7. Object.assign(ObjAssign.prototype,{
  8. toString(){
  9. console.log("string");
  10. },
  11. toValue(){
  12. console.log("value")
  13. }
  14. })
  15. const Obj = new ObjAssign('Bob',24);
  16. console.log(Obj);
  17. Obj.toString();//string
  18. Obj.toValue();//value
  19. console.log(Object.keys(ObjAssign.prototype));//["toString", "toValue"]
  20. console.log(Object.getOwnPropertyNames(ObjAssign.prototype));// ["constructor", "toString", "toValue"]
  1. class Pott {
  2. constructor(x,y){
  3. this.x = x;
  4. this.y = y;
  5. }
  6. toString() {
  7. return '(' + this.x + ',' + this.y + ')';
  8. }
  9. }
  10. const pott = new Pott(2,3);
  11. pott.toString();
  12. console.log(pott.hasOwnProperty("x"));//true
  13. console.log(pott.hasOwnProperty("y"));//true
  14. console.log(pott.hasOwnProperty("toString"));//false
  15. console.log(pott);
  16. console.log(pott.__proto__);
  17. console.log(pott.__proto__.hasOwnProperty("toString"));//true
  18. const p1 = new Pott(2,3);
  19. const p2 = new Pott(3,3);
  20. console.log(p1.__proto__ === p2.__proto__);//true
  21. p1.__proto__.printName = function(){
  22. return "Oops";
  23. }
  24. console.log(p1.printName());//Oops
  25. console.log(p2.printName());//Oops
  26. const p3 = new Pott(4,2);
  27. console.log(p3.printName());//Oops

prop属性有对应的存值函数和取值函数

  1. class MyClass {
  2. constructor(){
  3. //...
  4. }
  5. get prop(){
  6. return 'getter';
  7. }
  8. set prop(value){
  9. console.log("setter:" + value);
  10. }
  11. }
  12. const inst = new MyClass();
  13. inst.prop = 123;//setter: 123
  14. console.log(inst.prop)//getter
  1. class CustomHTMLElement {
  2. constructor(element) {
  3. this.element = element;
  4. }
  5. get html() {
  6. return this.element.innerHTML;
  7. }
  8. set html(value) {
  9. this.element.innerHTML = value;
  10. }
  11. }
  12. const descriptor = Object.getOwnPropertyDescriptor(
  13. CustomHTMLElement.prototype, "html"
  14. );
  15. console.log("get" in descriptor) // true
  16. console.log("set" in descriptor) // true
  1. const MyCl = class Me {
  2. getClassName() {
  3. return Me.name;
  4. }
  5. }
  6. const inMe = new MyCl();
  7. console.log(inMe.getClassName());//Me 只在class内部有定义
  1. const person = new class{
  2. constructor(name){
  3. this.name = name;
  4. }
  5. sayName(){
  6. console.log(this.name);
  7. }
  8. }('张三');
  9. person.sayName();//张三
  1. class Mine {
  2. //...
  3. }
  4. console.log(Mine.name);//Mine

this.printName = this.printName.bind(this)绑定解决

  1. class Logger{
  2. constructor(){
  3. this.printName = this.printName.bind(this);
  4. }
  5. printName(name = 'there'){
  6. this.print(`Hello ${name}`);
  7. }
  8. print(text){
  9. console.log(text);
  10. }
  11. }
  12. const logger = new Logger();
  13. const {printName} = logger;
  14. printName();//Hello there

如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是通过类来调用

  1. class Foo{
  2. static classMethod() {
  3. return 'hello';
  4. }
  5. }
  6. console.log(Foo.classMethod());//Hello
  7. const foo = new Foo();
  8. // console.log(foo.classMethod())//foo.classMethod is not a function
  1. class Fun {
  2. static bar(){
  3. this.baz();
  4. }
  5. static baz(){
  6. console.log('hello');
  7. }
  8. baz(){
  9. console.log('world');
  10. }
  11. }
  12. Fun.bar();//hello

父类静态方法可以被子类调用

  1. class Func{
  2. static classMethod() {
  3. return 'hello';
  4. }
  5. }
  6. class Baa extends Func{
  7. static classMethod(){
  8. console.log(super.classMethod + ",too") ;
  9. }
  10. }
  11. Baa.classMethod();//hello,too
  1. class IncreasingCounter{
  2. // constructor(){
  3. // this._count = 0;
  4. // }
  5. _count = 0;
  6. get value(){
  7. console.log('getting the current value');
  8. return this._count;
  9. }
  10. increment(){
  11. this._count++;
  12. }
  13. }

确保函数只能通过new命令调用

  1. function PersonMan(name){
  2. if(new.target !== undefined){
  3. this.name = name;
  4. }else{
  5. throw new Error('必须使用new命令生成实例')
  6. }
  7. }
  8. function PersonWoman(name){
  9. if(new.target === PersonWoman){
  10. this.name = name;
  11. }else{
  12. throw new Error('必须使用new命令生成实例')
  13. }
  14. }
  15. const personman = new PersonMan('张三');
  16. const personwoman = new PersonWoman('张三');
  17. // const personwoman2 = PersonWoman.call(PersonWoman,'张三');//报错

内部调用new.target会返回当前的class

  1. class Rectangle{
  2. constructor(length,width){
  3. console.log(new.target);
  4. console.log(new.target===Rectangle);
  5. this.length = length;
  6. this.width = width;
  7. }
  8. }
  9. const rectangle = new Rectangle(3,4);

子类继承父类时,new.target会返回子类

  1. class Rec{
  2. constructor(length,width){
  3. console.log(new.target);
  4. console.log(new.target===Rectangle);
  5. console.log(new.target===Square);
  6. this.length = length;
  7. this.width = width;
  8. //...
  9. }
  10. }
  11. class Square extends Rec{
  12. constructor(length,width){
  13. super(length,width);
  14. }
  15. }
  16. const squareA = new Square(3,6);//false/true

Javascript的国际标准ECMAScript第五版(目前通行的是第三版),提出了一个新的方法Object.create()。
使用Object.create()的方法,”类”就是一个对象,不是函数。
详细的可以看这篇文章:Javascript定义类(class)的三种方法

参考文章
探索ES6
ES6-阮一峰
Javascript定义类(class)的三种方法-阮一峰

版权声明:本文为yihan123原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/yihan123/p/12658077.html