乐趣区

ES6-class-characteristics

概述

class (类)作为对象的模板被引入,可以通过 class 关键字定义类。类简要说明
类的本质是 function, 是基本原型继承的语法糖。所以,JS 中继承的模型是不会被改变的。
类既然是函数,那与函数有何不同呢?我们为什么要使用类呢?
有时间,先看一下 MDN od

  • 函数声明可以被提升,而类声明与 let/const 声明类似,不能被提升,也就是在真正执行声明之前,它们会一直存在于临时死区中。
  • 类声明中的所有代码将自动运行在严格模式下,而且无法强行让代码脱离严格模式。
  • 类中的所有方法,都是不可枚举的。而普通自定义类型中,必须通过 Object.defineProperty()方法来指定某方法不可枚举。
  • 每个类都有一个 [[Construct]] 的内部方法,通过关键字 new 调用那些不含 [[Construct]] 的方法会导致程序抛出错误。
  • 使用除关键字 new 之外的方式调用构造函数会导致程序抛出错误。
  • 在类中修改类名会导致程序报错。

类声明

首先 class 关键字,然后是类的名字,其它部分的语法,类似于对象字面量方法的简写形式,但不需要在各元素之间使用逗号分隔。

class HelloClass {constructor(greeting) {this.greeting = greeting;}
    
    sayGreeting(){console.log(this.greeting);
    }
}

let hello = new HelloClass('Hello');
hello.sayGreeting();  // Hello

console.log(hello instanceof HelloClass);  // true
console.log(hello instanceof Object);  // true

console.log(typeof HelloClass);  // function
console.log(typeof HelloClass.prototype.sayGreeting); // function

分析:

  1. constructor 为保留方法名,是用来构建对象的,不可用作其它用途。
  2. 函数定义之前,不需要添加 function 关键字。
  3. 类的属性不可被赋予新值,HelloClass.prototype 是一个只可读类属性。

与之等价的 ES5 声明

let HelloClass = (function(){
    "use strict";
    const HelloClass  = function(greeting) {if (typeof new.target === 'undefined') {throw new Error("必须通过关键字 new 调用构造函数");
        }
        this.greeting = greeting;

        Object.defineProperty(HelloClass.prototype, "sayGreeting", {value: function() {if (typeof new.target !== 'undefined') {throw new Error("不可使用关键字 new 调用构造函数");
                }
                console.log(this.greeting);
            },
            enumerable: false,
            writable: true,
            configurable: true
        });        
    }
    return HelloClass;
}());

let hello = new HelloClass('Hello');
hello.sayGreeting();

console.log(hello instanceof HelloClass);
console.log(hello instanceof Object);

console.log(typeof HelloClass);
console.log(typeof HelloClass.prototype.sayGreeting);

类表达式

类表达式可以是被命名的或匿名的。赋予一个命名类表达式的名称是类的主体的本地名称。和 function 的表达式类似, 但不会像函数声名或和函数表达式一样被提升。

/* 匿名类 */ 
let Rectangle = class {constructor(height, width) {
    this.height = height;
    this.width = width;
  }
};
console.log(typeof Rectangle); // function
/* 命名的类 */ 
let Rectangle = class Rectangle1 {constructor(height, width) {
    this.height = height;
    this.width = width;
  }
};
console.log(typeof Rectange); // function
console.log(typeof Rectange1); // undefined

在 JS 中,函数为一等“公民”,可以传入函数,也可以从函数中返回,还可以赋值给变量的值。 也是 JS 中的一等公民。

访问器

- getter
- setter
class Rectangle {
    // constructor
    constructor(height, width) {
        this.height = height;
        this.width = width;
    }
    // Getter
    get area() {return this.calcArea()
    }
    // Method
    calcArea() {return this.height * this.width;}
}
const square = new Rectangle(10, 10);

console.log(square.area);
// 100

可计算成员

const methodName = "sayGreeting";
class HelloClass {constructor(greeting) {this.greeting = greeting;}
    
    [methodName]() {console.log(this.greeting);
    }
}

let hello = new HelloClass('Hello');
hello.sayGreeting(); // Hello
hello[methodName](); // Hello

可计算访问器属性。

const propertyName = "greeting";
class HelloClass {constructor() { }
    
    get [propertyName]() {return this.greetingStr;}
    set [propertyName](value) {this.greetingStr = value;}
}

let hello = new HelloClass();
hello.greeting = 'Hello';
console.log(hello.greeting);

生成器方法

class NormClass {*createIterator() {
        yield 1;
        yield 2;
        yield 3;
    }
}
let instance = new NormClass();
let iterator = instance.createIterator();
console.log(iterator.next());  // {value: 1, done: false}
console.log(iterator.next());  // {value: 2, done: false}
console.log(iterator.next());  // {value: 3, done: false}
console.log(iterator.next());  // {value: undefined, done: true}

为类定义默认迭代器。

class Collection {constructor() {this.items = [];
    }

    *[Symbol.iterator]() {yield *this.items.values();
    }
}

var coll = new Collection();
coll.items.push(1);
coll.items.push(2);
coll.items.push(3);
for (let i of coll) {console.log(i);
}
// 1
// 2
// 3

静态成员

class Animal {speak() {return this;}
    static eat() {return this;}
  }
  
  let obj = new Animal();
  console.log(obj.speak()); // Animal {}
  let speak = obj.speak;
  console.log(speak()); // undefined
  
  console.log(Animal.eat()); // class Animal
  let eat = Animal.eat;
  console.log(eat()); // undefined
退出移动版