天天看点

ES6学习-Class和Class的继承

说明:本文参考阮一峰的ECMAScript 6 入门

1.Class

类的由来

JavaScript语言中,生成实例对象的传统方法是通过构造函数。

function Person (name, age) {
	this.name = name
	this.age = age
}
Person.prototype.toString = function () {
	return `${name},${age}`
}

var per = new Person("wangwu", 19)
           

上面这种写法跟面向对象语言(C++、Java)差异很大,很容易让学习这门语言的程序员感到困惑。

ES6提供了更接近传统语言的写法,引入了class(类)这个概念,作为对象的模板。通过class关键字可以定义类。

新的Class写法只是让对象原型的写法更加清晰、更加面向对象编程的语法而已。上面代码用ES6的class写法,就是下面这样。

calss Person {
	constructor(name, age){
		this.name = name
		this.age = age
	}
	toString() {
		return `${this.name},${this.age}`
	}
}
var per = new Person("wangwu", 19)
           

上面代码,定义了一个类,里面有一个constructor方法,这就是构造方法,this代表实例对象。构造实例的时候,也是直接对类使用new命令,跟构造函数的用法完全一致。

Person类还定义了一个toString方法。注意,定义类的方法时候,不需要在前面加上关键字function,直接把函数定义放进去就可以了。另外方法之间,不需要逗号分隔,加了逗号会报错。

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

class Person {

}
typeof Person //function
Person === Point.prototype.constructor //true
           

上面代码说明,类的数据类型就是函数,类本身指向构造函数。类的所有方法都是定义在类的prototype属性上面。在类的实例上调用方法就是调用原型上的方法。

另外,类的内部所有定义的方法,都是不可枚举的(non-enumerable)。

注意点

  1. 严格模式,类和模块的内部,默认就是严格模式。考虑到未来所有的代码,其实都是运行在模块之中,所以 ES6 实际上把整个语言升级到了严格模式。
  2. 不存在提升,类不存在变量提升(hoist)。
  3. this指向,类的方法内部如果含有this,它默认指向类的实例。
  4. 静态方法,如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。如果静态方法包含this关键字,这个this指的是类,而不是实例。

2.CLass的继承

class是通过extends关键字来继承的,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多。

class Person {

}

class Student extends Person {

}
           

上面代码定义了一个Student类,该类通过extends关键字继承了Person类的所有属性和方法。

类的prototyppe属性和__proto__属性

大多数浏览器ES5实现之中,每一个对象都有__proto__属性,指向对应的构造函数的prototype属性。Class作为构造函数的语法糖,同时有prototype属性和__proto__属性。因此具有两条继承链。

(1)子类的__proto__属性,表示构造函数的继承,总是指向父类。

(2)子类的prototype的__proto__属性,表示方法的继承,总是指向父类的prototype属性。

class A {

}

class B extends A {
	
}

B.__proto__ === A //true
B.prototype.__proto__ === A.prototype
           

上面代码中,子类B的__proto__属性指向父类A,子类B的prototype属性的__proto__属性指向父类A的prototype属性。

这样的结果是因为,类的继承是按照下面的模式实现的。

class A {
}

class B {
}

// B 的实例继承 A 的实例
Object.setPrototypeOf(B.prototype, A.prototype);

// B 继承 A 的静态属性
Object.setPrototypeOf(B, A);

const b = new B();
           

下面这段代码是Object.setPrototypeOf方法的实现。

Object.setPrototypeOf = function (obj, proto) {
  obj.__proto__ = proto;
  return obj;
}
           

因此,就得到了上面的结果。

继续阅读