JavaScript定义类或函数的几种方式小结_js面向对象

JavaScript定义类或函数的几种方式小结_js面向对象,第1张

提起面向对象我们就能想到类,对象,封装,继承,多态。在《javaScript高级程序设计》(人民邮电出版社,曹力、张欣译。英文名字是:Professional JavaScript for Web Developers)这本书中描述的还算比较详细。我们看看JavaScript中定义类的各种方法。

1.工厂方式

javaScript中创建自己的类和对象,我们应该是必须掌握的,我们都知道javaScript中对象的属性可以在对象创建后动态定义,比如下面的代码:

代码如下:

//定义

var oCar = new Object();

oCarcolor = "red";

oCardoors = 4;

oCarshowColor = function() {

alert(thiscolor);

}

//调用

oCarshowColor();

我们很容易使用oCar对象,但是我们创就是想创建多个Car实例。我们可以使用一个函数来封装上面的代码来实现:

代码如下:

//定义

function createCar() {

var oCar = new Object();

oCarcolor = "red";

oCardoors = 4;

oCarshowColor = function() {

alert(thiscolor);

}

return oCar;

}

//调用

var ocar1 = createCar();

var ocar2 = createCar();

ocar1color = "black";

ocar1showColor();

ocar2showColor();

顺便说一下,javaScript对象默认成员属性都是public 的。这种方式我们称为工厂方式,我们创造了能创建并返回特定类型的对象的工厂。

这样做有点意思了,但是在面向对象中我们经常使用创建对象的方法是:

Car car=new Car();

使用new 关键字已经深入人心,因此我们使用上面的方法去定义总感觉别扭,并且每次调用时都去创建新的属性以及函数,功能上也不实际。下来我们看看构造函数的形式定义类。

2.构造函数

这种方式看起来有点象工厂函数。具体表现如下:

代码如下:

//定义

function Car(color, doors) {

thiscolor = color;

thisdoors = doors;

thisshowColor = function() {

alert(thiscolor);

};

}

//调用

var car1 = new Car("red", 4);

var car2 = new Car("blue", 4);

car1showColor();

car2showColor();

看起来效果很明显,有差别了吧。感觉有点意思了。在构造函数内部创造对象使用this 关键字,使用new 运算符创建对象感觉非常亲切。但是也有点问题:每次new 对象时都会创建所有的属性,包括函数的创建,也就是说多个对象完全独立,我们定义类的目的就是为了共享方法以及数据,但是car1对象与car2对象都是各自独立的属性与函数,最起码我们应该共享方法。这就是原形方式的优势所在。

3.原型方式

利用对象的prototype属性,可把它看出创建新对象所依赖的原型。方法如下:

代码如下:

//定义

function Car() {

};

Carprototypecolor = "red";

Carprototypedoors = 4;

Carprototypedrivers = new Array("Tom", "Jerry");

CarprototypeshowColor = function() {

alert(thiscolor);

}

//调用:

var car1 = new Car();

var car2 = new Car();

car1showColor();

car2showColor();

alert(car1drivers);

car1driverspush("stephen");

alert(car1drivers); //结果:Tom,Jerry,stephen

alert(car2drivers); //结果:Tom,Jerry,stephen

//可以用json方式简化prototype的定义:

Carprototype =

{

color: "red",

doors: 4,

drivers: ["Tom", "Jerry",'safdad'],

showColor: function() {

alert(thiscolor);

}

}

首先这段代码的构造函数,其中没有任何代码,接下来通过对象的prototype属性添加属性定义Car对象的属性。这种方法很好,但是问题是Car的对象指向的是Array指针,Car的两个对象都指向同一个Array数组,其中一个对象car1改变属性对象的引用(数组Array)时,另一个对象car2也同时改变,这是不允许的。

同时该问题也表现在原型不能带任何初始化参数,导致构造函数无法正常初始化。这需要另一种方式来解决:那就是混合的构造函数/原型模式。

4 混合的构造函数/原型模式

联合使用构造函数和原型方式,定义类就非常方便。

代码如下:

//定义

function Car(color,doors)

{

thiscolor=color;

thisdoors=doors;

thisdrivers=new Array("Tom","Jerry");

}

CarprototypeshowColor=function(){

alert(thiscolor);

}

//调用:

var car1=new Car('red',4);

var car2=new Car('blue',4);

car1showColor();

car2showColor();

alert(car1drivers);

car1driverspush("stephen");

alert(car1drivers); //结果:Tom,Jerry,stephen

alert(car2drivers); //结果:Tom,Jerry

alert(car1 instanceof Car);

