JavaScript原型对象、构造函数和实例对象功能与用法详解


Posted in Javascript onAugust 04, 2018

本文实例讲述了JavaScript原型对象、构造函数和实例对象功能与用法。分享给大家供大家参考,具体如下:

大家都知道,javascript中其实并没有类的概念。但是,用构造函数跟原型对象却可以模拟类的实现。在这里,就先很不严谨的使用类这个词,以方便说明。

下面整理了一些关于javascript的构造函数、原型对象以及实例对象的笔记,有错误的地方,望指正。

先用一张图简单的概括下这几者之间的关系,再细化:

JavaScript原型对象、构造函数和实例对象功能与用法详解

构造函数和实例对象

构造函数是类的外在表现,构造函数的名字通常用作类名。

其实构造函数也就是一个函数,只不过它于普通的函数又有点不同:

  • 没有显示的创建对象;
  • 直接将属性和方法赋给this
  • 没有return语句;

构造函数是用来构造新对象的。之前的笔记中有提到过,可以是用new关键词来调用构造函数,以创建特定类型的新对象。如,创建一个Object类型的对象实例:

var o=new Object();

为了区别构造函数和普通函数,通常规定构造函数的命名首字母大写,而普通函数的命名首字母小写。当然,这不是必须的,却是一个很好的习惯。

通过用构造函数创建并初始化的属性是实例属性。所谓的实例属性就是指,通过该构造函数创建的每个对象,都将拥有一份实例属性的单独拷贝。这些属性都是通过实例来访问的,值根据每个实例所定义的为准,若实例中没有定义,则为构造函数初始化时的默认值。来看一个例子:

function Person(name,age){
  this.name=name;
  this.age=age;
  this.friends=["Tom","Boo"];
}
var p1=new Person("Lily",20);
var p2=new Person("Sam",30);
alert(p1.name); //Lily
alert(p2.name); //Sam
p1.friends.push("Susan");
alert(p1.friends); //Tom,Boo,Susan
alert(p2.friends); //Tom,Boo

上面的例子定义了一个Person构造函数,并初始化了name、age和friends三个属性。接着创建了两个实例对象,分别为p1和p2。观察这个例子,每个属性都是为各自所拥有的,并不会相互影响。这就是因为每个实例对象都拥有一份属性的副本。

每个实例对象都有一个属性指向它的构造函数,这属性就是constructor:

function Person(name,age){
  this.name=name;
  this.age=age;
}
var p1=new Person("Lily",20);
var p2=new Person("Sam",30);
alert(p1.constructor==Person); //true
alert(p2.constructor==Person); //true

构造函数有一个prototype属性,指向原型对象。

原型对象和实例对象

在javascript中,每个对象都有一个与之相关联的对象,那就是它的原型对象。类的所有实例对象都从它的原型对象上继承属性。

原型对象是类的唯一标识:当且仅当两个对象继承自同一个原型对象时,它们才是属于同一个类的实例。

前面有提到,构造函数拥有一个prototype属性,指向原型。换句话来说,一个对象的原型就是它的构造函数的prototype属性的值。当一个函数被定义的时候,它会自动创建和初始化prototype值,它是一个对象,这时这个对象只有一个属性,那就是constructor,它指回和原型相关联的那个构造函数。看个例子:

function Person(name,age){
  this.name=name;
  this.age=age;
}
alert(Person.prototype); //[object Object]
alert(Person.prototype.constructor==Person); //true

也可以通过原型来创建属性和方法。通过原型创建的属性和方法是被所有实例所共享的。即,在一个实例中修改了该属性或方法的值,那么所有其他实例的属性或方法值都会受到影响:

function Person(name,age){
  this.name=name;
  this.age=age;
}
Person.prototype.friends=["Tom","Sam"];
var p1=new Person("Lily",24);
var p2=new Person("Susan",20);
alert(p1.friends); //Tom,Sam
alert(p2.friends); //Tom,Sam
p1.friends.push("Bill");
alert(p1.friends); //Tom,Sam,Bill
alert(p2.friends); //Tom,Sam,Bill

