关于JS中的constructor与prototype

在学习JS的面向对象过程中,一直对constructor与prototype感到很迷惑,看了一些博客与书籍,觉得自己弄明白了,现在记录如下:

我们都知道,在JS中有一个function的东西。一般人们叫它函数。比如下面的代码:

function Person(name)
{alert(name);
}
Person('js');//js

 




上面的代码中,Person的表现的确跟一般的函数没有什么区别,接着看下面的代码

function Person(name)
{this.name=name;this.showMe=function(){alert(this.name);}
};
var one=new Person('JavaScript');
one.showMe();//JavaScript

 



很多人见到了久违的new操作符,于是就叫Person为“类”,可是又没有关键字class的出现,觉得叫“类”有点勉强。于是退而求其次叫 Person为类的构造函数。这些概念好像都没有错,之所以出现这样的情况,可能是因为大家都学习了传统的面向对象语言(c++,c#,java等),还 有一种思维定势吧。为了让javascript也面向对象,要在javascript中找到与传统面向对象语言的影子。

可是按照javascript的说法,function定义的这个Person就是一个Object(对象),而且还是一个很特 殊的对象,这个使用function定义的对象与使用new操作符生成的对象之间有一个重要的区别。这个区别就是function定义的对象有一个 prototype属性,使用new生成的对象就没有这个prototype属性。

prototype属性又指向了一个prototype对象,注意prototype属性与prototype对象是两个不同的东西,要注意区别。在prototype对象中又有一个constructor属性,这个constructor属性同样指向一个constructor对象,而这个constructor对象恰恰就是这个function函数本身。

有点头晕,看下图吧:



不相信可以看下面的代码:

function Person(name)
{this.name=name;this.showMe=function(){alert(this.name);}
};var one=new Person('js');alert(one.prototype)//undefined
alert(typeof Person.prototype);//object
alert(Person.prototype.constructor);//function Person(name) {...};

 



上面的代码证明了one这个对象没有prototype属性。

我们接着看代码:

function Person(name)
{this.name=name;this.showMe=function(){alert(this.name);}
};Person.prototype.from=function()
{alert('I come from prototype.');
}var one=new Person('js');one.showMe();//js,这个结果没有什么好奇怪的
one.from();//I come from prototype.,这个结果有一点奇怪吧

 



要解释这个结果就要仔细研究一下new这个操作符了.var one=new Person('js');这个语句执行的过程可以分成下面的语句:

var one={};
Person.call(one,'js');

 



按照《悟透javascript》书中说的,new形式创建对象的过程实际上可以分为三步:
第一步是建立一个新对象(叫A吧);

第二步将该对象(A)内置的原型对象设置为构造函数(就是Person)prototype 属性引用的那个原型对象;

第三步就是将该对象(A)作为this 参数调用构造函数(就是Person),完成成员设置等初始化工作。

其中第二步中出现了一个新名词就是内置的原型对象,注意这个新名词跟prototype对象不是一回事,为了区别我叫它inobj,inobj就 指向了函数Person的prototype对象。在person的prototype对象中出现的任何属性或者函数都可以在one对象中直接使用,这个 就是javascript中的原型继承了。

又头晕了,上图吧!



这样one对象通过内置的原型对象inobj就可以直接访问Person的prototype对象中的任何属性与方法了。这也就解释了上面的代码 中为什么one可以访问form函数了。因为prototype对象中有一个constructor属性,那么one也可以直接访问 constructor属性。

function Person(name)
{this.name=name;this.showMe=function(){alert(this.name);}
};Person.prototype.from=function()
{alert('I come from prototype.');
}var one=new Person('js');one.showMe();//js,这个结果没有什么好奇怪的
one.from();//I come from prototype.,这个结果有一点奇怪吧
alert(one.constructor);//function Person(name) {...}
alert(Person.prototype.constructor);//function Person(name) {...}

 



接着看继承是如何实现的。

function Person(name)
{this.name=name;this.showMe=function(){alert(this.name);}
};Person.prototype.from=function()
{alert('I come from prototype.');
}function SubPerson()
{
}
SubPerson.prototype=new Person();var subOne=new SubPerson();
subOne.from();//I come from prototype.
alert(subOne.constructor);//function Person(name) {...};
alert(SubPerson.prototype.constructor);//function Person(name) {...};

 



继承的实现很简单,只需要把子类的prototype设置为父类的一个对象即可。注意这里说的可是对象哦!

那么通过prototype属性实现继承的原理是什么呢?还是先看图形说明,然后编写代码进行验证。



注意:红色的方框就是把子类与父类链接起来的地方。这个就应该是传说中的prototype链了吧。下面有代码进行验证。

function Person(name)
{this.name=name;this.showMe=function(){alert(this.name);}
};Person.prototype.from=function()
{alert('I come from prototype.');
}
var father=new Person('js');//为了下面演示使用showMe方法,采用了js参数,实际多采用无参数
alert(father.constructor);//查看构造函数,结果是:function Person(name) {...};
function SubPer()
{
}
SubPer.prototype=father;//注意这里
SubPer.prototype.constructor=SubPer;var son=new SubPer();
son.showMe();//js
son.from();//I come from prototype.
alert(father.constructor);//function SubPer(){...}
alert(son.constructor);//function SubPer(){...}
alert(SubPer.prototype.constructor);//function SubPer(){...}

 



根据上图的prototype链,还有代码的结果,我想应该明白为什么使用prototype能够实现

JS中的继承了吧。



本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/niuyongjie/archive/2009/11/15/4810835.aspx

转载于:https://www.cnblogs.com/myphoebe/archive/2012/04/10/2440974.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/434582.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

resolv.conf

文件/etc/resolv.conf配置DNS客户,它包含了主机的域名搜索顺序和DNS服务器的地址,每一行应包含一个关键字和一个或多个的由空格隔开的参数。下面是一个例子文件: search mydom.edu.cnnameserver 210.34.0.14nameserver 210.34.0.2合法的参数及…

C# 温故而知新:Stream篇(六)

C# 温故而知新:Stream篇(六) BufferedStream 目录: 简单介绍一下BufferedStream如何理解缓冲区?BufferedStream的优势从BufferedStream 中学习装饰模式    如何理解装饰模式    再次理解下装饰模式在Stream中的…

HDU 3306 Another kind of Fibonacci

题意:A(0) 1 , A(1) 1 , A(N) X * A(N - 1) Y * A(N - 2) (N > 2);给定三个值N,X,Y求S(N):S(N) A(0)2 A(1)2……A(n)2。 思路:原来我们讲的斐波那契数列是: F(0) 1, F(1) 1, F(N) F(N - 1) F(N…

Arm Linux交叉编译和连接过程分析(1)

一、配置内核(Kconfig) 我们配置内核是实质是根据众多目录下面的Kconfig文件中组合成我们需要的一个最佳选择,即最终在根目录下面生成的.config文件,而这个文件会在根目录Makefile下调用的。这一部分我们主要讨论整个SEP4020体系…

Arm Linux交叉编译和连接过程分析(2)

二、编译内核镜像过程 1、编译过程中涉及到到文件: /Makefile 编译产生顶层vmlinux镜像文件/scripts/Kbuild.include make过程中到一些基本定义 /scripts/Makefile.lib 编译内核时用到到函数库文件 /scripts/Makefile.build 内核编译到相关命令文件…

sql server 2008学习3 表组织和索引组织

表组织 表包含在一个或多个分区中,每个分区在一个堆或一个聚集索引结构包含数据行。堆页或聚集索引页在一个或多个分配单元中进行管理,具体的分配单元数取决于数据行中的列类型。 聚集表、堆和索引 SQL Server 表使用下列两种方法之一来组织其分区中的数…

Oracle备份standby,Oracle 11g 利用泠备份恢复standby库

Oracle 11g 利用泠备份恢复standby库1 开始在备库上进行泠备份先查好控制文件、redo、undo文件、数据文件的路径1.1 先关闭主库的归档日志传输SQL> ALTER system SETlog_archive_dest_state_2 DEFER;System altered.SQL>1.2 先关闭standby库SQL> shutdown immediate;D…

matlab单位阶跃响应与单位脉冲响应,python 已知响应函数求单位阶跃响应或脉冲响应...

最近学习自动控制原理,关于控制系统的一些,老师用布置了一些作业说要用matlab画,我试试python首先介绍一下所使用的库:control matplotlib sympy1.control库:用来计算脉冲响应与阶跃响应Paste_Image.png2.sympy&#x…

$_server['php_self'] 漏洞,Discuz! $_SERVER['PHP_SELF'] XSS Vulnerability

在common.inc.php文件的69行:$PHP_SELF $_SERVER[PHP_SELF] ? $_SERVER[PHP_SELF] : $_SERVER[SCRIPT_NAME];$SCRIPT_FILENAME str_replace(\\\\, /, (isset($_SERVER[PATH_TRANSLATED]) ? $_SERVER[PATH_TRANSLATED] : $_SERVER[SCRIPT_FILENAME]));$boardurl …

【前端破解系列之一】一分钟教你破解下载虾米音乐

虾米音乐网站上有很多高品质的音乐和精心组织的精选集,但普通用户只能试听,不能下载,下载的话需要使用“米”,这个“米”除了极少数的新手任务可以获得之外,基本上都要靠付费来购买,很多人没有网银或者没有…

网络编程常用接口的内核实现----sys_listen()

listen()函数仅在TCP服务器端调用,它做两个事情:将套接字转换到LISTEN状态和设置套接上的最大连接队列。listen()对应的内核实现为sys_listen(),下面开始对其实现作具体的分析。 一、sys_listen()函数 sys_listen()的源码实现及分析如下所示…

linux查看启动配置文件内容,Linux开机启动项的查看和设置方法总结

一、查看开机自启项1.Centos7自启项查看方式从Centos6的chkconfig改为:systemctl list-unit-files2.用grep过滤查看,比如:查看启动项:systemctl list-unit-files | grep enable查看sshd服务自启动情况:systemctl list-…

XP Embedded:不同的用户使用不同的外壳程序

摘要: 能够使应用程序成为外壳程序是 Windows XP Embedded 的关键功能之一。设备可以在自定义外壳程序而不是 Explorer 外壳程序中启动,这提供了两个好处。第一个好处是系统能够更快地启动。Explorer 外壳程序需要花费大量的时间来加载所有支持库和文件…

linux系统中 库分为静态库和,Linux系统中“动态库”和“静态库”那点事儿-【经典好文】...

今天我们主要来说说Linux系统下基于动态库(.so)和静态(.a)的程序那些猫腻。在这之前,我们需要了解一下源代码到可执行程序之间到底发生了什么神奇而美妙的事情。在linux操作系统中,普遍使用ELF格式作为可执行程序或者程序生成过程中的中间格式。ELF(Exec…

linux上的壁纸软件下载,Ubuntu 17.10上安装开源壁纸工具Wallch 4.0

在Ubuntu 17.04上安装WallchWallch是一款免费的开源通用壁纸更换器,用户可以在设置的时间更改桌面背景图片。它会在桌面上更改并显示随机图片或维基百科的当天图片。它还具有一个实时地球Living Earth壁纸,每30分钟更换桌面背景,以显示阳光和…

linux find显示文件的基本信息,命令find搜索文件,命令stat查看文件的详细信息

命令stat命令语法stat(选项)(参数)命令描述命令stat用于显示文件的状态信息。stat命令的输出信息比ls命令的输出信息要更详细。命令选项-L:支持符号连接;-f:显示文件系统状态而非文件状态;-t:以简洁方式输出信息&#…

Linux rpm 命令参数使用详解[介绍和应用]

RPM是RedHat Package Manager(RedHat软件包管理工具)类似Windows里面的“添加/删除程序” rpm 执行安装包 二进制包(Binary)以及源代码包(Source)两种。二进制包可以直接安装在计算机中,而源代…

Ubuntu10.10的网络配置

有一阵子着实对Ubuntu的网络配置很迷惑,耐下心来仔细上网找了找,有点小心得,总结一下。 先说下大概的配置过程,再去细究一些情况。 一、配置大概分三类:通过配置文件配置、通过命令配置、通过图形化的网络连接菜单配置…

DllMain详解

1 DLL的进入/退出函数 1.1 DllMain简介 跟exe有个main或者WinMain入口函数一样,DLL也有一个入口函数,就是DllMain。以“DllMain”为关键字,来看看MSDN帮助文档怎么介绍这个函数的。 The DllMain function is an optional method of entr…

linux安装tensorflow教程,真正从零开始,TensorFlow详细安装入门图文教程!

在正式开始之前我想说:一定要注意窗口给出的提示(英文)。在实际操作中可能会碰到各种各样的问题,但常见的问题其实都可以根据它的报错信息找到原因,只要上网搜一搜相应的信息就能解决,甚至它自己就会给出解决的建议。如果你发现你…