Class基本语法
ES6中引入了Class这个概念作为对象的模板,通过Class关键字可以定义类。
function Person (name, age) {
this.name = name; //this指向对象的实例
this.age = age;
}
Person.prototype.sayName = function () {
return this.name;
} //ES5 构造函数
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayName() {
return this.name;
}
} //ES6定义类 这样的写法只是为了看起来更像传统的面向对象语言
所有类的方法都可以添加到prototype对戏上,prototype对象的constructor属性直接指向“类”本身。类的内部定义的所有方法都是不可枚举的
constructor方法
constructor方法是类的默认方法,通过new命令生成对象实例时自动调用constructor方法。
class Foo {
constructor() {
return Object.create(null);
}
}
new Foo() instanceof Foo //false
//constructor默认返回实例对象(this),也可以指定
实例对象
实例对象的属性除非显式地定义在其本身(this对象),否则都是定义在原型上的 :
var p = new Person('Jersey', 20);
p.sayName() // 'Jersey'
p.hasOwnProperty('name'); //true
p.hasOwnProperty('sayName'); //false
name和age都是实例对象p自身的属性(因为定义在this变量上),而sayName方法是定义在原型上的。类的所有实例都共享一个原型对象
Class表达式
const MyClass = class Me {
getClassName() {
return Me.name;
}
};
let inst = new MyClass();
inst.getClassName(); //Me
Me.name //error: Me is not undefined
//相当于:
const MyClass = class {//do somenthing};
这是一个MyClass类而不是Me,Me只在Class的内部代码可用,指代当前类
立即执行的Class
var person = new class {
constructor(name) {
this.name = name;
}
sayName() {
return this.name;
}
}('Jersey');
person.sayName() //'Jersey'
Class的继承
Class之间可以通过关键字extends实现继承
class Per extends Person {}
上面的代码定义了一个Per类,该类继承了Person类的所有属性和方法,
class Per extends Person {
constructor(name, age, home) {
super(x, y); //调用父类的constructor(name, age)
this.home = home;
}
}
上面的代码中,constructor方法中出现了super关键字,它指代父类的实例(即父类的this对象)。子类必须在constructor方法中调用super方法,否则新建实例会报错。因为子类没有自己的this对象,而是继承了父类的this对象,必须调用super方法之后才能得到this对象。
类的prototype属性和 _proto_ 属性
ES5的实现中,每个对象的_proto_属性指向对应的构造函数的prototype属性。Class同时存在两条继承链:
- 子类的_proto_属性构造函数的继承,总指向父类
- 子类prototype属性的_proto_属性表示方法的继承,总是指向父类的prototype属性
这两条继承链可以这样理解:作为一个对象,子类的原型(_proto_属性)是父类;作为一个构造函数,子类的原型(prototype属性)是父类的实例:
class A {}
class B extends A {}
B._proto_ === A //true 作为一个对象
B.prototype._proto_ === A.prototype //true 作为一个构造函数
extends的继承目标
extends关键字后面可以跟多种类型的值,上面的A只要是一个有prototype属性的函数,就能被B继承,所以A可以是任意函数。Object.getPrototypeOf()方法可以判断一个类是否继承了另一个类
原生构造函数的继承
ES5中,原生构造函数是无法继承的,比如我们不能定义一个Array, String的子类。这是因为子类无法获得原生构造函数的内部属性。ES6允许继承原生构造函数定义子类,ES6先新建父类的实例对象this,再用子类的构造函数修饰this,是父类的所有行为都可以被继承
class arr extends Array {
constructor(...args) {
super(...args);
}
} //这里定义了一个arr类,继承了原生构造函数Array
Class的 getter 和 setter
在Class内部可以使用get和set关键字对某个属性设置存值函数和取值函数
class Myclass {
constructor() {}
get prop() {
return 'getter';
}
set prop(value) {
console.log('setter:' + value)
}
}
let inst = new Myclass();
inst.prop = 123; // setter:123
inst.prop // 'getter' prop属性的赋值和取值行为都被定义了!
new.target属性
在构造函数中new.target属性返回new命令所作用的构造函数,如果构造函数不是通过new命令所调用的,就会返回undefined
class内部调用new.target返回当前class
class A {
constructor(length, width) {
console.log(new.target === A);
this.length = length;
this.width = width;
}
}
let B = new A(3, 3) //true
子类继承父类时new.target会返回子类
class C extends A {
constructor(length) {
super(length, length);
}
}
var d = new C(3); //false