由上面的例子可以看出,用原型定义的属性是被所有实例共享的。为p1添加了一个朋友,导致p2也添加了这个朋友。

其实,很多情况下,这种现象并不是我们想看到的。那么什么时候应该用构造函数初始化属性和方法,哪些时候又该由原型对象来定义呢?

通常建议在构造函数内定义一般成员,即它的值在每个实例中都将不同,尤其是对象或数组形式的值;而在原型对象中则定义一些所有实例所共享的属性,即在所有实例中,它的值可以是相同的属性。

当用构造函数创建一个实例时,实例的内部也包含了一个指针,指向构造函数的原型对象。一些浏览器中,支持一个属性__proto__来表示这个内部指针:

function Person(name,age){
  this.name=name;
  this.age=age;
}
Person.prototype.sayName=function(){
  alert(this.name);
}
var p1=new Person("Lily",24);
alert(p1.__proto__.sayName); //function (){alert(this.name);}
alert(p1.__proto__.constructor==Person); //true

在ECMAscript5中新增了一个方法,Object.getPrototypeOf(),可以返回前面提到的实例对象内部的指向其原型的指针的值:

function Person(name,age){
 this.name=name;
 this.age=age;
}
var p1=new Person("Lily",24);
alert(Object.getPrototypeOf(p1)==Person.prototype); //true

isPrototypeOf()方法也可用于确定实例对象和其原型之间的这种关系:

function Person(name,age){
  this.name=name;
  this.age=age;
}
var p1=new Person("Lily",24);
alert(Person.prototype.isPrototypeOf(p1)); //true

原型语法

从前面介绍原型对象于实例对象及构造函数的关系中,我们已经知道,给原型对象添加属性和方法只要像这样定义即可:Person.prototype=name

那么是否每定义一个Person的属性,就要敲一遍Person.prototype呢?答案是否定的,我们也可以像用对象字面量创建对象那样来创建原型对象:

function Person(){
}
Person.prototype={
  name:"Tom",
  age:29
}
var p1=new Person();
alert(p1.name); //Tom
alert(p1.age); //29

有一点要注意,这个方法相当于重写了整个原型对象,因此切断了它与构造函数的关系,此时Person.prototype.constructor不再指向Person:

function Person(){
}
Person.prototype={
  name:"Tom",
  age:29
}
var p1=new Person();
alert(Person.prototype.constructor==Person); //false
alert(Person.prototype.constructor==Object); //true

因此,如果想要让它重新指向Person,可以显示的进行赋值:

function Person(){
}
Person.prototype={
 constructor:Person,
 name:"Tom",
 age:29
}
var p1=new Person();
alert(Person.prototype.constructor==Person); //true
alert(Person.prototype.constructor==Object); //false

总结

最后,我们拿一个例子,再来理理构造函数、原型对象以及实例对象之间的关系:

function Person(name,age){
  this.name=name;
  this.age=age;
}
Person.prototype.sayName=function(){
  alert(this.name);
}
var p1=new Person("Tom",20);
alert(Person.prototype); //object
alert(Person.prototype.constructor==Person); //true
alert(p1.constructor==Person); //true
alert(p1.__proto__==Person.prototype); //true
alert(p1.__proto__.__proto__==Object.prototype); //true
alert(p1.__proto__.__proto__.constructor==Object); //true
alert(Person.constructor==Function); //true
alert(Object.prototype.constructor==Object);

JavaScript原型对象、构造函数和实例对象功能与用法详解

上图说明了这个例子中原型、构造函数和实例属性的关系。

希望本文所述对大家JavaScript程序设计有所帮助。

