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 相关文章推荐
懒就要懒到底——鼠标自动点击(含时间判断)
Feb 20 Javascript
JavaScript中实现继承的三种方式和实例
Jan 29 Javascript
Javascript基于AJAX回调函数传递参数实例分析
Dec 15 Javascript
javascript的 {} 语句块详解
Feb 27 Javascript
JS模拟简易滚动条效果代码(附demo源码)
Apr 05 Javascript
Angularjs之filter过滤器(推荐)
Nov 27 Javascript
JavaScript无操作后屏保功能的实现方法
Jul 04 Javascript
for循环 + setTimeout 结合一些示例(前端面试题)
Aug 30 Javascript
JavaScript判断输入是否为数字类型的方法总结
Sep 28 Javascript
微信小程序获取手机系统信息的方法【附源码下载】
Dec 07 Javascript
一次记住JavaScript的6个正则表达式方法
Feb 22 Javascript
完美解决vue 中多个echarts图表自适应的问题
Jul 19 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中使用Sockets 从Usenet中获取文件
2008/01/10 PHP
CodeIgniter整合Smarty的方法详解
2017/08/25 PHP
PHP中散列密码的安全性分析
2019/07/26 PHP
JQuery 学习笔记 选择器之六
2009/07/23 Javascript
两种简单实现菜单高亮显示的JS类代码
2010/06/27 Javascript
js 函数调用模式小结
2011/12/26 Javascript
javascript白色简洁计算器
2015/05/04 Javascript
AngularJS ng-change 指令的详解及简单实例
2016/07/30 Javascript
浅谈js中对象的使用
2016/08/11 Javascript
JavaScript ES6中CLASS的使用详解
2016/11/22 Javascript
JavaScript仿支付宝6位数字密码输入框
2016/12/29 Javascript
浅谈jQuery中的$.extend方法来扩展JSON对象
2017/02/12 Javascript
js和jQuery以及easyui实现对下拉框的指定赋值方法
2018/01/23 jQuery
详解vue2.6插槽更新v-slot用法总结
2019/03/09 Javascript
基于elementUI使用v-model实现经纬度输入的vue组件
2019/05/12 Javascript
vue实现搜索功能
2019/05/28 Javascript
vue单页应用的内存泄露定位和修复问题小结
2019/08/02 Javascript
原生js 实现表单验证功能
2021/02/08 Javascript
[49:15]DOTA2-DPC中国联赛 正赛 CDEC vs XG BO3 第二场 1月19日
2021/03/11 DOTA
Python matplotlib通过plt.scatter画空心圆标记出特定的点方法
2018/12/13 Python
python向企业微信发送文字和图片消息的示例
2020/09/28 Python
解决HTML5手机端页面缩放的问题
2017/10/27 HTML / CSS
HTML5拖放API实现自动生成相框功能
2020/04/07 HTML / CSS
Ever New加拿大官网:彰显女性美
2018/10/05 全球购物
乌克兰珠宝大卖场:Zlato.ua
2020/09/27 全球购物
国贸类专业毕业生的求职信分享
2013/12/08 职场文书
环境科学专业优秀毕业生自荐书
2014/02/03 职场文书
《盲人摸象》教学反思
2014/02/16 职场文书
农村婚庆司仪主持词
2014/03/15 职场文书
欢度春节标语
2014/07/01 职场文书
装修施工安全责任书
2014/07/24 职场文书
2015年妇产科工作总结
2015/05/18 职场文书
Redis实现订单自动过期功能的示例代码
2021/05/08 Redis
用python实现监控视频人数统计
2021/05/21 Python
Python开发五子棋小游戏
2022/05/02 Python
Java实现扫雷游戏详细代码讲解
2022/05/25 Java/Android