一、类的由来
1.1 工厂函数
ES5时批量生成实例对象的传统方法是通过工厂函数
function Person(name, age) {
var obj = {}
obj.name = name
obj.age = age
obj.run=()=>{
console.log('i am running');
}
return obj
}
var foo = Person('foo',18)
1.2 构造函数
引入关键字new
function Person(name, age) {
this.name = name
this.age = age
this.run = () => {
console.log(this.name + ' running');
}
}
var foo = new Person('foo', 18)
每一个Person实例都有一个独立的run方法,高度开辟空间,可添加到Person函数的原型中
Person.prototype.run=function(){
console.log(this.name +"running");
}
foo.run() // foo running
二、类的声明
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。
2.1 Class 关键字
用class 改写上述例子
class Person {
constructor(name,age) {
this.name = name
this.age = age
}
run(){
console.log(this.name + " running");
}
}
var foo = new Person('foo', 18)
foo.run()
2.2 static 关键字
类的所有方法都定义在类的prototype属性上面。
实例访问类定义的方法是通过_proto_访问类原型上的方法
class Person {
constructor(name,age) {
this.name = name
this.age = age
}
}
Person.prototype.run=()=>{
console.log(this.name + " running");
}
var foo = new Person('foo', 18)
foo.__proto__.run()
可用关键字static将方法挂载到类的属性
class Person {
constructor(name,age) {
this.name = name
this.age = age
}
static run(){
console.log(this.name + " running");
}
}
Person.run()
2.3 constructor方法
constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加
class Point {
}
// 等同于
class Point {
constructor() {}
}
可通过return返回另一个对象
class Person {
constructor(name,age) {
this.name = name
this.age = age
return {}
}
}
var foo = new Person('foo', 18)
foo instanceof Person // false
2.4 getter 和 setter
与 ES5 一样,在“类”的内部可以使用get和set关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为。
class Person {
constructor() {
}
get name() {
return 'foo'
}
set name(name) {
console.log(name);
}
}
var foo = new Person()
console.log(foo.name); // foo
foo.name = 'bar' // bar
三、类的事项
3.1 严格模式
类和模块的内部,默认就是严格模式,所以不需要使用use strict指定运行模式。只要你的代码写在类或模块之中,就只有严格模式可用。考虑到未来所有的代码,其实都是运行在模块之中,所以 ES6 实际上把整个语言升级到了严格模式。
3.2 不存在提升
类不存在变量提升(hoist),这一点与 ES5 完全不同。
new Foo(); // ReferenceError
class Foo {}
上面代码中,Foo类使用在前,定义在后,这样会报错,因为 ES6 不会把类的声明提升到代码头部。这种规定的原因与继承有关,必须保证子类在父类之后定义。
3.3 name 属性
类的name属性总是返回紧跟在class关键字后面的类名。
class Person {
constructor() {
}
}
Person.name // Person
3.4 Generator 方法
如果某个方法之前加上星号(*),就表示该方法是一个 Generator 函数
class Person {
constructor(...args) {
this.args = args;
}
* [Symbol.iterator]() {
for (let arg of this.args) {
yield arg;
}
}
}
for (let x of new Foo('foo', 'bar')) {
console.log(x);
}
// foo
// bar
Symbol.iterator方法返回一个Foo类的默认遍历器,for...of循环会自动调用这个遍历器。