JS基础学习第七天:对象原型及原型式的继承

来源:互联网 发布:精雕编程软件 编辑:程序博客网 时间:2024/05/29 23:44

   通过原型这种机制,JavaScript中的对象从其他对象继承功能特性,这种继承机制与经典的面向对象变成语言的继承机制不同,本文将探讨这些差别,解释原型链如何工作,并了解如何通过prototype属相向已有的构造器添加方法

基于原型的语言?

===============

   JavaScript 常被描述为一种基于原型的语言 (prototype-based language)——每个对象拥有一个原型对象,对象以其原型为模板、从原型继承方法和属性。原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推。这种关系常被称为原型链 (prototype chain),它解释了为何一个对象会拥有定义在其他对象中的属性和方法。

   准确地说,这些属性和方法定义在Object的构造器函数(constructor functions)之上的prototype属性上,而非对象实例本身。

理解原型对象

   

   在 JavaScript 控制台输入 "person1.",你会看到,浏览器将根据这个对象的可用的成员名称进行自动补全:

   在这个列表中,你可以看到定义在 person1 的原型对象、即 Person() 构造器中的成员—— name、age、gender、interests、bio、greeting。同时也有一些其他成员—— watch、valueOf 等等——这些成员定义在 Person() 构造器的原型对象、即 Object 之上。下图展示了原型链的运作机制

    

prototype属性:继承成员被定义的地方

    继承的属性和方法是定义在 prototype 属性之上的(你可以称之为子命名空间 (sub namespace) )——那些以 Object.prototype. 开头的属性,而非仅仅以 Object. 开头的属性。prototype 属性的值是一个对象,我们希望被原型链下游的对象继承的属性和方法,都被储存在其中。

     1.可以检查例子中已有的prototype属性
     2.输出并不多,毕竟我们没有在自定义构造器的原型定义任何成员。缺省状态下,构造器的prototype属性初始为空白。输入Object.prototype,可以看到大量的方法

 

    JavaScript 中到处都是通过原型链继承的例子。比如,你可以尝试从String、Date、Number 和 Array 全局对象的原型中寻找方法和属性。它们都在原型上定义了一些方法,因此当你创建一个字符串时:可以看到字符串立即具有了一些有用方法。

constructor属性

   每个对象实例都具有constructor属性,他只想创建该实例的构造器函数

    

修改原型

    

    事实上,一种极其常见的对象定义模式是,在构造器(函数体)中定义属性、在 prototype 属性上定义方法。如此,构造器只包含属性定义,而方法则分装在不同的代码块,代码更具可读性。


原型式的继承

===========

   

function Person(first, last, age, gender, interests) {  this.name = {    first,    last  };  this.age = age;  this.gender = gender;  this.interests = interests;};
所有的方法都定义在构造器prototype上,比如:

Person.prototype.greeting = function() {  alert('Hi! I\'m ' + this.name.first + '.');};

    上面我们已经创建了一个Person的类,现在我们想要创建一个Teacher类,就像我们前面在面向对象解释时用的一样。这个类会继承Person的所有成员,同时也包括
    1.一个新的属性,subject -- 这个属性包含了教师教授的学科

    2.一个被更新的greeting()方法,这个方法打招呼听起来比一般的greeting()方法更正式一点 ---对于一个教授一些学生的老师来说。

定义Teacher()的构造函数

   首先第一件事就是创建一个Teacher() 构造器

function Teacher(first, last, age, gender, interests, subject) {  Person.call(this, first, last, age, gender, interests);  this.subject = subject;}
   这在很多方面看起来都和Person的构造器很像,但是这里有一些我们从没见过的奇怪玩意——call()函数。基本上,这个函数允许您调用一个在这个文件里别处定义的函数。第一个参数指明了在您运行这个函数时想对“this”指定的值,也就是说,您可以重新指定您调用的函数里所有“this”指向的对象。其他的变量指明了所有目标函数运行时接受的参数。
            所以在这个例子里,我们很有效的在Teacher()构造函数里运行了Person()构造函数(见上文),得到了和在Teacher()里定义的一样的属性,但是用的是传送给Teacher(),而不是Person()的值(我们简单使用这里的this作为传给call()this,意味着this指向Teacher()函数)。

从无参构造函数继承

      请注意,如果您继承的构造函数不从传入的参数中获取其属性值,则不需要在call()中为其指定其他参数。所以,例如,如果您有一些相当简单的东西:

    

function Brick() {  this.width = 10;  this.height = 20;}

您可以这样继承widthheight属性(以及下面描述的其他步骤):

function BlueGlassBrick() {  Brick.call(this);  this.opacity = 0.5;  this.color = 'blue';}

设置Teacher()的原型和构造器引用

******

每一个函数对象(Function)都有一个prototype属性,并且只有函数对象有prototype属性,因为prototype本身就是定义在Function对象下的属性。当我们输入类似var person1=new Person(...)来构造对象时,JavaScript实际上参考的是Person.prototype指向的对象来生成person1。另一方面,Person()函数是Person.prototype的构造函数,也就是说Person===Person.prototype.constructor(不信的话可以试试)

******

    到目前为止一切看起来都还行,但是我们遇到问题了。我们已经定义了一个新的构造器,这个构造器默认有一个空的原型属性。我们需要让Teacher()Person()的原型对象里继承方法。我们要怎么做呢?

  1.在您上的添加内容的下面加上以下这一行:

Teacher.prototype = Object.create(Person.prototype);

  1. 这里我们的老朋友create()又来帮忙了——在这个例子里我们用这个函数来创建一个和Person.prototype一样的新的原型属性值(这个属性指向一个包括属性和方法的对象),然后将其作为Teacher.prototype的属性值。这意味着Teacher.prototype现在会继承Person.prototype的所有属性和方法。

     2.在我们接下去做之前,还需要完成一件事 — 现在Teacher()prototypeconstructor属性指向的是Person(), 这是因为我们生成Teacher()的方式决定的。 将您写的页面在浏览器中打开,进入JavaScript控制台,输入以下代码来确认:
  
Teacher.prototype.constructor
     3.这或许会成为很大的问题,所以我们需要将其正确设置——您可以回到源代码,在底下加上这一行代码来解决:
Teacher.prototype.constructor = Teacher;

  4.当您保存并刷新页面以后,输入Teacher.prototype.constructor就会得到Teacher()

向Teacher()增加新的函数greeting()
  为了完善代码,您还需在构造函数Teacher()上定义一个新的函数greeting()。最简单的方法是在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 + '.');};

现在我们来键入代码,将下面的代码放到您的 JavaScript 代码下面从而来创建一个 Teacher()对象实例。
  
var teacher1 = new Teacher('Dave', 'Griffiths', 31, 'male', ['football', 'cookery'], 'mathematics');

当您保存代码并刷新的时候,试一下您的老师实例的属性和方法:
teacher1.name.first;teacher1.interests[0];teacher1.bio();teacher1.subject;teacher1.greeting();

前面三个进入到从Person()的构造器 继承的属性和方法,后面两个则是只有Teacher()的构造器才有的属性和方法。


原创粉丝点击