本文实例讲述了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错误与调试技巧总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript遍历算法与技巧总结》及《JavaScript数学运算用法总结》
希望本文所述对大家JavaScript程序设计有所帮助。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新日志
- 钟镇涛-《百分百钟镇涛》首批限量版SACD-ISO
- 群星《继续微笑致敬许冠杰》[低速原抓WAV+CUE]
- 潘秀琼.2003-国语难忘金曲珍藏集【皇星全音】【WAV+CUE】
- 林东松.1997-2039玫瑰事件【宝丽金】【WAV+CUE】
- 谭咏麟.2022-倾·听【环球】【WAV+CUE】
- 4complete《丛生》[320K/MP3][85.26MB]
- 4complete《丛生》[FLAC/分轨][218.01MB]
- 羽泉《给未来的你&天黑天亮》[WAV+CUE][968M]
- 庄心妍《我也许在等候》[低速原抓WAV+CUE]
- 王雅洁《小调歌后2》[原抓WAV+CUE]
- 中国武警男声合唱团《辉煌之声1天路》[DTS-WAV分轨]
- 紫薇《旧曲新韵》[320K/MP3][175.29MB]
- 紫薇《旧曲新韵》[FLAC/分轨][550.18MB]
- 周深《反深代词》[先听版][320K/MP3][72.71MB]
- 李佳薇.2024-会发光的【黑籁音乐】【FLAC分轨】