搜索
首页web前端js教程在JavaScript中实现类的方式探讨_javascript技巧

在 javascript 中有很多方式来创建对象,所以创建对象的方式使用起来非常灵活。那么,到底哪一种方式是最恰当的对象创建方式呢?构造模式,原型模式还是对象原意模式(Object literal)呢?

但这些模式具体是怎么回事呢?

在开始讲解之前,让我们先清楚地介绍一下关于 javascript 基本知识。

有没有可能在 javascript 中实现面向对象编程的方式呢?

答案是可能的,javascript 是可以创建对象的!这种对象可以包含数据及能够操作数据的方法,甚至可以包含其他对象。它没有类但拥有构造函数;它没有类继承机制,但是可以通过原型(prototype)实现继承。

现在看起来,我们已经了解了在 javascript 中创建对象及实现基于对象编程时所必须的组成部分。

我们都知道 javascript 拥有私有变量。一个通过“var”关键字定义的变量,只能在函数体中被访问,而不能在函数外被访问。那么,如果我们不通过使用“var”关键字来定义变量会怎样呢?我们现在不对这个问题进行深入探讨,可能是通过“this”进行访问的,我会在另外的时间来详细讲述这个问题。

现在回到之前的问题。到底哪一种方式是最恰当的对象创建方式呢?
让我们用已经知晓的知识,通过创建Person的对象是来试验一下。

复制代码 代码如下:

var Person = {
firstName : 'John',
lastName : 'Cody',
fullName : '',
message : '',

createFullName : function () {
fullName = this.firstName + ' ' + this.lastName;
},

changeMessage : function (msg) {
this.message = msg;
},

getMessage : function () {
this.createFullName();
return this.message + ' ' + fullName;
}
}

Person.firstName = 'Eli';
Person.lastName = 'Flowers'
Person.changeMessage('welcome');
var message = Person.getMessage(); // welcome Eli Flowers
alert(message);

这是对象原意模式(literal pattern)。这非常接近我们常创建对象的方式。如果你不需要关心私有/包装的成员,并且你知道不将创建这个对象的实例。那么,这种方式将会很适合你。公有的成员可以做所有私有成员的事情,不是吗?但是,这不是一个类,而是一个对象而已,不能被创建实例并且不能被继承。

让我们尝试下其他的方面:
复制代码 代码如下:

var Person = {
firstName : 'John',
lastName : 'Cody',
fullName : '',
message : '',

createFullName : function () {
fullName = this.firstName + ' ' + this.lastName;
},

changeMessage : function (msg) {
this.message = msg;
},

getMessage : function () {
this.createFullName();
return this.message + ' ' + fullName;
}
}

Person.firstName = 'Eli';
Person.lastName = 'Flowers'
Person.changeMessage('welcome');
var message = Person.getMessage(); // welcome Eli Flowers
alert(message);

这是一种构造模式的实例(Constructor Pattern)。那么,这是类还是对象呢?应该 两种都算是吧。我们能够在当请求时把它当做对象Person来使用。它毕竟也只是一个函数而已。然而,它可以通过使用“new”关键字来实现创建新的实例功能。

在使用这种方式时,我们需要时刻记住如下要点:

1. 无论什么时候这个函数被调用时,它拥有一个特别的变量叫做“this”并且可以在全局范围内使用。全局范围依赖于这个函数自身的作用范围。

2. 无论什么时候通过“new”关键字创建这个函数的实例,“this”变量指向这个函数本身,并且这个“new”操作将会影响到函数体中的代码被执行。这也正是构造模式。

3. 任何附加到“this”变量下的变量都会成为公有属性并且任何通过“var”关键字定义的变量都将是属于私有属性。

4. 一个附加到“this”下的函数叫做特权函数,它可以访问所有的私有变量以及被附加到“this”下的函数及变量。

5. 私有函数可以访问到其他私有变量及私有函数。

6. 私有函数不能直接访问被附加到“this”变量和函数。我们可以通过创建一个私有变量“_that”并且将它赋值为“this”的方式实现。

7. 任何私有变量及函数对于其他私有函数及其他被附加到“this”的函数是可用的。这完全是可能的再javascript的作用范围下。

8. 一个变量:不是通过“var”关键字,也不是附加到“this”变量上以获得全局作用范围的。例如,对于一个自定义函数的作用范围。需要再一次地了解作用域及集群的知识。

这已经实现了我们想要的大部分要求了,但是,有时候“this”和“that”这两个入口变量很容易造成给人们带来疑惑。尤其对于那些一直坚持要求纯粹私有的人来说,更容易迷惑。

让我们再稍微修改下试试吧。
复制代码 代码如下:

