关于Class
ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,
作为对象的模板。通过class关键字,可以定义类。
基本上,ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,
新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
1.我们先用构造函数来构造一个对象:
function Point (x,y) {
this.x = x;
this.y = y;
}
Point.prototype.show = function () {
console.log('hello world');
}
var demo = new Point(1,2);
demo.show();
2.然后我们用Class类来改写一下:
class Point{
constructor(x,y){
this.x = x;
this.y = y;
}
show(){
console.log('hello world');
}
}
var demo = new Point(1,2);
demo.show();
代码定义了一个“类”,可以看到里面有一个constructor方法,这就是构造方法,而this关键字则代表实例对象。
注意,定义“类”的方法的时候,前面不需要加上function这个保留字,直接把函数定义放进去了就可以了。
另外,方法之间不需要逗号分隔,加了会报错。
3.Class数据类型:
class Point {}
console.log(typeof Point);
//function
console.log(Point === Point.prototype.constructor);
//true
我们发现类的数据类型就是函数,类本身就指向构造函数。
4.constructor方法
(1)constructor 方法 constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。
(2)constructor方法默认返回实例对象(即this),完全可以指定返回另外一个对象。
class Foo {
constructor() {
return Object.create(null);
}
}
console.log(new Foo() instanceof Foo);
//false
默认返回实例对象 但是更改后就是新的对象。
5.prototype属性
构造函数的prototype属性,在ES6的“类”上面继续存在。
事实上,类的所有方法都定义在类的prototype属性上面。
class Point {
constructor() {
this.x = 10;
alert(0);
}
toString() {
alert("1");
}
toValue() {
alert("2");
}
}
console.log(Point.prototype);
//{constructor: ƒ, toString: ƒ, toValue: ƒ}
另外要注意的是类内部所有定义的方法都是不可枚举的
class Point {
constructor (x,y) {
}
toString() {
console.log(1);
}
}
function Point1 () {
this.toString = function () {
console.log(1);
}
}
Point1.prototype.toValue = function () {
console.log(2);
}
var demo = new Point();
var demo1 = new Point1();
for (var prop in demo) {
console.log(prop);
//不可枚举
}
for (var prop in demo1) {
console.log(prop);
//toString
//toValue
}
6.类的实例共享一个原型对象:
class Point {}
var demo1 = new Point();
Point.prototype.say = function() {
console.log("hello");
};
var demo2 = new Point();
demo2.__proto__.printName = function() {
console.log("world");
};
var demo3 = new Point();
demo1.printName();
//hello
demo2.printName();
//hello
demo3.printName();
//hello
demo1.say();
//world
demo2.say();
//world
demo3.say();
//world
实例的__proto__ 指向构造函数的prototype
7.name属性
name 属性 由于本质上,ES6的Class只是ES5的构造函数的一层包装,所以函数的许多特性都被Class继承,包括name属性。
代码使用表达式定义了一个类。需要注意的是,
这个类的名字是MyClass而不是Me,Me只在Class的内部代码可用,指代当前类。
如果Class内部没用到的话,可以省略Me,也就是可以写成下面的形式:
const MyClass = class Me {
getClassName() {
return Me.name;
}
};
let demo = new MyClass();
console.log(demo.getClassName());
//Me
同时Class不存在变量提升。
8.继承
Class之间可以通过extends关键字实现继承,这比ES5的通过修改原型链实现继承,要清晰和方便很多。
class Father {
constructor() {
this.name = 'He';
}
static show() {
console.log('hello dad');
}
eat(){
console.log('eat');
}
}
class Child extends Father {
constructor() {
super();
this.hobby = "sing";
}
static ChildShow(){
super.show();
}
childEat(){
super.eat();
}
}
var baby = new Child();
Child.ChildShow();
//hello dad
baby.childEat();
//eat
var dad = new Father();
Father.show();
//hello dad
静态方法继承的时候也需要借助我们的super方法,静态的super指向的是类,非静态方法指向的是原型。并且静态方法只能继承静态方法而不能去继承其他方法。这是因为静态方法直接在类上调用,而不是在类的实例上调用。普通方法是绑定在类的原型链上,两者继承的话会找不到对应方法而报错。