您的位置:首页 > Web前端 > JavaScript

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

2017-12-05 17:12 926 查看
   通过原型这种机制,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;
}
您可以这样继承
width
height
属性(以及下面描述的其他步骤):
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);

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

   
  2.在我们接下去做之前,还需要完成一件事 — 现在
Teacher()
prototype
constructor
属性指向的是
Person()
,
这是因为我们生成
Teacher()
的方式决定的。 将您写的页面在浏览器中打开,进入JavaScript控制台,输入以下代码来确认:

  
Teacher.prototype.constructor
     
3
b072
.这或许会成为很大的问题,所以我们需要将其正确设置——您可以回到源代码,在底下加上这一行代码来解决:

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()
的构造器才有的属性和方法。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