该方法是把属性放在内部定义,把方法放在外边利用prototype进行定义。解决了第三种方法的问题。

这种方法其实应该来说非常友好了,但是比起java的语法来,应该有一些不和谐,感觉比较凌乱,对C++来说,我们就没有那么麻烦的感觉了,可是开发C++的研发人员一般情况下很少涉及javaScript,而对J2EE的研发人员来说,这种方式总有一些别扭。总感觉不是友好的封装,其实只不过是视觉上封装效果不是很好而已,要想达到视觉封装效果而又能达到这种方法的效果的也可以以,个人认为其实比较麻烦。那就是动态原型法。

5动态原型

对于习惯使用其他语言的开发者来说,使用混合的构造函数/原型方式感觉不那么和谐。毕竟,定义类时,大多数面向对象语言都对属性和方法进行了视觉上的封装。考虑下面的C#类:

代码如下:

class Car //class

{

public string color = "red";

public int doors = 4;

public int mpg = 23;

public Car(string color, int doors, int mpg) //constructor

{

thiscolor = color;

thisdoors = doors;

thismpg = mpg;

}

public void showColor() //method

{

ConsoleWriteLine(thiscolor);

}

}

C#很好的打包了Car类的所有属性和方法,因此看见这段代码就知道它要实现什么功能,它定义了一个对象的信息。批评混合的构造函数/原型方式的人认为,在构造函数内存找属性,在其外部找方法的做法不合逻辑。因此,他们设计了动态原型方法,以提供更友好的编码风格。

动态原型方法的基本想法与混合的构造函数/原型方式相同,即在构造函数内定义非函数属性,而函数属性则利用原型属性定义。唯一的区别是赋予对象方法的位置。下面是用动态原型方法重写的Car类:

代码如下:

//定义

function Car() {

thiscolor = "red";

thisdoors = 4;

thisdrivers = new Array("Tom", "Jerry");

if (typeof Car_initialized == "undefined") {

CarprototypeshowColor = function() {

alert(thiscolor);

}

//

}

//最后定义

Car_initialized = true;

}

直到检查typeof Car_initialized是否等于"undefined"之前,这个构造函数都未发生变化。这行代码是动态原型方法中最重要的部分。如果这个值未定义,构造函数将用原型方式继续定义对象的方法,然后把Car_initialized设置为true。如果这个值定义了(它的值为true时,typeof的值为Boolean),那么就不再创建该方法。简而言之,该方法使用标志(_initialized)来判断是否已给原型赋予了任何方法。该方法只创建并赋值一次,为取悦传统的OOP开发者,这段代码看起来更像其他语言中的类定义了。

6 混合工厂方式

这种方式通常是在不能应用前一种方式时的变通方法。它的目的是创建假构造函数,只返回另一种对象的新实例。这段代码看来与工厂函数非常相似:

代码如下:

function Car() {

var oTempCar = new Object();

oTempCarcolor="red";

oTempCardoors=4;

oTempCarmpg=23;

oTempCarshowColor = function() {

alert(thiscolor);

}

return oTempCar;

}

与经典方式不同,这种方式使用new运算符,使它看起来像真正的构造函数:

var oCar = new Car();

由于在Car()构造函数内部调用了new运算符,所以将忽略第二个new运算符(位于构造函数之外)。在构造函数内部创建的对象被传递回变量var。这种方式在对象方法的内部管理方面与经典方式有着相同的问题。强烈建议:除非万不得已(请参阅第15章),还是避免使用这种方式。

总结:(采用哪种方式)

目前使用最广泛的是混合的构造函数/原型方式。此外,动态原型方法也很流行,在功能上与构造函数/原型方式等价。可以采用这两种方式中的任何一种。不过不要单独使用经典的构造函数或原型方式,因为这样会给代码引入问题。

代码如下:

//ps

//static class (1:function)

var CarCollection = new function() {

var _carCollection = new Array(); //global,private

thisAdd = function(objCar) {

alert('Add');

}

thisGet = function(carid) {

alert('Get');

}

}

//static class (2:json)

var Car = {

color: 'red',

doors: 4,

showColor: function() { alert(thiscolor); }

}

CarshowColor();

酷来电设置来电视频的方法是:

1、先在手机里开启酷来电的权限,按照软件的提示点击下方“立即开启”功能;

2、参考官方的提示操作授予酷来电手机的权限,然后就可以通过下方“开启来电视频”的功能进行设置了;

3、找到感兴趣的来电视频,点击视频页面右下角的“设为来电”选项,就成功完成设置了。

贴个代码先:

