对于Javascript而言对象其实就是键值对集合,而Javascript中几乎任何东西都可以看作是一个对象,所以Javascript同样也可以实现面向对象编程。但是在Javascript中并不区分类和实例,没有所谓类和类实例的概念。Javascript通过原型(prototype)和原型链来实现传统面向对象编程中类与类实例之间的关系。
类与类实例
类和实例是大多数面向对象编程语言的基本概念。
-
类是对象的类型模板,例如,定义
Student
类来表示学生,类本身是一种类型,Student
表示学生类型,但不表示任何具体的某个学生; -
实例是根据类创建的对象,例如,根据
Student
类可以创建出xiaoming
等多个实例,每个实例表示一个具体的学生,他们全都属于Student
类型。
原型
比方说我们想要创建类似于上述概念中的Student
和xiaoming
这样的关系。那么原型是指当我们想要创建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
继承而来或者说创建而来,只要Student
有run()
方法,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代码运行时期,你可以把xiaoming
从Student
变成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也还有其他方法来创建对象.