var Person = function () {

//private
var firstName = 'John';
var lastName = 'Cody';
var fullName = '';
var message = '';


var createFullName = function () {
fullName = firstName + ' ' + lastName;
}

//public setters
var setMessage = function (msg) {
message = msg;
}

var setFirstName = function (fName) {
firstName = fName;
}

var setLastName = function (lName) {
lastName = lName;
}

var getMessage = function () {
createFullName();
return message + ' ' + fullName;
}

//functions exposed public
return {
setFirstName: setFirstName,
setLastName: setLastName,
setMessage: setMessage,
getMessage: getMessage
};

};

var person1 = new Person();
person1.setFirstName('Eli');
person1.setLastName('Flowers');
person1.setMessage('welcome');
var message = person1.getMessage(); // welcome Eli Flowers
alert(message);

这是一个显示模式(Revealing Pattern)。非常感谢 Christian Heilmann。使用这种模式的方式就是把请求的"getters" 和 "setters" 当作属性使用。我们很多都是从传统的Java编程中找到这样的身影并且很明显地知道实现它其实并不复杂。这同样是一种类似于当类继承自一个接口的情况。

这种模式大部分方面都实现得很好,仅仅只有一个很微小的问题。每一次当一个类的实例被创建时。这个新创建的对象获得了一份变量和函数的拷贝。现在,拷贝变量是没有问题的,我们希望对于每一个对象的数据都是属于对象自身的,那么,成员函数呢?他们仅仅是操作数据而已。那么,为什么需要拷贝他们呢?

这正是原型模式(Prototype)的优势所在。在所有实例中,所有东西都是被创建成一个原型,并且能够相互分享。我们仅仅需要做的就是依据原型创建共有函数。
复制代码 代码如下:

var Person = function () {

//private
var welcomeMessage = 'welcome';
var fullName = '';
var firstName = '';
var lastName = "";
var createFullName = function () {
Person.prototype.setFirstName('asdsad');
fullName = firstName + ' ' + lastName;
};

//constructor
var Person = function () { }; //will be created evrytime

//public
Person.prototype = {
getFullName: function () {
createFullName();
return welcomeMessage + ' ' + fullName;
},
setFirstName: function (fName) {
firstName = fName;
},
setLastName: function (lName) {
lastName = lName;
},
ChangeMessage: function (mesg) {
welcomeMessage = mesg;
}
}

return new Person(); // Person; //new Person();
};


var person1 = new Person();
person1.setFirstName ('Eli');
person1.setLastName('Flowers');
person1.ChangeMessage('welcome');
var message = person1.getFullName(); // welcome asdsad Flowers
alert(message);

原型模式存在的一个问题是它不能访问私有变量及私有函数,正因为这个问题,我们才会介绍闭包以及始终组织好创建类中存在的代码以使得它在全局范围内不会变得很混乱。所有都是属于 Person 类的作用范围内。

另外一个问题是每一次实例被创建时,全部的代码都被执行一遍,包括原型的绑定。对于我们中的一部分人来说,这仅仅只是一个效率问题。处理好这个问题的一种方式是仅仅在期望共有函数不可用的情况下绑定这个原型。

这样将会使得绑定原型操作只会在第一个实例被创建时执行,并且在那之后所有其他的实例都将只会进行检查操作。不幸的是,这样还是不能解决我们在上面例子中提到的问题,因为我们只有重新再来一次创建的函数用于生成一个闭包来达到这个类的效果。这样的话,至少我们减少了一部分内存的使用。

等等,还有另外一个问题是私有函数不能直接访问原型函数。

为什么你们一定得需要私有函数和私有变量呢?我知道你一定是想实现类的封装性,想确保类中的属性或者内部的数据不会被突然地修改了或者被内部的其他程序所修改,或者任何其他的操作……

你应该记住你是不能将 javascript 代码编译成二进制的,对于这种情况,你在一定程度上很恼火吧,这样代码始终都是可用的。所以,如果任何人想搅乱代码的话,不管你真正实现私有或者没有实现私有,不管你将代码给团队中的其他成员或者卖出去,他们都可以搅乱代码。实现私有化可能有那么一点点帮助吧。

另一个其他编程者使用的技术是使用约定命名,使用下划线 “_”给所有你想设成私有任何的东西加上前缀以规定它成为私有。
复制代码 代码如下:

(function () {
var Person = function () {
this._fullName = '';
this.welcomeMessage = '';
this.firstName = '';
this.lastName = "";
_that = this;

this._createFullName = function () {
this.ChangeMessage('Namaste');
this._fullName = this.firstName + ' ' + this.lastName;
};
}

//Shared Functions for Code optimization
Person.prototype = {
constructor: Person,
getFullName: function () {
this._createFullName();
return this.welcomeMessage + ' ' + this._fullName;
},
ChangeMessage: function (mesg) {
this.welcomeMessage = mesg;
}
}

this.Person = Person;
})();