function O(user,pwd){ //use constructor

thisuser=user;

thispwd=pwd;

thisget=get;

return this;

}

function O2(user,pwd){ //use factory

var obj=new Object();

objuser=user;

objpwd=pwd;

objget=get;

return obj;

}

function O3(){ //use prototype

}

O3prototypeuser='abc';

O3prototypepwd='dis';

// O3propotypeget='get';

//O3prototypeget(){

//alert(thispwd);

//}

function O4(user,pwd){

thisuser=user;

thispwd=pwd;

return this;

}

O4prototypeget=function(){alert('123');}

//function get(){

//alert("This User:"+thisuser);

// }

function test2(){

//var a=new O2('Us','Pw'); use factory & constructor

//var a=new O3(); //use prototype

//aget();

var a=new O4('U4','P4'); //混合

//auser='Not ABC'; //set new property

//alert(auser);

aget();

}

常用的MS 就这几种,可能还有其它的碰到再说吧

题外话:昨天手欠,试图用alert(windowappName)到ff之下去查看浏览器版本,结果弹出的竟然是Netscape,咋不是 firefox。继而又跑去chrome下试验,又一次弹出了Netscape。baidu搜 Netscape 竟然发现js就出自Netscape公司。惭愧啊惭愧!!!研究了这么久的js都不认识祖师爷。于是又跑去找了找族谱,原来js出自Brendan Eich之手,95年他创造js时候,也不过就31岁。哎呀,真是白活了,如他一般老的我,到现在都学不会js,真是人比人气死人。js当初设计的时候,没有想到自己能从一部打电话用的手机变成集拍照,上网,游戏,电话于一身的智能机。真是造化弄人!!!也许各中的神奇,连Brendan Eich本人都没有想到。应该说Brendan Eich创造了js,而一大批的js牛人成就了今天如此复杂的js。

js不是木有类么?没关系,人家不是设计了原型属性么~

js不是木有块级作用域么?没关系,人家不是有作用域链么~

js怎样实现成员变量私有化?哦,用闭包解决吧~

哦,这么多基本概念,彻底的晕掉了,路漫漫其修远兮。

言归正传,本文讨论几种js创建对象的方法,先从最好理解的工厂模式开始:

代码如下:

function createPerson(name,age,job){

var o = {};

oname = name;

oage = age;

ojob = job;

osayName = function(){

alert(thisname);

};

return o;

}

var tanya = createPerson("tanya","30","female");

var ansel = createPerson("ansel","30","male");

tanyasayName();

anselsayName();

这里先定义o为一个空的对象,然后为o设置了一堆属性。其实也可以直接给o属性的嘛,所以如果这样写也是ok的。

代码如下:

function createPerson(name,age,job){

var o = {

name : name,

age : age,

job : job,

sayName : function(){

alert(thisname);

}

};

return o;

}

var tanya = createPerson("tanya","30","female");

var ansel = createPerson("ansel","30","male");

tanyasayName();

anselsayName();

还有一种办法是利用无敌的this,因为this就表示当前运行时的对象,将构造函数this的作用域指向新对象,将当前运行对象的属性和方法都赋给新对象,这样对象模式称为构造函数模式

代码如下:

function Person(name,age,job){

thisname = name;

thisage = age;

thisjob = job;

thissayName = function(){

alert(thisname);

};

}

var tanya = new Person("tanya","30","female");

var ansel = new Person("ansel","30","male");

tanyasayName();

anselsayName();

在这个例子中,tanya和ansel都有一个constructor属性,该属性指向person。

考虑一下如下的情况:

代码如下:

function Person(name,age,job){

thisname = name;

thisage = age;

thisjob = job;

thissayName = function(){

alert(thisname);

};

}

Person("tanya","30","female");

Person("ansel","30","male");

windowsayName();

windowsayName();

发现两次弹出的都是ansel,这是因为不用new的话,就不是一个person的实例,而仅仅在执行函数。而在全局作用域调用一个函数时this总是指向Global对象。而Global对象在浏览器中就是window对象。

我们还可以用构造模式在另外一个对象中调用sayName方法,还记得Apply和call么,来吧再考虑另外一种情况,

代码如下:

function Person(name,age,job){

thisname = name;

thisage = age;

thisjob = job;

thissayName = function(){

alert(thisname);

};

}

var olivia = {};

Personcall(olivia,"tanya","30","female");

oliviasayName();

var philip = {}

Personapply(philip,["ansel","30","male"]);

philipsayName();

原型模式就要考虑原型链了,分析一下,sayName方法在实例中被重复定义了两次,但其实没有必要创造两个一样的副本。使用原型方法,可以使是tanya和ansel的共享一个sayName方法。

