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的构造器很像,但是这里有一些我们从没见过的奇怪玩意——
所以在这个例子里,我们很有效的在
从无参构造函数继承
请注意,如果您继承的构造函数不从传入的参数中获取其属性值,则不需要在
function Brick() {
this.width = 10;
this.height = 20;
}
您可以这样继承
function BlueGlassBrick() {
Brick.call(this);
this.opacity = 0.5;
this.color = 'blue';
}
设置Teacher()的原型和构造器引用
******
每一个函数对象(
******
到目前为止一切看起来都还行,但是我们遇到问题了。我们已经定义了一个新的构造器,这个构造器默认有一个空的原型属性。我们需要让
1.在您上的添加内容的下面加上以下这一行:
Teacher.prototype = Object.create(Person.prototype);
这里我们的老朋友
2.在我们接下去做之前,还需要完成一件事 — 现在
这是因为我们生成
3
b072
.这或许会成为很大的问题,所以我们需要将其正确设置——您可以回到源代码,在底下加上这一行代码来解决:
4.当您保存并刷新页面以后,输入
向Teacher()增加新的函数greeting()
为了完善代码,您还需在构造函数
现在我们来键入代码,将下面的代码放到您的 JavaScript 代码下面从而来创建一个
当您保存代码并刷新的时候,试一下您的老师实例的属性和方法:
前面三个进入到从
基于原型的语言?
===============
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()的构造器才有的属性和方法。
相关文章推荐
- js核心基础之理解原型对象以及原型继承(二)
- JS学习笔记——JavaScript继承的6种方法(原型链、借用构造函数、组合、原型式、寄生式、寄生组合式)
- 一步步学习javascript基础篇(5):面向对象设计之对象继承(原型链继承)
- js核心基础之理解原型对象以及原型继承(一)
- js核心基础之理解原型对象以及原型继承(三)
- JS 学习笔记--JS中的事件对象基础
- 笔记 - JS易忘基础知识(二)(关于对象和继承)
- JS面向对象基础讲解(工厂模式、构造函数模式、原型模式、混合模式、动态原型模式)
- JavaScript继承基础讲解(原型链、借用构造函数、混合模式、原型式继承、寄生式继承、寄生组合式继承)
- Js中的对象、构造函数、原型、原型链及继承
- js对象继承之原型链继承实例
- JS函数的原型及对象,对象方法,对象属性的学习
- 【web前端-理解js原型】理解Javascript中的原型对象、原型链和继承
- JS面向对象基础篇(封装 继承 多态)
- 【学习笔记六】 - js中 创建对象的模式与继承 及 js中实现块级作用域和函数私有变量 《js高程》6-7笔记
- JavaScript继承基础讲解,原型链、借用构造函数、混合模式、原型式继承、寄生式继承、寄生组合式继承
- 【MDNjs笔记】——入门——第三章——对象.构造函数.原型链.继承
- .Net学习笔记----2015-07-21(C#基础复习04,面向对象语法和继承复习)
- JS中Object对象的原型概念基础
- 深入js的面向对象学习篇(继承篇)——温故知新(三)