es6 Class
一、 概述
在 ES6 中,class (类)作为对象的模板被引入,可以通过 class 关键字定义类。
class 的本质是 function。
它可以看作一个语法糖,让对象原型的写法更加清晰、更像面向对象编程的语法。
二、 写法
1. new 的过程
- 创建空对象
- 执行构造函数
- 改变 this 指向到空对象
- 设置空对象的原型和构造函数等属性
function myNew() {
// 创建一个新对象
var obj = {};
// 拿到构造函数,因为构造函数是第一个参数,arguments里面的其余的参数就是构造函数的参数
var constructorFunction = [].shift.call(arguments);
// 此时的arguments已经是去掉了第一个参数的arguments
var params = arguments;
// 这句是改变constructorFunction的this指向到obj并且执行constructorFunction这个函数
var res = constructorFunction.apply(obj, params);
// res是否 Object 实例的对象的方法
return res instanceof Object ? res : obj;
}
2. es5 写法
function Dog() {
this.type = "Dog";
}
Dog.prototype.run = function() {
console.log("running");
};
let dog = new Dog();
console.log(dog);
3. es6 写法
class Cat {
//构造函数
constructor() {
console.log("在Cat的构造函数中");
this.type = "cat";
}
//Cat.prototype.jump
jump() {
console.log("jump");
}
}
let cat = new Cat();
console.log(cat);
三、 继承
1. es5 写法
function Dog() {
this.type = "Dog";
}
Dog.prototype.run = function() {
console.log("running");
};
function Naidog() {
this.type = "奶狗";
}
//重新赋一个对象作为子类的原型
Naidog.prototype = new Dog();
Naidog.prototype.constructor = Naidog;
console.log(new Naidog());
2. es6 写法
class Cat {
//构造函数
constructor() {
console.log("在Cat的构造函数中");
this.type = "cat";
}
//Cat.prototype.jump
jump() {
console.log("jump");
}
}
//class 子类名 extends 父类名
class Jumao extends Cat {
constructor() {
super();
//作为对象使用
//super.constructor === cat
console.log(super.constructor);
this.type = "橘猫";
}
eat() {}
}
console.log(new Jumao());
3. 详解
Class 可以通过extends关键字实现继承,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多。
1️. 子类必须在constructor方法中调用super方法,否则新建实例时会报错。
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y); // 调用父类的constructor(x, y)
this.color = color;
}
toString() {
return this.color + ' ' + super.toString(); // 调用父类的toString()
}
}
这是因为子类自己的this对象,必须通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后对其加工,加上子类自己的实例属性和方法,如果不调用super方法,子类就得不到this对象。
2️. 父类的静态方法,也会被子类继承
class A {
static hello() {
console.log('hello world');
}
}
class B extends A {
}
B.hello() // hello world
上面代码中,hello()是A类的静态方法,B继承A,业绩承了A的静态方法。
3. Object.propotypeOf()
Object.propotypeOf方法可以用来从子类上获取父类。
Object.propotypeOf(colorPoint) === Point
//true
因此,使用这个方法判断,一个类是否继承了另一个类,
4. super关键字
super
这个关键字,既可以当作函数使用,也可以当作对象使用。在这两种情况下,它的用法完全不同.
第一种情况, super
作为函数调用时,代表父类的构造函数。ES6 要求,子类的构造函数必须执行一次 super
函数。
第二种情况, super
作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。
5. 类的 prototype
属性和 __proto__
属性
大多数浏览器的ES5实现中,每一个对象都有一个 __proto__
属性,指向相应的构造函数的 prototype
属性。 Class作为构造函数的语法糖,同时有 prototype
属性和 __proto__
属性,因此同时存在两条继承链。
子类的 __proto__
属性,表示构造函数的继承,总是指向父类。 子类 prototype
属性的 __proto__
属性,表示方法的继承,总是指向父类的 prototype
属性。
class A {
}
class B extends A {
}
B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true
四、 传参
在es6中的对象的属性都是写在constructor里面,方法都是在原型身上。在这里面的代码用constructor约定了两个参数,然后用add()方法把参数相加
class Coder{
name(val){
console.log(val);
return val;
}
constructor(a,b){
this.a=a;
this.b=b;
}
add(){
return this.a+this.b;
}
}
let shuang=new Coder(1,2);
console.log(shuang.add());
五、 静态方法
类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果function前面加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。
class Cat {
static mew() {
return 'hello';
}
}
Cat.mew() // 'hello'
var buou = new Cat();
buou.mew()
// TypeError: buou.mew is not a function
注意,如果静态方法包含this关键字,这个this指的是类,而不是实例
class Foo {
static bar() {
this.baz();
}
static baz() {
console.log('hello');
}
baz() {
console.log('world');
}
}
Foo.bar() // hello
六、 实例属性的新写法
实例属性除了定义在constructor()方法里面的this上面,也可以定义在类的最顶层。写法对比:
//实例属性this._count定义在constructor()方法里面
class IncreasingCounter {
constructor() {
this._count = 0;
}
get value() {
console.log('Getting the current value!');
return this._count;
}
increment() {
this._count++;
}
}
//属性定义在类的最顶层,其它不变
class IncreasingCounter {
_count = 0;
get value() {
console.log('Getting the current value!');
return this._count;
}
increment() {
this._count++;
}
}
这种新写法的好处是,所有实例对象自身的属性都定义在类的头部,看上去比较整齐,一眼就能看出这个类有哪些实例属性。
七、 静态属性
静态属性指的是 Class 本身的属性,即Class.propName,而不是定义在实例对象(this)上的属性。
class Foo {
}
Foo.prop = 1;
Foo.prop // 1
目前,只有这种写法可行,因为 ES6 明确规定,Class 内部只有静态方法,没有静态属性。现在有一个提案提供了类的静态属性,写法是在实例属性法的前面,加上static关键字。
// 老写法 class Foo { // ... } Foo.prop = 1;
// 新写法(可以使用) class Foo { static prop = 1; }
> 参考链接:https://www.jianshu.com/p/0743e31cd911