于是原型模式的写法如下:

代码如下:

function Person(name,age,job){

thisname = name;

thisage = age;

thisjob = job;

}

PersonprototypesayName= function(){

alert(thisname);

};

var tanya = new Person("tanya","30","female");

var ansel = new Person("ansel","30","male");

tanyasayName();

anselsayName();

实际应用时,不是一成不变的套用某种模式,活学活用。需要共享方法的时候就用原型模式,需要使用副本的时候就用构造模式,还可以结合起来,把所有信息都封装在构造函数中,而通过在构造函数中初始化原型,使得对象保持了同时使用构造函数和原型的优点。

代码如下:

function Person(name,age,job){

thisname = name;

thisage = age;

thisjob = job;

if (typeof sayName != "function" ){

PersonprototypesayName= function(){

alert(thisname);

};

}

}

var tanya = new Person("tanya","30","female");

var ansel = new Person("ansel","30","male");

anselsayName = function () {

alert("Hi ansel, how hansome you are!");

}

tanyasayName();

anselsayName();

欢迎分享,转载请注明来源:品搜搜测评网

原文地址:https://pinsoso.cn/shuma/933908.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-08-17
下一篇2023-08-17

随机推荐

  • 男士洗面奶哪个牌子最好

    男士洗面奶如下:1、碧欧泉男士洁面乳碧欧泉男士洁面乳是法国的高端护肤品牌,价格偏高,而且基本不打折。适合所有肤质男士,深层清洁力很强,而且保湿锁水效果挺好。用完之后脸部不会觉得很干,早上睡醒皮肤都还有点水滑滑的感觉。2、迪蕾氨基酸洁面泡泡迪

    2024-04-15
    47900
  • 盲盒现在哪些渠道效果比较好?

    展开3全部事实上,盲盒的玩法并不稀奇,尤其容易理解,花钱拆盒得结果。和我们线下买**,大转盘抽奖只是形式上的不同,主要是利用人性的好奇心和贪婪。列举一下三个进货渠道:1、16881688是中国最大的线上批发商城,几乎可以满足你对货源

    2024-04-15
    36200
  • 痘痘还在长~~脸上坑坑洼洼的已成月球~~可怜可怜我

    我也经历过你这样的情况!!你这主要是因为毛孔大!加上你工作的环境不是很清洁!一些你不干净的东西通过毛孔进入你的皮肤!从而是皮肤不能正常的新陈代谢造成的!毛孔里有很多危害你皮肤的污垢!你现在应该从最基础的肌肤护理开始!!要有一定的耐心!效果不

    2024-04-15
    34800
  • 我想给我妈妈买眼部精华或者眼霜,我想知道哪个牌子适合她,他接近50岁了,想去眼纹,黑眼圈

    选择眼部精华或眼霜的品牌和类型需要考虑许多因素,包括你的妈妈的肤质、需求、预算和个人偏好。以下是一些适合成熟肌肤的眼部护肤品牌和产品的推荐:1 La Mer眼部精华霜:这是一款轻盈的眼部精华霜,可显著减少细纹和皱纹,同时提供深层保湿。2 E

    2024-04-15
    31400
  • 水光焕颜套盒好不好

    水光焕颜套盒好。根据查询相关公开信息显示,这个水光焕颜套盒一般是指保湿补水系列的美容护肤品,它们通常包括洁面、爽肤水、乳液、精华液和面霜等,这类套盒质量是很好的,可以满足日常护肤需求。女人30岁以后,选择使用焕颜套盒还是补水套盒,这是众多女

    2024-04-15
    24700
  • 大漂亮三周年卖的40块钱的福利套盒是什么

    是一款限时特惠的美容礼盒。根据查询大漂亮官方的介绍得知,这个福利套盒包括两个主要产品:一个是10毫升的小样玫瑰精华液,另一个是一片玫瑰面膜。这两个产品都是大漂亮品牌的明星产品,其中玫瑰精华液富含多种植物精华和玫瑰精油,能够深层滋养肌肤,提升

    2024-04-15
    39200
  • 兰蔻粉水和红水感肌水光精华露哪个先用?

    首先使用兰蔻粉水。洁面后,首先使用粉水能滋润皮肤,打开肌肤吸收的通道,然后使用水感肌水光针,修护肌肤。兰蔻粉水是一款二次清洁水,主要的功效为补水,最适合干性肌肤使用,缓解皮肤干燥的问题,水乳质地,容易吸收,令肌肤水润细腻。水感肌水光针是一款

    2024-04-15
    33500

发表评论

登录后才能评论
保存