Javascript 相关文章推荐
jQuery 渐变下拉菜单
Dec 15 Javascript
jquery 得到当前页面高度和宽度的两个函数
Feb 21 Javascript
提交表单时执行func方法实现代码
Mar 17 Javascript
JavaScript字符串插入、删除、替换函数使用示例
Jul 25 Javascript
JS实现点击图片在当前页面放大并可关闭的漂亮效果
Oct 18 Javascript
javascript中直接引用Microsoft的COM生成Word
Jan 20 Javascript
FF IE浏览器修改标签透明度的方法
Jan 27 Javascript
借助FileReader实现将文件编码为Base64后通过AJAX上传
Dec 24 Javascript
jQGrid动态填充select下拉框的选项值(动态填充)
Nov 28 Javascript
Javascript 之封装(Package)
Sep 14 Javascript
使用express获取微信小程序二维码小记
May 21 Javascript
基于js实现复制内容到操作系统粘贴板过程解析
Oct 11 Javascript
JavaScript中变量、指针和引用功能与操作示例
Aug 04 #Javascript
webpack4.x开发环境配置详解
Aug 04 #Javascript
微信小程序实现收藏与取消收藏切换图片功能
Aug 03 #Javascript
解决mpvue + vuex 开发微信小程序vuex辅助函数mapState、mapGetters不可用问题
Aug 03 #Javascript
mpvue跳转页面及注意事项
Aug 03 #Javascript
JavaScript高级函数应用之分时函数实例分析
Aug 03 #Javascript
mpvue小程序仿qq左滑置顶删除组件
Aug 03 #Javascript
You might like
php 静态变量的初始化
2009/11/15 PHP
php park、unpark、ord 函数使用方法(二进制流接口应用实例)
2010/10/19 PHP
symfony表单与页面实现技巧
2015/01/26 PHP
PHP类和对象相关系统函数与运算符小结
2016/09/28 PHP
网页中实现浏览器的最大,最小化和关闭按钮
2007/03/12 Javascript
JavaScript 以对象为索引的关联数组
2010/05/19 Javascript
用JavaScript对JSON进行模式匹配 (Part 2 - 实现)
2010/07/17 Javascript
关于JS判断图片是否加载完成且获取图片宽度的方法
2013/04/09 Javascript
jquery 文本上下无缝滚动,鼠标放上去就停止 小例子
2013/06/05 Javascript
IE6下拉框图层问题探讨及解决
2014/01/03 Javascript
javascript学习笔记(六)数据类型和JSON格式
2014/10/08 Javascript
javascript实现随机读取数组的方法
2015/08/03 Javascript
通过js获取上传的图片信息(临时保存路径,名称,大小)然后通过ajax传递给后端的方法
2015/10/01 Javascript
js判断日期时间有效性的方法
2015/10/24 Javascript
JS实现直接运行html代码的方法
2017/03/13 Javascript
xmlplus组件设计系列之图标(ICON)(1)
2017/05/05 Javascript
用最简单的方法判断JavaScript中this的指向(推荐)
2017/09/04 Javascript
JS实现的全排列组合算法示例
2017/10/09 Javascript
vue通过cookie获取用户登录信息的思路详解
2018/10/30 Javascript
vue实现压缩图片预览并上传功能(promise封装)
2019/01/10 Javascript
node koa2 ssr项目搭建的方法步骤
2020/12/11 Javascript
Python中对列表排序实例
2015/01/04 Python
高质量Python代码编写的5个优化技巧
2017/11/16 Python
Python3实现的简单验证码识别功能示例
2018/05/02 Python
python统计多维数组的行数和列数实例
2018/06/23 Python
Pyqt5 实现跳转界面并关闭当前界面的方法
2019/06/19 Python
Python socket实现的文件下载器功能示例
2019/11/15 Python
python操作docx写入内容,并控制文本的字体颜色
2020/02/13 Python
django的autoreload机制实现
2020/06/03 Python
Keras-多输入多输出实例(多任务)
2020/06/22 Python
Python 执行矩阵与线性代数运算
2020/08/01 Python
小区停车场管理制度
2014/01/27 职场文书
学前班评语大全
2014/05/04 职场文书
保护环境建议书300字
2014/05/13 职场文书
红旗渠导游词
2015/02/09 职场文书
公文写作:工伤事故分析报告怎么写?
2019/11/05 职场文书