JS里类的创建

JS里类就是方法,创建一个类其实就是定义一个方法,比如:

function Person() {
    this.name = 'tomcat';
    this.age = 20;
}

这就定义了一个Person类,要使用的话,需要new一个实例,如下

var p = new Person();
console.log(p.name);
console.log(p.age);

类里当然也可以定义方法了,js里类本身就是方法,定义类的方法,就是在这个方法里写匿名方法

function Person() {
    this.name = 'tomcat';
    this.age = 20;
    this.run = function() {
        console.log(`${name} is running...`);
    }
}

也可以通过原型链prototype来定义方法

// 原型链方式定义属性
Person.prototype.sex = 'male';
// 原型链方式定义方法
Person.prototype.work = function() {
    console.log(`${this.name} is working...`);
}

这样定义的方法是个实例方法,调用要使用类的实例来调用,如下

var p = new Person();
p.run();
p.work();

通过构造方法定义方法和原型链定义方法区别:原型链方式定义的方法可以被多个实例共享

上面说了在类里定义方法,这种方法是实例方法,如何定义静态方法呢?

Person.getInfo = function() {
    console.log('i am an static method!!');
}

// 调用直接使用类名调用
Person.getInfo();

测试结果是,静态方法里没法用 this.name 来获取构造方法里的属性

JS里类的继承

JS里类的继承有两种,原型链 对象冒充 两种方式,而且这两种方式可以组合使用

冒充实现

定义一个类 People 类,让它继承 Person

function People() {
    Person.call(this);
}
// 调用
var people = new People();
people.run(); // 正常运行
people.work(); // 报错

对象冒充方式继承类,只能继承构造方法里定义的属性和方法,原型链定义的属性和方法是没法继承过来的

原型链继承

还是定义一个 People 类,通过原型链继承

function People() {

}

People.prototype = new Person();

// 调用
var people = new People();
people.run();
people.work();

原型链继承可以继承构造方法里的属性和方法也可以继承原型链里的属性和方法

但是原型链继承也是有问题的,看下面例子

如果Person对象里的属性是通过参数来实例化的

function Person(name, age) {
    this.name = name;
    this.age = age;
    this.run = function() {
        console.log(`name: ${this.name}, age: ${this.age}`);
    }
}
// 下面通过原型链继承
function People(name, age) {

}
People.prototype = new Person();
var people = new People('jetty', 22);
people.run(); // name: undefined, age: undefined

可以看到实例化子类的时候没法给父类传参

原型链+对象冒充

还是上面那个例子

function Person(name, age) {
    this.name = name;
    this.age = age;
    this.run = function() {
        console.log(`name: ${this.name}, age: ${this.age}`);
    }
}
Person.prototype.work = function() {
    console.log(`${this.name} is working...`);
}
// 下面通过原型链继承
function People(name, age) {
    Person.call(this, name, age);
}
People.prototype = new Person();
var people = new People('jetty', 22);
people.run(); // name: jetty, age: 22
people.work();

只需要在创建子类的构造方法里通过对象冒充的方式继承父类,并把参数传进去就可以了,下面打印就有子类传递的参数了

上面那种方法中原型链的继承用的是通过new Person()的方式来实现的,但上面子类里已经通过对象冒充的方式把父类的构造方法和属性都继承了,下面继承原型链属性方法就有些重复了,所以也可以写成下面这样

function Person(name, age) {
    this.name = name;
    this.age = age;
    this.run = function() {
        console.log(`name: ${this.name}, age: ${this.age}`);
    }
}
Person.prototype.work = function() {
    console.log(`${this.name} is working...`);
}
// 下面通过原型链继承
function People(name, age) {
    Person.call(this, name, age);
}
People.prototype = Person.prototype; // 这里只继承父类的原型链属性和方法,构造方法里的属性和方法就不继承了
var people = new People('jetty', 22);
people.run(); // name: jetty, age: 22
people.work();

参考

  • https://www.bilibili.com/video/av38379328?p=5
原文链接: https://tomoya92.github.io/2019/01/28/ES5-extends/