【问题标题】:Correct way to build classes in JavaScript?在 JavaScript 中构建类的正确方法?
【发布时间】:2011-08-25 00:57:24
【问题描述】:
我是 JavaScript 新手,并试图了解我应该如何编写类(我在“常规”OO 语言方面的背景,例如 java 和 c++)。
我知道我有两种选择:
如果我希望我的类有私有方法和成员,我不能在原型中定义它们。但在这种情况下,将为每个创建的新对象构建它们(内存问题)。
如果我在类原型中定义方法,我将没有封装(这对我来说很奇怪,作为一个 java/c++ 开发人员:P)。
您使用两种方法中的哪一种?为什么?
【问题讨论】:
标签:
javascript
prototype-programming
【解决方案1】:
所以,我认为这个问题没有“正确答案”...基本上是您喜欢并认为最适合您的特定用途的内容。我的许多课程都是“静态课程”,例如
var MyClassName = {
methodName: function() { },
//...
}
因为我从不需要实例化它们。当我需要实例化多个实例时,我使用原型方法。
如果您需要私有变量,您可以定义一个函数/类来执行私有变量,以及需要在该函数/类中访问这些私有变量的方法。然后,对所有不需要访问私有变量的方法使用原型方法。例如
var PageClass = function() {
var _birthdate;
this.getBirthdate = function() {
return typeof(_birthdate) == "undefined" ? null : _birthdate;
}
this.setBirthdate = function( date ) {
if( typeof(date) == 'object' && date.constructor == Date ) {
_birthdate = date;
}
else {
throw "Invalid Argument Exception: PageClass.setBirthdate expects parameter of type 'Date'";
}
}
}
PageClass.prototype.doSomething = function() {
alert("DOING SOMETHING");
}
两者都做应该能让你的实例化更轻一些,但仍然给你一些封装。到目前为止,我从来没有为私有变量烦恼过。
【解决方案2】:
如果您使用原型框架,您最好使用他们实现类和继承的方式。你可能指的是this article
通常我认为私有成员不会在 javascript 中使用。 (编辑:不在实例化类中。我经常在我们的代码库中看到一些“模块”,它们确实保持私有状态,但可以被视为单例)
Kevin 的回答非常概括。技术上可以解决语言缺乏封装的问题,但如果你的类要被实例化很多,这是有代价的。此外,我认为如果您要使用继承,您需要做一些工作来获得受保护的可见性。
例如,我认为在查看外部资源时我没有看到任何私人内容。他们确实将“//private”放在应该是私有的方法上,这暗示它们不应该被直接调用。
这确实意味着如果您要以这种方式编写代码,您需要更多的“纪律”来编写 getter/setter。
【解决方案3】:
为什么是的,现在有……。
上面的答案在当时是正确的。
这是新的解决方案:
'use strict';
// Declare our class
class Metadata {
// Declare the constructor and pass it some values - a and b are "defaults"
constructor( ninfo, a = 1.0, b = 1.0 )
{
// Set our class variables
this.ninfo = ninfo;
this.a = a;
this.b = b;
// Define our "secret" or nonenumerable options
Object.defineProperty( this, 'addA', {
enumerable: false,
writable: false,
// Have it add our passed in value
value: n => this.a += n
} );
}
}
// Call our class and pass in some variables
let x = new Metadata( "we have a and b", 1.0 );
// Log our result if we call "addA"
console.log( x.addA( 3 ) ); // => 4
// Log our object
console.log( x ); // => Metadata { ninfo: 'we have a and b', a: 4, b: 2 }
// Log our object 'for real'
console.log( require( 'util' ).inspect( x, { showHidden: true, depth: null } ) );
// result
// Metadata {
// ninfo: 'we have a and b',
// a: 4,
// b: 2,
// [addA]: { [Function: value] [length]: 1, [name]: 'value' } }