Javascript对象定义的几种方式一.工厂方式:先创建对象,再向对象添加方法和属性,封闭后调用不要使用new操作符创建对象。
使用这种方法有很多弊端,把方法定义在工厂函数内部的时候,每次调用的时候都会产生新的函数function factory(name,person,address,time){ var tmp=new Object; tmp.name=name; tmp.person=person; tmp.address=address; tmp.workTime=function(){ alert("we start to work at" + time); } return tmp;}var factory1=factory("drugs",100,"huashan Rd",10);var factory2=factory("TCMdrugs",100,"hongqiao Rd",11);factory1.workTime();factory2.workTime();//Here,factory1 and factory2 have different method对这种问题虽然可以用下面的方式改进,但是缺乏很好的封装性function factory(name,person,address,time){ var tmp=new Object; tmp.name=name; tmp.person=person; tmp.address=address; tmp.workTime=workTime(); return tmp;}function workTime(){ alert("we start to work at" + this.time);}二,构造函数方式,在构造函数内部不创建对象,使用this关键字,使用时候用new操作符,存在和工厂方式相同的问题,重复创建函数。function counstruct(name,person,address,time){ this.name=name; this.person=person; this.address=address; this.workTime=function(){ alert("we start to work at" + this.time); };}三.原型方式:利用prototype属性来实现属性和方法,可以通过instanceof 检查对象类型,解决了重复创建函数的问题,但不能通过传递参数初始化属性function Car(){}Car.prototype.color = "red";Car.prototype.doors = 4;Car.prototype.mpg = 23;Car.prototype.showColor = function(){ alert(this.color);};var car1 = new Car();var car2 = new Car();但是如果遇到下面的情况,又出问题了Car.prototype.drivers = new Array("mike", "sue");car1.drivers.push("matt");alert(car1.drivers); //outputs "mike,sue,matt"alert(car2.drivers); //outputs "mike,sue,matt"drivers是指向Array对象的指针,Car的两个实例都指向同一个数组。
四.混合的构造函数/原型方式:针对原型方式的解决方案function Car(sColor, iDoors, iMpg){ this.color = sColor; this.doors = iDoors; this.mpg = iMpg; this.drivers = new Array("mike", "sue");}Car.prototype.showColor = function (){ alert(this.color);};var car1 = new Car("red", 4, 23);var car2 = new Car("blue", 3, 25);car1.drivers.push("matt");alert(car1.drivers);alert(car2.drivers);五.动态原型方式:这种方式是极力推荐的方式,避免了前面几种方式所出现的问题,提供了更友好的编码风格function Car(sColor, iDoors, iMpg){ this.color = sColor; this.doors = iDoors; this.mpg = iMpg; this.drivers = new Array("mike", "sue"); if(typeof Car.initialized == "undefined"){ Car.prototype.showColor = function (){ alert(this.color); }; Car.initialized = true; }}var car1 = new Car("red", 4, 23);var car2 = new Car("blue", 3, 25);car1.drivers.push("matt");alert(car1.drivers);alert(car2.drivers);六.混合工厂方式:和工厂方式有些相似,但采用new关键字实例化,具有和工厂方式相同的弊端,不推荐使用。
js中的面向对象面向对象在js里有两个层次的含义,第一种是会使用面向对象函数;第二种是构造面向对象函数。
js也是面向对象中的一种写法,不过相对于java,js是一种弱数据类型,并不是严格意义上的面向对象。但是jq就是使用面向对象的写法创作出来的js库。
面向对象的特点(“抽风机”谐音记忆) 面向对象有四个特点: 1. 抽象:抓住核心问题 2. 封装:即把能够实现功能的函数写成封装起来,在面向对象里叫做方法。简单来说就是把实现功能的函数写成方法。
3. 继承:继承的意思是,在实现同一种功能的前提下,新对象可以使用就对象的属性和方法。 4. 多态:一个变量在引用不同类型的情况下的不同状态。
多态开发在开发组件和模块化开发的时候能节省很多资源。举个例子说明面向对象// 这里的函数名在面向对象里叫做类function Create(n, s){// var obj = new Object();// obj叫做实例,同时也是对象,面向对象写法中系统会自动创建一个obj空对象// 对象属性this.name = n; this.sex = s; // this指针,在这里指的就是这个对象// 对象方法this.showName = function(){alert(n);}; this.showSex = function(){alert(s);}; // 返回对象// 同样,面向对象中系统会自动帮我们返回obj(即this)//return obj;//return this;}原型(prototype)原型可以用来构造函数的属性和方法,使这个构造函数的属性和方法成为公用的。
使用原型的优点:在内存中节省资源,提高系统性能。下面举个例子说明原型:Array.prototype.sum = function(){var num = 0; for(var i=0;inum += this[i];}alert(num);};1234567这是一个用原型构造的数组方法,将求和的sum方法挂在原型上,可以使这个方法被重复使用,当然,重点是节省内存资源。
使用原型还有一个优点,就是优先级: 原型的优先级类似于CSS中的优先级,没有使用原型的构造函数,就好比CSS中的行内样式,优先级高,而与原型挂钩的属性和方法 ,就像是style的内联样式,优先级低于行内样式。所以在调用同一种方法名的时候,系统会优先调用挂在原型上的方法。
在JavaScript中定义对象可以采用以下几种方式: 1.基于已有对象扩充其属性和方法 2.工厂方式 3.构造函数方式 4.原型(“prototype”)方式 5.动态原型方式-- 1.基于已有对象扩充其属性和方法object.name = "zhangsan";object.sayName = function(name){ this.name = name; alert(this.name);}object.sayName("lisi");-- 2.工厂方式 function createObject() { var object = new Object(); object.username = "zhangsan"; object.password = "123"; object.get = function() { alert(this.username + ", " + this.password); } return object;}var object1 = createObject();var object2 = createObject();object1.get(); -- 采用带参数的构造方法:function createObject(username, password){ var object = new Object(); object.username = username; object.password = password; object.get = function() { alert(this.username + ", " + this.password); } return object;}var object1 = createObject("zhangsan", "123");object1.get();。
要解决该问题,开发者创造了能创建并返回特定类型的对象的工厂函数(factory function)。
例如,函数 createCar() 可用于封装前面列出的创建 car 对象的操作:function createCar() { var oTempCar = new Object; oTempCar.color = "blue"; oTempCar.doors = 4; oTempCar.mpg = 25; oTempCar.showColor = function() { alert(this.color); }; return oTempCar;}var oCar1 = createCar();var oCar2 = createCar(); 在这里,第一个例子中的所有代码都包含在 createCar() 函数中。此外,还有一行额外的代码,返回 car 对象(oTempCar)作为函数值。
调用此函数,将创建新对象,并赋予它所有必要的属性,复制出一个我们在前面说明过的 car 对象。因此,通过这种方法,我们可以很容易地创建 car 对象的两个版本(oCar1 和 oCar2),它们的属性完全一样。
为函数传递参数我们还可以修改 createCar() 函数,给它传递各个属性的默认值,而不是简单地赋予属性默认值:function createCar(sColor,iDoors,iMpg) { var oTempCar = new Object; oTempCar.color = sColor; oTempCar.doors = iDoors; oTempCar.mpg = iMpg; oTempCar.showColor = function() { alert(this.color); }; return oTempCar;}var oCar1 = createCar("red",4,23);var oCar2 = createCar("blue",3,25);oCar1.showColor(); //输出 "red"oCar2.showColor(); //输出 "blue" 给 createCar() 函数加上参数,即可为要创建的 car 对象的 color、doors 和 mpg 属性赋值。这使两个对象具有相同的属性,却有不同的属性值。
在工厂函数外定义对象的方法虽然 ECMAScript 越来越正式化,但创建对象的方法却被置之不理,且其规范化至今还遭人反对。一部分是语义上的原因(它看起来不像使用带有构造函数 new 运算符那么正规),一部分是功能上的原因。
功能原因在于用这种方式必须创建对象的方法。前面的例子中,每次调用函数 createCar(),都要创建新函数 showColor(),意味着每个对象都有自己的 showColor() 版本。
而事实上,每个对象都共享同一个函数。有些开发者在工厂函数外定义对象的方法,然后通过属性指向该方法,从而避免这个问题:function showColor() { alert(this.color);}function createCar(sColor,iDoors,iMpg) { var oTempCar = new Object; oTempCar.color = sColor; oTempCar.doors = iDoors; oTempCar.mpg = iMpg; oTempCar.showColor = showColor; return oTempCar;}var oCar1 = createCar("red",4,23);var oCar2 = createCar("blue",3,25);oCar1.showColor(); //输出 "red"oCar2.showColor(); //输出 "blue" 在上面这段重写的代码中,在函数 createCar() 之前定义了函数 showColor()。
在 createCar() 内部,赋予对象一个指向已经存在的 showColor() 函数的指针。从功能上讲,这样解决了重复创建函数对象的问题;但是从语义上讲,该函数不太像是对象的方法。
所有这些问题都引发了开发者定义 的构造函数的出现。构造函数方式创建构造函数就像创建工厂函数一样容易。
第一步选择类名,即构造函数的名字。根据惯例,这个名字的首字母大写,以使它与首字母通常是小写的变量名分开。
除了这点不同,构造函数看起来很像工厂函数。请考虑下面的例子:function Car(sColor,iDoors,iMpg) { this.color = sColor; this.doors = iDoors; this.mpg = iMpg; this.showColor = function() { alert(this.color); };}var oCar1 = new Car("red",4,23);var oCar2 = new Car("blue",3,25); 下面为您解释上面的代码与工厂方式的差别。
首先在构造函数内没有创建对象,而是使用 this 关键字。使用 new 运算符构造函数时,在执行第一行代码前先创建一个对象,只有用 this 才能访问该对象。
然后可以直接赋予 this 属性,默认情况下是构造函数的返回值(不必明确使用 return 运算符)。现在,用 new 运算符和类名 Car 创建对象,就更像 ECMAScript 中一般对象的创建方式了。
你也许会问,这种方式在管理函数方面是否存在于前一种方式相同的问题呢?是的。就像工厂函数,构造函数会重复生成函数,为每个对象都创建独立的函数版本。
不过,与工厂函数相似,也可以用外部函数重写构造函数,同样地,这么做语义上无任何意义。这正是下面要讲的原型方式的优势所在。
原型方式该方式利用了对象的 prototype 属性,可以把它看成创建新对象所依赖的原型。这里,首先用空构造函数来设置类名。
然后所有的属性和方法都被直接赋予 prototype 属性。我们重写了前面的例子,代码如下:function Car() {}Car.prototype.color = "blue";Car.prototype.doors = 4;Car.prototype.mpg = 25;Car.prototype.showColor = function() { alert(this.color);};var oCar1 = new Car();var oCar2 = new Car(); 在这段代码中,首先定义构造函数(Car),其中无任何代码。
接下来的几行代码,通过给 Car 的 prototype 属性添加属性去定义 Car 对象的属性。调用 new Car() 时,原型的所有属性都被立即赋予要创建的对象,意味着所有 Car 实例存放的都是指向 showColor() 函数的指针。
从语义上讲,所有属性看起来都属于一个对象,因。
JS函数的定义方式比较灵活,它不同于其他的语言,每个函数都是作为一个对象被维护和运行的。
先看几种常用的定义方式:
function func1([参数]){/*函数体*/}
var func2=function([参数]){/*函数体*/};
var func3=function func4([参数]){/*函数体*/};
var func5=new Function();
上述第一种方式是最常用的方式,不用多说。
第二种是将一匿名函数赋给一个变量,调用方法:func2([函数]);
第三种是将func4赋给变量func3,调用方法:func3([函数]);或func4([函数]);
第四种是声明func5为一个对象。
再看看它们的区别:
1234567
function func(){ //函数体}//等价于var func=function(){ //函数体}
但同样是定义函数,在用法上有一定的区别。
12345678
<script>;//这样是正确的func(1);function func(a){ alert(a);}</script>
1234567891011121314
<script>;//这样是错误的,会提示func未定义,主要是在调用func之前没有定义func(1);var func = function(a){ alert(a);}//这样是正确的,在调用func之前有定义var func = function(a){ alert(a);}func(1);</script>
用同样的方法可以去理解第三种定义方式。
第四种定义方式也是需要声明对象后才可以引用。
1.对象字面量。
var clock={ hour:12,minute:10,second:10,showTime:function(){ alert(this.hour+":"+this.minute+":"+this.second); } } clock.showTime();//调用2.创建Object实例 var clock = new Object(); clock.hour=12; clock.minute=10; clock.showHour=function(){alert(clock.hour);}; clock.showHour();//调用 由此可见 属性是可以动态添加,修改的 对象创建模式:1.工厂模式:就是一个函数,然后放入参数,返回对象,流水线工作 function createClock(hour,minute,second){ var clock = new Object(); clock.hour=hour; clock.minute=minute; clock.second=second; clock.showHour=function(){ alert(this.hour+":"+this.minute+":"+this.second); }; return clock; }; var newClock = createClock(12,12,12);//实例化 newClock.showHour();//调用 优点:总算优点抽象的概念了。但是不能识别对象的类型呢!2.构造函数模式 function clock(hour,minute,second){ this.hour = hour; this.minute = minute; this.second = second; this.showTime = function(){ alert(this.hour+":"+this.minute+":"+this.second); } } var newClock =new clock(12,12,12); alert(newClock.hour); 注意:这个new关键字是必须,如果不加,clock就不会当成构造函数调用,而只是一个普通的函数。
同时,还会意外地给他的外部作用域即window添加属性,因为此时构造函数内部的this已经映射到了外部作用域了。所以为了安全起见,可以这样创建 function clock(hour,minute,second){ if(this instanceof clock){ this.hour = hour; this.minute = minute; this.second = second; this.showTime = function(){ alert(this.hour+":"+this.minute+":"+this.second); } } else{ throw new Error("please add 'new' to make a instance"); } } 构造函数的缺点:由于this指针在对象实例的时候发生改变指向新的实例。
这时新实例的方法也要重新创建,如果n个实例就要n次重建相同的方法。于是让来揭开原型模式吧3.原型模式 function clock(hour,minute,second){ } clock.prototype.hour=12; clock.prototype.minute=12; clock.prototype.second=12; clock.prototype.showTime=function(){ alert(this.hour+":"+this.minute+":"+this.second); } var newClock = new clock(); newClock.showTime(); 深度理解原型模型很重要,首先,每个函数都有一个prototype(原型)属性,这个指针指向的就是clock.prototype对象。
而这个原型对象在默认的时候有一个属性constructor,指向clock,这个属性可读可写。而当在实例化一个对象的时候,实例newClock除了具有构造函数定义的属性和方法外(注意,只是构造函数中的),还有一个指向构造函数的原型的指针,ECMAScript管他叫[[prototype]],这样实例化对象的时候,原型对象的方法并没有在某个具体的实例中,因为原型没有被实例。
(废话有点多,没有误导您吧。别晕) 所以这种模式定义的对象,在调用方法的时候过程:调用newClock.showTime();先看实例中有没有,有调之,无追踪到原型,有调之,无出错,调用失败。
当然可以这样写:function clock(hour,minute,second){ } clock.prototype={ constructor:clock, //必须手动设置这个属性,不然就断了与构造函数的联系了。没有实例共享原型的意义了。
hour:12,minute:12,second:12,showTime:function(){ alert(this.hour+":"+this.minute+":"+this.second) } } var newClock = new clock(); newClock.showTime(); 注意:实例与构造函数原型的联系也是通过指针来联系的,故可以动态添加修改原型的方法。这种纯原型的模式问题也很明显,所有的属性,方法都是共享的,不能让对象具体化。
常常想每个对象有自己的属性。于是,结合前两种,产生新的模式4.构造-原型组合模式。
function clock(hour,minute,second){ this.hour = hour; this.minute = minute; this.second = second; } clock.prototype.showTime=function(){alert(this.hour+":"+this.minute+":"+this.second);} var newClock = new clock(12,12,12); newClock.showTime(); 这里将属性放在构造函数中,更显得对象的具体性。
可以参考如下内容:第一种模式:工厂方式[javascript] view plain copy print?var lev=function(){ return "啊打"; }; function Parent(){ var Child = new Object(); Child.name="李小龙"; Child.age="30"; Child.lev=lev; return Child; }; var x = Parent(); alert(x.name); alert(x.lev()); 说明:1.在函数中定义对象,并定义对象的各种属性,,虽然属性可以为方法,但是建议将属性为方法的属性定义到函数之外,这样可以避免重复创建该方法2.引用该对象的时候,这里使用的是 var x = Parent()而不是 var x = new Parent();因为后者会可能出现很多问题(前者也成为工厂经典方式,后者称之为混合工厂方式),不推荐使用new的方式使用该对象3.在函数的最后返回该对象4.不推荐使用这种方式创建对象,但应该了解第二种模式:构造函数方式[javascript] view plain copy print?var lev=function(){ return "啊打"; }; function Parent(){ this.name="李小龙"; this.age="30"; this.lev=lev; }; var x =new Parent(); alert(x.name); alert(x.lev()); 说明:1.与工厂方式相比,使用构造函数方式创建对象,无需再函数内部重建创建对象,而使用this指代,并而函数无需明确return2.同工厂模式一样,虽然属性的值可以为方法,扔建议将该方法定义在函数之外3..同样的,不推荐使用这种方式创建对象,但仍需要了解第3种模式:原型模式[javascript] view plain copy print?var lev=function(){ return "啊打"; }; function Parent(){ }; Parent.prototype.name="李小龙"; Parent.prototype.age="30"; Parent.prototype.lev=lev; var x =new Parent(); alert(x.name); alert(x.lev());。
推荐有一下几种方式:
1.对象字面量创建对象
var obj = { a:1,b:2 };
注意:对象字面量是一个表达式,这种表达式每次运算都会创建并初始化一个新对象,并计算这个新对象的每个属性值。所以如果在循环体内使用对象字面量,每次循环时都会创建新对象。
2.通过new运算符创建对象
var obj = new Object(); //创建空对象 var ary = new Array(); //创建空的数组对象
注意:new运算符后面跟的是一个函数调用,这个函数被称为构造函数。js中原始类型都包含内置的构造函数,也可以自己定义构造函数。
3.通过立即执行函数创建对象
var obj = (function(){ return {x:1,y:2};}());
注意:在立即执行函数内部一定要有return语句,return出的内容就是待创建的对象。
声明:本网站尊重并保护知识产权,根据《信息网络传播权保护条例》,如果我们转载的作品侵犯了您的权利,请在一个月内通知我们,我们会及时删除。
蜀ICP备2020033479号-4 Copyright © 2016 学习鸟. 页面生成时间:3.091秒