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下:nth-child(an+b)的使用注意
May 28 Javascript
js Form.elements[i]的使用实例
Nov 13 Javascript
获得所有表单值的JQuery实现代码[IE暂不支持]
May 24 Javascript
JS链式调用的实现方法
Mar 07 Javascript
用JavaScript获取DOM元素位置和尺寸大小的方法
Apr 12 Javascript
js动态添加表格数据使用insertRow和insertCell实现
May 22 Javascript
浏览器缩放检测的js代码
Sep 28 Javascript
javascript实现的闭包简单实例
Jul 17 Javascript
javascript中日期函数new Date()的浏览器兼容性问题
Sep 05 Javascript
vue.js学习笔记之绑定style样式和class列表
Oct 31 Javascript
详解基于Vue2.0实现的移动端弹窗(Alert, Confirm, Toast)组件
Aug 02 Javascript
Angular实现svg和png图片下载实现
May 05 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 静态变量与自定义常量的使用方法
2010/01/26 PHP
PHP操作MongoDB GridFS 存储文件的详解
2013/06/20 PHP
php指定长度分割字符串str_split函数用法示例
2017/01/30 PHP
PHP排序算法之堆排序(Heap Sort)实例详解
2018/04/21 PHP
apycom出品的jQuery精美菜单破解方法
2011/02/18 Javascript
jQuery最佳实践完整篇
2011/08/20 Javascript
两种常用的javascript数组去重方法思路及代码
2013/03/26 Javascript
JS读取XML文件示例代码
2013/11/15 Javascript
javascript判断office版本示例
2014/04/11 Javascript
24款热门实用的jQuery插件推荐
2014/12/24 Javascript
使用AngularJS 应用访问 Android 手机的图片库
2015/03/24 Javascript
jQuery制作圣诞主题页面 更像是爱情影集
2016/08/10 Javascript
jquery Ajax 全局调用封装实例详解
2017/01/16 Javascript
在vue2.0中引用element-ui组件库的方法
2018/06/21 Javascript
PM2自动部署代码步骤流程总结
2018/12/10 Javascript
vue中 this.$set的用法详解
2019/09/06 Javascript
解决vue无法侦听数组及对象属性的变化问题
2020/07/17 Javascript
python 查找文件夹下所有文件 实现代码
2009/07/01 Python
Python解析excel文件存入sqlite数据库的方法
2016/11/15 Python
python中字符串变二维数组的实例讲解
2018/04/03 Python
python绘制圆柱体的方法
2018/07/02 Python
Python3利用Dlib实现摄像头实时人脸检测和平铺显示示例
2019/02/21 Python
Python一行代码解决矩阵旋转的问题
2019/11/30 Python
利用Pytorch实现简单的线性回归算法
2020/01/15 Python
浅谈JupyterNotebook导出pdf解决中文的问题
2020/04/22 Python
通俗易懂了解Python装饰器原理
2020/09/17 Python
威盛公司软件C++工程师笔试题面试题
2012/07/16 面试题
Hashtable 添加内容的方式有哪几种,有什么区别?
2012/04/08 面试题
国际会议邀请函范文
2014/01/16 职场文书
五星级酒店餐饮部总监的标准岗位职责
2014/02/17 职场文书
《影子》教学反思
2014/02/21 职场文书
优秀共产党员事迹材料
2014/12/18 职场文书
给客户的感谢信
2015/01/21 职场文书
新郎新娘致辞
2015/07/31 职场文书
升职自荐书
2019/05/09 职场文书
MySQL表的增删改查基础教程
2021/04/07 MySQL