var person1 = new Person();
person1.firstName = 'Eli';
person1.lastName = 'Flowers';
person1.ChangeMessage('Welcome');
var message = person1.getFullName(); // Namaste Eli Flowers
alert(message);

我不是说你不应该考虑 “private” 或者类似的知识。你是代码的设计者,所以你将知道怎么来管理并且知道怎么做才是最好的。根据你的需求,你可以使用任何一种设计模式或者多个设计模式组合一起使用。

无论你决定采用哪种设计模式,始终记住做尽量少的事情,不要在全局作用范围内实现闭包,尽量减少内存泄露,以及优化代码,并且组织好代码。所以,尽量多了解些作用域,闭包以及 “this” 的表现行为。

最后,祝编程愉快!

译后感

经常使用 javascript,对于它的印象一直都是直接拷贝过来就可以用的。最近使用 extjs,它的类框架非常好用。从这样文章也明白在 javascript 中实现类的各种方式,以及在文章最后讨论了类中私有成员的实现情况。
声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
Python vs. JavaScript:开发人员的比较分析Python vs. JavaScript:开发人员的比较分析May 09, 2025 am 12:22 AM

Python和JavaScript的主要区别在于类型系统和应用场景。1.Python使用动态类型,适合科学计算和数据分析。2.JavaScript采用弱类型,广泛用于前端和全栈开发。两者在异步编程和性能优化上各有优势,选择时应根据项目需求决定。

Python vs. JavaScript:选择合适的工具Python vs. JavaScript:选择合适的工具May 08, 2025 am 12:10 AM

选择Python还是JavaScript取决于项目类型:1)数据科学和自动化任务选择Python;2)前端和全栈开发选择JavaScript。Python因其在数据处理和自动化方面的强大库而备受青睐,而JavaScript则因其在网页交互和全栈开发中的优势而不可或缺。

Python和JavaScript:了解每个的优势Python和JavaScript:了解每个的优势May 06, 2025 am 12:15 AM

Python和JavaScript各有优势,选择取决于项目需求和个人偏好。1.Python易学,语法简洁,适用于数据科学和后端开发,但执行速度较慢。2.JavaScript在前端开发中无处不在,异步编程能力强,Node.js使其适用于全栈开发,但语法可能复杂且易出错。

JavaScript的核心:它是在C还是C上构建的?JavaScript的核心:它是在C还是C上构建的?May 05, 2025 am 12:07 AM

javascriptisnotbuiltoncorc; saninterpretedlanguagethatrunsonenginesoftenwritteninc.1)javascriptwasdesignedAsalightweight,解释edganguageforwebbrowsers.2)Enginesevolvedfromsimpleterterterpretpreterterterpretertestojitcompilerers,典型地提示。

JavaScript应用程序:从前端到后端JavaScript应用程序:从前端到后端May 04, 2025 am 12:12 AM

JavaScript可用于前端和后端开发。前端通过DOM操作增强用户体验,后端通过Node.js处理服务器任务。1.前端示例:改变网页文本内容。2.后端示例:创建Node.js服务器。

Python vs. JavaScript:您应该学到哪种语言?Python vs. JavaScript:您应该学到哪种语言?May 03, 2025 am 12:10 AM

选择Python还是JavaScript应基于职业发展、学习曲线和生态系统:1)职业发展:Python适合数据科学和后端开发,JavaScript适合前端和全栈开发。2)学习曲线:Python语法简洁,适合初学者;JavaScript语法灵活。3)生态系统:Python有丰富的科学计算库,JavaScript有强大的前端框架。

JavaScript框架:为现代网络开发提供动力JavaScript框架:为现代网络开发提供动力May 02, 2025 am 12:04 AM

JavaScript框架的强大之处在于简化开发、提升用户体验和应用性能。选择框架时应考虑:1.项目规模和复杂度,2.团队经验,3.生态系统和社区支持。

JavaScript,C和浏览器之间的关系JavaScript,C和浏览器之间的关系May 01, 2025 am 12:06 AM

引言我知道你可能会觉得奇怪,JavaScript、C 和浏览器之间到底有什么关系?它们之间看似毫无关联,但实际上,它们在现代网络开发中扮演着非常重要的角色。今天我们就来深入探讨一下这三者之间的紧密联系。通过这篇文章,你将了解到JavaScript如何在浏览器中运行,C 在浏览器引擎中的作用,以及它们如何共同推动网页的渲染和交互。JavaScript与浏览器的关系我们都知道,JavaScript是前端开发的核心语言,它直接在浏览器中运行,让网页变得生动有趣。你是否曾经想过,为什么JavaScr

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具

EditPlus 中文破解版

EditPlus 中文破解版

体积小,语法高亮,不支持代码提示功能

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

安全考试浏览器

安全考试浏览器

Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。