【JavaScript】原型、原型链和对象继承

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,创建了两个对象zhangsanlisi
而这两个对象都拥有一个不变的属性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中。

这样,创建的zhangsanlisi对象都拥有一个原型对象的引用,
然后通过这个引用可以获取原型对象中定义的公共属性和方法。

2. 原型链

console.log(lisi);

在控制台打印lisi对象,分析原型。

从上图可以看出,

lisiPerson构造函数的一个具体对象实例。
拥有两个成员:name, __proto__

其中的 __proto__便是Person的原型对象。
拥有四个成员:age,hobit,constructor,__proto__

constructorPerson的构造器。
__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();

文章作者: 叶遮沉阳
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 叶遮沉阳 !
  目录