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 相关文章推荐
如何用javascript去掉字符串里的所有空格
Feb 08 Javascript
Jquery+WebService 校验账号是否已被注册的代码
Jul 12 Javascript
js 动态文字滚动的例子
Jan 17 Javascript
jquery一句话全选/取消全选
Mar 01 Javascript
修复ie8&chrome下window的resize事件多次执行
Oct 20 Javascript
js限制文本框只能输入整数或者带小数点的数字
Apr 27 Javascript
JS验证input输入框(字母,数字,符号,中文)
Mar 23 Javascript
详解axios在node.js中的post使用
Apr 27 Javascript
vue打包使用Nginx代理解决跨域问题
Aug 27 Javascript
Echarts之悬浮框中的数据排序问题
Nov 08 Javascript
js实现简单的打印表格
Jan 15 Javascript
5种方法告诉你如何使JavaScript 代码库更干净
Sep 15 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生成自己的LOG文件
2006/10/09 PHP
用php获取远程图片并把它保存到本地的代码
2008/04/07 PHP
php实现图片缩略图的方法
2016/03/29 PHP
php并发加锁示例
2016/10/17 PHP
PHP实现redis限制单ip、单用户的访问次数功能示例
2018/06/16 PHP
php unlink()函数使用教程
2018/07/12 PHP
jquery 可排列的表实现代码
2009/11/13 Javascript
JavaScript与Div对层定位和移动获得坐标的实现代码
2010/09/08 Javascript
JS创建类和对象的两种不同方式
2014/08/08 Javascript
JS动态修改iframe内嵌网页地址的方法
2015/04/01 Javascript
js操作css属性实现div层展开关闭效果的方法
2015/05/11 Javascript
Nodejs中session的简单使用及通过session实现身份验证的方法
2016/02/04 NodeJs
Javascript必知必会(四)js类型转换
2016/06/08 Javascript
深入浅析JS是按值传递还是按引用传递(推荐)
2016/09/18 Javascript
bootstrap switch开关组件使用方法详解
2017/08/22 Javascript
JS实现浏览上传文件的代码
2017/08/23 Javascript
解决element-ui中下拉菜单子选项click事件不触发的问题
2018/08/22 Javascript
Layui数据表格 前后端json数据接收的方法
2019/09/19 Javascript
d3.js 地铁轨道交通项目实战
2019/11/27 Javascript
JavaScript 面向对象程序设计详解【类的创建、实例对象、构造函数、原型等】
2020/05/12 Javascript
JavaScript enum枚举类型定义及使用方法
2020/05/15 Javascript
基于JavaScript实现轮播图效果
2021/01/02 Javascript
[02:22]2018DOTA2亚洲邀请赛VG赛前采访
2018/04/03 DOTA
用Python编写脚本使IE实现代理上网的教程
2015/04/23 Python
web.py 十分钟创建简易博客实现代码
2016/04/22 Python
python中函数默认值使用注意点详解
2016/06/01 Python
python3代码中实现加法重载的实例
2020/12/03 Python
extern在函数声明中是什么意思
2014/01/19 面试题
大学生就业推荐信范文
2013/11/29 职场文书
会计应届生的自荐信
2013/12/13 职场文书
泸县召开党的群众路线教育实践活动总结大会新闻稿
2014/10/21 职场文书
北京青年观后感
2015/06/15 职场文书
创业计划书之便利店
2019/09/05 职场文书
浅谈Laravel中使用Slack进行异常通知
2021/05/29 PHP
python中opencv实现图片文本倾斜校正
2021/06/11 Python
剑指Offer之Java算法习题精讲二叉树的构造和遍历
2022/03/21 Java/Android