【js】原型、原型链和对象继承
1. 原型
所有JavaScript
对象都能从原型prototype
中继承属性和方法。
可以将不变的属性和方法定义到原型中,节省内存开支。
我们都知道,通过构造函数可以定义所有属性和方法,
但是会存在一个问题,请看下面的例子:
function Person(name){
this.name = name;
this.age = 12;
this.hobit = function(){
console.log(this.name + '都喜欢吃零食。');
}
}
var zhangsan = new Person('张三');
zhangsan.hobit();
var lisi = new Person('李四');
lisi.hobit();
一个构造函数Person
,创建了两个对象zhangsan
和lisi
。
而这两个对象都拥有一个不变的属性age
和一个不变的方法hobit()
。
不免造成重复冗余,一旦对象创建多了,内存可能吃不消。
所以,应该将这些重复不变的东西,归纳到一个地方,
所有创建的对象都统一到这一个地方去取。
那么,prototype
很好的解决了这个问题。
function Person(name){
this.name = name;
}
Person.prototype.age = 12;
Person.prototype.hobit = function(){
console.log(this.name + '都喜欢吃零食。');
}
var zhangsan = new Person('张三');
zhangsan.hobit();
var lisi = new Person('李四');
lisi.hobit();
将不变的属性age
以及hobit()
方法定义到prototype
中。
这样,创建的zhangsan
和lisi
对象都拥有一个原型对象的引用,
然后通过这个引用可以获取原型对象中定义的公共属性和方法。
2. 原型链
console.log(lisi);
在控制台打印lisi
对象,分析原型。
从上图可以看出,
lisi
是 Person
构造函数的一个具体对象实例。
拥有两个成员:name
, __proto__
。
其中的 __proto__
便是Person
的原型对象。
拥有四个成员:age
,hobit
,constructor
,__proto__
。
constructor
是Person
的构造器。
__proto__
则指向了Object
原型。
原型里面包含原型,这就构成了一条原型链。
所有JavaScript
中的对象都是位于原型链顶端的Object
的实例。
当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。
3. 对象继承
以下代码示例来自 MDN
首先,需要一个父类Person
。
// 定义父类,将所有属性放到构造器中
function Person(first, last, age, gender, interests) {
this.name = {
first,
last
};
this.age = age;
this.gender = gender;
this.interests = interests;
};
// 将所有方法放到原型中
Person.prototype.greeting = function() {
alert('Hi! I\'m ' + this.name.first + '.');
};
然后定义Teacher
继承Person
。
// 定义子类
function Teacher(first, last, age, gender, interests, subject) {
// 通过 call() 调用父类构造方法
Person.call(this, first, last, age, gender, interests);
this.subject = subject;
}
// 复制父类的原型
Teacher.prototype = Object.create(Person.prototype);
// 修复构造器,不要指向父类,而是指向自己本身
Teacher.prototype.constructor = Teacher;
// 在自己的原型上,添加方法
Teacher.prototype.greeting = function() {
var prefix;
if(this.gender === 'male' || this.gender === 'Male' || this.gender === 'm' || this.gender === 'M') {
prefix = 'Mr.';
} else if(this.gender === 'female' || this.gender === 'Female' || this.gender === 'f' || this.gender === 'F') {
prefix = 'Mrs.';
} else {
prefix = 'Mx.';
}
alert('Hello. My name is ' + prefix + ' ' + this.name.last + ', and I teach ' + this.subject + '.');
};
最后,可以简单测试一下。
var teacher1 = new Teacher('Dave', 'Griffiths', 31, 'male', ['football', 'cookery'], 'mathematics');
teacher1.name.first;
teacher1.interests[0];
teacher1.bio();
teacher1.subject;
teacher1.greeting();