Javascript面向对象与原型

2020/05/07 Javascript

对于Javascript而言对象其实就是键值对集合,而Javascript中几乎任何东西都可以看作是一个对象,所以Javascript同样也可以实现面向对象编程。但是在Javascript中并不区分类和实例,没有所谓类和类实例的概念。Javascript通过原型(prototype)和原型链来实现传统面向对象编程中类与类实例之间的关系。

类与类实例

类和实例是大多数面向对象编程语言的基本概念。

  • 类是对象的类型模板,例如,定义Student类来表示学生,类本身是一种类型,Student表示学生类型,但不表示任何具体的某个学生;

  • 实例是根据类创建的对象,例如,根据Student类可以创建出xiaoming等多个实例,每个实例表示一个具体的学生,他们全都属于Student类型。

原型

比方说我们想要创建类似于上述概念中的Studentxiaoming这样的关系。那么原型是指当我们想要创建xiaoming这个具体的学生时,我们并没有一个Student类型可用,但是我们有个叫做Student的对象:

var Student = {
    name: 'student',
    height: 1.7,
    run: function () {
        console.log(this.name + ' is running...');
    }
};

根据Javascript中原型和原型链的概念,我们可以使用Student对象来创建xiaoming这个对象:

var xiaoming = {
    name: 'Xiaoming'
};

xiaoming.__proto__ = Student;

注意到上述代码的最后一行把xiaoming中键名是__proto__的属性(成员)指向了对象Student,这样一来xiaoming就可以使用Student对象中的方法,而相同键名的属性(成员)则似乎会被覆盖:

xiaoming.name; // 'Xiaoming'
xiaoming.run(); // Xiaoming is running...

xiaoming有自己的name属性,但并没有定义run()方法。不过,由于小明是从Student继承而来或者说创建而来,只要Studentrun()方法,xiaoming也可以调用。而所谓的相同键名的成员也并不是被覆盖,只是因为xiaoming本身有name属性,所以直接调用xiaoming.name得到的就是xiaoming这个对象自己的name。如果调用xiaoming.__proto__.name自然也能获取Student对象中的name属性。这样一看,Javascript中原型和原型链的概念,既可以说像类的实例化,也可以说像类的继承。同样都是对象,xiaoming由于继承了Student而获得了Student中的方法和属性。

xiaoming ---__proto__---> Student
- name                  - name
                        - height
                        - run()

那么在xiaoming中调用run()方法,由于xiaoming本身并没有这一属性(成员),于是Javascript会自动向它的原型中去查找,顺着原型链一直找到尽头(也就是null),如果存在这样一个方法则调用,不存在则会报错。

如果你把xiaoming的原型指向其他对象:

var Fish = {
    swim: function () {
        console.log(this.name + ' is swimming...');
    }
};

xiaoming.__proto__ = Fish;

现在xiaoming已经无法run()了,它和它的原型链中都不存在run(),它只能调用swim()

xiaoming.swim(); // xiaoming is swimming...

在JavaScrip代码运行时期,你可以把xiaomingStudent变成Fish,或者变成任何对象。

Hint

在编写JavaScript代码时,最好不要直接用obj.__proto__去改变一个对象的原型,而且低版本的IE也无法使用__proto__Object.create()方法可以传入一个原型对象,并创建一个基于该原型的新对象,但是新对象什么属性都没有,因此,我们可以编写一个函数来创建xiaoming

// Prototype
var Student = {
    name: 'student',
    height: 1.7,
    run: function () {
        console.log(this.name + ' is running...');
    }
};

function createStudent(name) {
    // Create a new object inherited from Student
    var student = Object.create(Student);
    // Initialize
    student.name = name;
    return student;
}

var xiaoming = createStudent('Xiaoming');
xiaoming.run(); // Xiaoming is running...
xiaoming.__proto__ === Student; // true

这是创建原型继承的一种方法,JavaScript也还有其他方法来创建对象.

Search

    Table of Contents