javascript继承(四)—prototype属性介绍
js里每一个function都有一个prototype属性,而每一个实例都有constructor属性,并且每一个function的prototype都有一个constructor属性,这个属性会指向自身。这会形成一个非常有意思的链式结构。举例如下:
function Person(){
this.name =12;
}
console.log(Person.prototype);
console.log(Person.prototype.constructor);//输出Person,指向自身
console.log(Person.prototype.constructor.prototype.constructor);//输出Person,指向自身
/***再看一下这个类的输出,则会出现如下情况**/
function Person(){}
Person.prototype.name = 'xiaoming';
var p1 = new Person();
console.log(p1);
输出结果如下:
会把这个实例显示出来,展开如下。p1有一个原型属性,这个属性有一个构造方法Person(),而这个构造方法又有prototype属性,这个属性有constructor方法…
这里主要让我们了解一下prototype是属于类(或者说函数function)的属性,指向这个类的共有属性和方法,而constructor是实例的属性,指向它的构造函数(也可以说是类,js里构造函数和类是一个概念)。
通过前面的两篇文章
我们知道用prototype来实现继承可以使子类拥有父类的共有属性和方法,其它两种不行。所以这里主要讨论如何用prototype实现继承。
由于采用prototype继承父类的实例在javascript继承—继承的实现原理(1)中已有论述,下面着重介绍用prototype继承实现的几种方式。
方案一:
直接将父类的prototype属性赋给子类,同时用call继承父类的特权属性,然后再修改子类prototype的constructor
function Person(name,age){
this.name = name;
this.age = age;
} Person.prototype = {
sayHi:function(){
alert('hi');
}
} function Student(name,age,grade){
Person.call(this,name,age);
this.grade = grade;
} Student.prototype = Person.prototype;
//Student.prototype.constructor = Student;
Student.prototype.study = function(){
alert('study');
}
var p1 = new Person('xiaoming',10);
var s1 = new Student('xiaohong',9,3);
//p1.study();// p1.study is not a function 说明Person的实例没有study方法,即子类的共有方法没有被父类共享
console.log(p1);//Person { name="xiaoming", age=10, sayHi=function()}
console.log(s1);//Student { name="xiaohong", age=9, grade=3, 更多...}
console.log(p1.constructor);//Object()
console.log(s1.constructor);//Object() 子类父类实例相同都为Object /**
如果在原文中加上Student.prototype.constructor = Student;
则
console.log(p1.constructor);//Student()
console.log(s1.constructor);//Student() 子类父类实例相同都为Student
***/
这种方案经测试是行不通的,因为不管怎么变,子类和父类的实例都会共有相同的constructor,这种情形下修改子类的共有方法,同时会修改了父类的共有方法,说明此法不通。
方案二:
将父类的实例赋给子类的原型对象,同时使用call方法使子类继承父类的特权属性。
function Person(name,age){
this.name = name;
this.age = age;
} Person.prototype = {
constructor:Person,
sayHi:function(){
alert('hi');
}
} function Student(name,age,grade){
Person.call(this,name,age);
this.grade = grade;
} Student.prototype = new Person();
Student.prototype.constructor = Student;
Student.prototype.study = function(){
alert('study');
}
var p1 = new Person('xiaoming',10);
var s1 = new Student('xiaohong',9,3);
//p1.study();// p1.study is not a function 说明Person的实例没有study方法,即子类的共有方法没有被父类共享
console.log(p1);//Person { name="xiaoming", age=10, sayHi=function()}
console.log(s1);//Student { name="xiaohong", age=9, grade=3, 更多...}
console.log(p1.constructor);//Person(name,age) 父类的实例指向仍是父类
console.log(s1.constructor);//Student(name,age,grade) //子类的实例指向仍是子类
得到的结果基本符合我们继承的要求,但是这个继承实现方式所继承的是父类实例所有的属性和方法,即实例方法(也可以说是特权方法),每创建一个子类对象都会把父类的特权方法都复制一遍,这样会耗费资源并且是无意义的。这时创建子类的实例就相当于javascript创建对象的三种模式 中的第二种构造函数模式。
方案三:
function Person(name,age){
this.name = name;
this.age = age;
}
//第一种创建共有方法方式
Person.prototype.sayHi = function(){
alert('hi');
}
//第二种创建共有方法方式
/*--------------------------------------------------------
Person.prototype = {
constructor:Person,
sayHi:function(){
alert('hi');
}
}
-------------------------------------------------------*/ function Student(name,age,grade){
Person.call(this,name,age);
this.grade = grade;
} for(var i in Person.prototype){Student.prototype[i] = Person.prototype[i]} //第二种创建共有方法方式继承时需要加上这句,不然子类实例会指向Person
/*--------------------------------------------------------
Student.prototype.constructor = Student
-------------------------------------------------------*/
Student.prototype.study = function(){
alert('study');
}
var p1 = new Person('xiaoming',10);
var s1 = new Student('xiaohong',9,3);
//p1.study();// p1.study is not a function 说明Person的实例没有study方法,即子类的共有方法没有被父类共享
console.log(p1);//Person { name="xiaoming", age=10, sayHi=function()}
console.log(s1);//Student { name="xiaohong", age=9, grade=3, 更多...}
console.log(p1.constructor);//Person(name,age) 父类的实例指向仍是父类
console.log(s1.constructor);//Student(name,age,grade) //子类的实例指向仍是子类
/*--------------------------------------------------------
第二种方式
console.log(p1.constructor);//Person() 父类的实例指向仍是Person
-------------------------------------------------------*/
用prototype实现原型链继承。对于第三种创建共有方法,如果创建的时候不加constructor: Person,得到的父类实例会指向Object,是因为创建共有方法的时候直接将一个包含共有方法的Object对象赋给了父类的prototype属性,将父类原有的constructor属性Person修改为Object。所以会出现这种情形。
经过测试,这种继承方式是可行的。使用这种方式继承,可以看到基本实现了子类继承父类的所有属性和方法,并且子类的构造函数仍是子类,父类的构造函数是父类。自认为这是比较完美的方案。
javascript继承(四)—prototype属性介绍的更多相关文章
- javascript继承(五)—prototype最优两种继承(空函数和循环拷贝)
一.利用空函数实现继承 参考了文章javascript继承—prototype属性介绍(2) 中叶小钗的评论,对这篇文章中的方案二利用一个空函数进行修改,可以解决创建子类对象时,父类实例化的过程中特权 ...
- javascript 继承 inheritance prototype
* Rectangle继承Shape function Shape() { this.x = 0; this.y = 0; } Shape.prototype.move = function(x, ...
- javascript继承—prototype最优两种继承(空函数和循环拷贝)
一.利用空函数实现继承 参考了文章javascript继承-prototype属性介绍(2) 中叶小钗的评论,对这篇文章中的方案二利用一个空函数进行修改,可以解决创建子类对象时,父类实例化的过程中特权 ...
- JavaScript继承详解(四)
在本章中,我们将分析Douglas Crockford关于JavaScript继承的一个实现 - Classical Inheritance in JavaScript. Crockford是Java ...
- 谈谈javascript中的prototype与继承
谈谈javascript中的prototype与继承 今天想谈谈javascript中的prototype. 通常来说,javascript中的对象就是一个指向prototype的指针和一个自身的属性 ...
- Javascript 继承 call与prototype
function Parent(hello){ this.hello = hello; this.sayHello = function(){ alert(this.hello); } } Paren ...
- javascript继承机制的设计思想(ryf)
我一直很难理解Javascript语言的继承机制. 它没有"子类"和"父类"的概念,也没有"类"(class)和"实例" ...
- [原创]JavaScript继承详解
原文链接:http://www.cnblogs.com/sanshi/archive/2009/07/08/1519036.html 面向对象与基于对象 几乎每个开发人员都有面向对象语言(比如C++. ...
- 【JavaScript】重温Javascript继承机制
上段时间,团队内部有过好几次给力的分享,这里对西风师傅分享的继承机制稍作整理一下,适当加了些口语化的描述,留作备案. 一.讲个故事吧 澄清在先,Java和Javascript是雷锋和雷峰塔的关系.Ja ...
随机推荐
- 数据结构--树状数组(黑龙江省第八届大学生程序设计竞赛--post office)
例题来源: 题目: 1468: Post office 题目描述 There are N(N<=1000) villages along a straight road, numbered fr ...
- hdu Flow Problem (最大流 裸题)
最大流裸题,贴下模版 view code#include <iostream> #include <cstdio> #include <cstring> #incl ...
- [转]响应式网页设计:rem、em设置网页字体大小自适应
本文转自:http://www.cnblogs.com/aimyfly/archive/2013/07/19/3200742.html 「rem」是指根元素(root element,html)的字体 ...
- fdtd simulation, plotting with gnuplot, writting in perl
# 9月13日 于成都黄龙溪 1 #!/usr/bin/perl # Author : Leon Email: yangli0534@gmail.com # fdtd simulation , plo ...
- 怎么运用好ZBrush中Magnify膨胀笔刷
Magnify膨胀笔刷是ZBrush笔刷中经常使用的,利用该笔刷可绘制中心向四周膨胀的效果.本文内容向大家介绍ZBrush®中膨胀笔刷以便大家熟悉它的用法和特性. 查看更多内容请直接前往:http:/ ...
- 2014 Super Training #10 C Shadow --SPFA/随便搞/DFS
原题: FZU 2169 http://acm.fzu.edu.cn/problem.php?pid=2169 这题貌似有两种解法,DFS和SPFA,但是DFS怎么都RE,SPFA也要用邻接表表示边, ...
- Tsung测试openfire服务器
环境准备 安装Tsung.安装openfire.安装Spark Tsung使用 要对openfire进行压力测试,因此我们主要讲解如何利用jabber_register.xml在openfire上面注 ...
- xshell5.0实现中键复制
1. 右建点击黑色屏幕 2. 在打开选项 3. 勾选 ""
- 关于软件测试人员能力模型的建立(from知乎)
转自: http://www.zhihu.com/question/20254092 测试思维方面:1.测试基础理论(测试流程.测试的基础知识)2.测试用例设计方法论(黑盒.白盒)3.软件质量体系(建 ...
- 03SpringMvc_自定义的spring.xml配置文件和逻辑视图名
这篇文章的目的是实现Struts2中一种形式(封装视图的逻辑名称),在Struts2中Action处理后会返回"SUCCESS"这样,然后根据"SUCCESS" ...