因为函数也是值,因此能够做为对象的属性。把函数放在对象内部有两个主要理由,第一个理由是把许多相关函数放在一组。把许多函数组合到单个对象中,有助于组织和理解大型程序。
人类不但愿去尝试理解一个拥有数百个甚至数千个函数的系统,若是一个系统只有数十个软件组成部分,那咱们理解起来会容易不少。例如,在一个游戏程序中,咱们会很天然地为玩家、地貌、物理属性、消息传递、装备、图像等分别建立出子系统,每一个都是一个很大的对象。编程
将函数做为属性的第二个理由是让程序从面向过程转向面向对象。例如,咱们不必定要将函数看做对形状执行操做,将函数存储为形状的属性。将函数放在对象的内部,可让人们专一于这些函数,让函数扮演对象行为的角色。
数组
var firstGirlfriend = { // 属性 sex:"woman", behaviorA:function () {return ("漂亮")}, behaviorB:function () {return ("前凸后翘")}, skill:{first:"作家务",second:"按摩",thirdly:"PAPAPA"} // 方法 behaviorC:function () { return ("我会:"+this.skill.first+" | "+this.skill.second+" | ") }, test:function () {return this;} }; alert(firstGirlfriend.behaviorC()) // "我会:作家务 | 按摩 | " alert(firstGirlfriend.test()===firstGirlfriend) // true
this
我会另开一篇文章谈个人理解:this
引用的是全局对象。this
引用根据函数调用方式不一样而有所不一样。接收方对象:
经过点运算符或中括号运算符调用对象的方法时,在运算符左侧所指定的对象。var obj = { x:3, doit:function () {alert("method is called."+this.x);} }; obj.doit(); // 对象obj时接收方对象。doit是方法 obj["doit"](); // 同上
回到我们的"妹子"那儿,我想知道妹子有有什么技能,因此我用一个方法(behaviorC()
)让她本身说出来,这时谁是接收方呢?没错,是妹子firstGirlfriend
,妹子本身说本身会什么嘛,固然是她本身了,test()
也证实了函数
方法中,this.skill.first
,先肯定this
引用的对象,而后读取属性值,最后成为全局函数alert的传入值,被弹出。学习
好了大概知道this是什么咱们就要继续了。this
们
:var GirlfriendPlant = function (s) { return { sex:s, behaviorA:function () {return ("漂亮")}, behaviorB:function () {return ("前凸后翘")}, skill:{first:"作家务",second:"按摩",thirdly:"PAPAPA"}, // 方法 behaviorC:function () { return ("我会:"+this.skill.first+" | "+this.skill.second+" | ") }, test:function () {return this;} }; }; var girl_a = GirlfriendPlant("woman"); var girl_b = GirlfriendPlant("man"); alert(girl_a.behaviorB()); // "前凸后翘" alert(girl_b.sex+" | "+girl_b.behaviorC("man | 我会:作家务 | 按摩 | ")); // :)
瞧,是否是不用一个一个的写啦?并且我还高度定制了一些"功能",好比......咳咳,我是异性恋,可是男生力气大作家务也快不是?
可是!仍是有不足的地方,每一个妹子出生就自带这些技能和属性了,但是有些妹子是不肯学习某些技能的,好比一些方法,一些属性也不想表露出来,怎么办?spa
这段代码看上去没问题,却有一个严重缺陷,每次建立一个对象,都另行建立了额外的属性、方法。在建立多个对象时,会浪费大量的内存来保存这些函数方法的冗余副本,这是很糟糕的事情,由于内存资源是有限的。当脚本耗尽内存就会崩溃。可是,咱们还有一个方法来解决它们!
// 工厂设置制造车间,protoMGP对象表明一个技能属性坑齐全可是未命名未定制的妹子 var protoMGP = { sex:undefined, behaviorA:function () {return ("漂亮")}, behaviorB:function () {return ("前凸后翘")}, skill:{first:undefined,second:undefined,thirdly:undefined}, // 方法 behaviorC:function () { alert("我会:"+this.skill.first+" | "+this.skill.second+" | "+this.skill.thirdly); } }; // 工厂参数输入车间 var middleGirlPlant = function (sex,f,s,t) { // 得到车间制造的妹子(对象),注意得到的只是粗胚,为设置参数,但已经留好坑了 var girlObj = Object.create(protoMGP); // 开始定制妹子 girlObj.sex = sex; girlObj.skill.first = f; girlObj.skill.second = s; girlObj.skill.thirdly = t; // 返回定制好的妹子(对象) return girlObj; }; //如今开始制造妹子 var gA = middleGirlPlant("woman","洗衣","作饭","LOL"); console.log(gA.skill.first+" | "+gA.skill.second+" | "+gA.skill.thirdly); // "洗衣 | 作饭 | LOL" var gB = middleGirlPlant("man","Java","C","JavaScript"); console.log(gB.skill.first+" | "+gB.skill.second+" | "+gB.skill.thirdly); // "Java | C | JavaScript"
看,咱们的妹子不但知足自定义属性方法,而且这些属性方法并不保存在每一个妹子对象上,而是在她们的工厂中,只要须要随时能够调用它们。(好吧这里实在抽象不起来了)prototype
middleGirlPlant
建立的对象都有本身的sex
、skill
、behaviorA()
、behaviorB()
、behaviorC()
属性,方法,这些属性方法是由每一个对象里的prototype
引用的对象提供的,每一个对象的隐藏连接都指向惟一共享原型,其中包含了上面所述的那些属性方法。不过还有一个小小缺陷。咱们使用了两个全局变量middleGirlPlant
、protoMGP
。若是有一个就更好了,这样咱们的原型做为函数的一个属性(对象)。接下来,就是引出new
这个构造器了。JavaScript中的每一个函数对象都自动包含一个
prototype
属性,prototype
是函数两个预约义属性中的第二个,第一个length
。只要函数一经定义,它的prototype
属性就会被初始化为一个全新对象。(这个全新对象有本身的一个属性,叫作constructor
)。
// 建立构造函数highGirlfactory function highGirlfactory(s) { this.sex = s; var test = "哇哈哈,我有女友啦!!!!"; return test; }; // 构造函数的prototype(原型) highGirlfactory.prototype.behaviorA = function (a,b,c) { this.first = a; this.second = b; this.thirdly = c; }; // 构造函数的prototype(原型) highGirlfactory.prototype.behaviorB = function () { console.log("我会:"+this.first+this.second+this.thirdly); }; // GirlA对象 var GirlA = new highGirlfactory("woman"); GirlA.behaviorA("Ax","Ay","Az"); GirlA.behaviorB(); // "我会:AxAyAz" // GirlB对象 var GirlB = new highGirlfactory("woman"); GirlB.sex = "SEX"; console.log(GirlB.sex) // "SEX" // --- var Test = highGirlfactory(); alert(Test); // "哇哈哈,我有女友啦!!!!" // 原型链 alert(highGirlfactory.prototype.constructor===highGirlfactory) // true alert(GirlA.__proto__===highGirlfactory.prototype) // true
就不废话了.....当你使用new操做符,就无需明确连接(Object.create
)原型,也无需返回新建立的对象。当你在函数调用以前加上了new
时,会发生什么?引自《JavaScript程序设计》《JavaScript编程全解》设计
new
表达式的值是(被生成的)对象的引用。经过new
表达式调用的构造函数内的this
引用,引用了(被新生成的)对象。new
表达式后,会隐式生成一个新对象,可是对象不是赋值的,是引用的,因此说完就是生成了一个新对象的引用,代码中就是var GirlA = new highGirlfactory("woman")
将这个引用赋值给了变量GirlA
。而后!构造函数里的(this引用)引用了新对象,嗯这样断句应该没错@_@
,这里要提到一个以前没说清楚的知识,this
这个功能全称叫this
引用,咱们为了形象点说指向。意思就是this
指向的是新对象,接收方对象就是那个新生成的对象。so.......1.
全部的函数(对象)都具备名为prototype
的属性(这个属性引用的对象成为prototype
对象)。 2.
全部的对象都含有一个(隐藏的)连接,用以指向在对象生成过程当中所使用的构造函数(Function
对象)的prototype
对象。 Object.prototype
对象。GirlB.sex = "SEX"
;这里从新建立一个键值对,在console.log(GirlB.sex)
时,因为自身属性就存在这个键值对,不会在搜索到原型里的sex属性。关于Object.prototype
我理解不是很深,到时也会在研究一下。code
_proto_
)这个玩意儿,他就是那个神秘的隐式连接,在new
生成的新对象中,里面的_proto_
引用的对象就是原型对象。GirlA.__proto__===highGirlfactory.prototype对象
prototype
引用的对象里还有一个constructor
属性,这个东东引用的是构造函数,没错就是本身找本身。书中是这么写的:highGirlfactory.prototype.constructor===highGirlfactory
能够经过使用对象的
constructor
属性来从对象处获取其构造函数。若是能获知对象的构造函数,也就可以知道该对象的原型继承状况了,因而即可以了解这个对象的一部分操做。
constructor
属性不是对象的以前属性,而是经过原型链查找到的属性。嗯,不懂~,先暂时理解为获取构造函数吧(弄懂回来补充)