没有办法在javascript中有基于类的对象? [英] No ways to have class-based objects in javascript?

查看:213
本文介绍了没有办法在javascript中有基于类的对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

基于JavaScript原型的面向对象编程风格很有趣,但是在很多情况下,你需要能够从类创建对象。



例如,在矢量绘图应用程序中,工作空间在绘图开始时通常为空:我无法从现有的线创建新的线。更普遍的是,对象被动态创建的每一种情况都需要使用类。



我已经阅读了很多教程和书Javascript:the good parts ,但是在我看来,没有办法来定义类尊重1)封装和2)高效的成员方法声明(我的意思是:成员方法,被定义一次,并在每个类实例共享)。



要定义私有变量,使用闭包:

  function ClassA 
{
var value = 1;
this.getValue = function()
{
返回值;
}
}

这里的问题是每个ClassA将有自己的成员函数getValue的副本,这是不高效的。



为了有效地定义成员函数,正在使用原型:

  function ClassB()
{
this.value = 1;
}

ClassB.prototype.getValue = function()
{
return this.value;
}

这里的问题是成员变量value p>

我不认为这个问题很容易解决,因为私有变量需要定义DURING对象创建(使对象可以访问其上下文创建,而不暴露你的值),而基于原型的成员函数定义必须在对象创建后进行,所以原型是有意义的(this.prototype不存在,我已经检查过了)。



还是我缺少某些内容?

/ p>

首先,感谢您的有趣答案。



我只想添加一点精确度初始消息:



我真正想做的是有1)私有变量(封装是好的,因为人们只能访问他们需要的东西)和2)高效成员方法声明(避免复制)。



似乎简单的私有变量声明只能通过在javascript中的闭包来实现,这本质上是为什么我专注于基于类的方法。如果有一种方法可以用基于原型的方法来实现简单的私有变量声明,那对我来说没关系,我不是一个激烈的基于类的方法支持。



阅读答案,似乎简单的解决方案是忘记privates,并使用特殊的编码约定,以阻止其他程序员直接访问私有变量...



解决方案

我不知道想要沮丧,因为你似乎是StackOverflow的一个相当新的成员,但我将不得不在你的脸上说一点,说 尝试在JavaScript中实现经典继承是一个糟糕的主意



注意:我说,在JavaScript中实现经典继承是一个坏主意我的意思是试图在JavaScript中模拟实际的类,接口,访问修饰符等是一个坏主意。然而,经典继承作为JavaScript中的设计模式是有用的,因为它只是用于原型继承的语法糖(例如最大最小类)。我一直在我的代码中使用这种设计模式( a la augment )。



JavaScript是一种原型面向对象的编程语言。不是一种经典的面向对象的编程语言。当然,您可以在JavaScript之上实现经典继承,但在您确定以下事项之前:


  1. 你违背了语言的精神,这意味着你会面临问题。许多问题 - 性能,可读性,可维护性等。

  2. 您不需要类。托马斯,我知道你真的相信你需要上课,但相信我。您不需要。

因为您的缘故,我会为这个问题提供两个答案。第一个将告诉你如何在JavaScript中做经典继承。



JavaScript中的传统继承



大多数程序员开始尝试在JavaScript中实现经典继承。即使像Douglas Crockford这样的JavaScript Gurus也试图在JavaScript中实现经典继承。我也尝试在JavaScript中实现经典继承。



首先,我创建了一个名为的函数库,然后扩充。但是我不建议你使用这些库,因为它们违背了JavaScript的精神。事实是,当我写这些经典的继承库时,我还是一个业余的JavaScript程序员。



我提到这个的唯一原因是因为每个人都是一个业余的时间,虽然我更喜欢你没有使用JavaScript中的经典继承模式,我不能指望你理解为什么原型继承问题还没有结束。



你不能学会如何循环而不会掉下几次。我相信你仍然处于原型继承的学习阶段。您对经典继承的需求就像周期上的训练轮。



然而,训练轮是重要的。如果你想有一些经典的继承库,应该让你更方便在JavaScript中编写代码。其中一个图书馆是 jTypes



注意:我个人不喜欢jTypes一个位。



JavaScript中的原型继承



我将这部分写为一个里程碑您可以稍后再回来,并知道下一步该做什么何时,您已准备好了解

首先,以下行是错误的:


基于javascript原型的面向对象编程风格很有趣,但是有很多情况下你需要从类中创建对象。 p>

这是错误的,因为:



  1. 无法在JavaScript中创建类。

是的,可以在JavaScript中模拟经典继承。但是,您仍然从对象而不是类继承属性。例如, ECMAScript Harmony类仅是原型继承的古典模式的语法糖。 p>

在同一上下文中,您给出的示例也是错误的:


一个矢量绘图应用程序,工作区通常在绘图的开头是空的:我不能从现有的一个新的线。更一般地,动态创建对象的每种情况都需要使用类。


是的,您可以从现有的即使工作空间在开始时是空的。

  var line = {
x1:0 ,
y1:0,
x2:0,
y2:0,
draw:function(){
//绘制逻辑
} b $ b create:function(x1,y1,x2,y2){
var line = Object.create(this);
line.x1 = x1;
line.y1 = y1;
line.x2 = x2;
line.y2 = y2;
return line;
}
};

现在你可以通过调用 line.draw 或者你可以从中创建一个新行:

  var line2 = line.create 0,0,100); 
var line3 = line.create(0,100,100,100);
var line4 = line.create(100,100,100,0);
var line5 = line.create(100,0,0,0);

line2.draw();
line3.draw();
line4.draw();
line5.draw();

线 line2 line3 line4 line5 form a 100x100 正方形。



结论



所以你看到你真的不需要JavaScript中的类。对象就够了。



这就是说,你不能让每个实例的公共函数访问对象的私有状态,而每个实例没有自己的集合



这不是问题,因为:


  1. 真的不需要私人状态。

  2. 如果你真的想让一个变量私有,那么提到的ThiefMaster 只是在变量名前添加下划线,并告诉用户不要混淆。 li>


The javascript prototype-based object-oriented programming style is interesting, but there are a lot of situations where you need the ability to create objects from a class.

For instance in a vector drawing application, the workspace will usually be empty at the beginning of the drawing : I cannot create a new "line" from an existing one. More generally, every situation where objects are being dynamically created require the use of classes.

I've read a lot of tutorials and the book "Javascript : the good parts", but yet it seems to me that there is no way to define classes that respect 1) encapsulation and 2) efficient member methods declaration (I mean : member methods that are being defined once, and shared among every class instances).

To define private variables, closures are being used :

function ClassA()
{
    var value = 1;
    this.getValue = function()
    {
        return value;
    }
}

The problem here is that every instance of "ClassA" will have its own copy of the member function "getValue", which is not efficient.

To define member functions efficiently, prototype is being used :

function ClassB()
{
    this.value = 1;
}

ClassB.prototype.getValue = function()
{
    return this.value;
}

The problem here is that the member variable "value" is public.

I don't think that this issue can be solved easily, since "private" variables need to be defined DURING object creation (so that the object can have access to its context of creation, without exposing thoses values) whereas prototype-based member functions definition has to be done AFTER object creation, so that prototype makes sense ("this.prototype" does not exists, I've checked).

Or am I missing something ?


EDIT :

First of all, thank you for your interesting answers.

I just wanted to add a little precision to my initial message :

What I really want to do is to have 1) private variables (encapsulation is good, because people only have access to what they need) and 2) efficient member methods declaration (avoid copies).

It seems that simple private variables declaration can really only be achieved via closure in javascript, that's essentially why I focused on the class based approach. If there is a way to achieve simple private variables declaration with a prototype based approach, that's okay for me, I'm not a fierce class-based approach proponnent.

After reading the answers, it seems like the simple solution is to forget about privates, and use a special coding conventions to detter other programmers from accessing "private" variables directly...

And I agree, my title / first sentence was misleading regarding the issue I wanted to discuss here.

解决方案

I don't want to be discouraging since you seem to be a fairly new member of StackOverflow, however I'm going to have to be a little in your face and say that it's a really bad idea to try to implement classical inheritance in JavaScript.

Note: When I say that it's a bad idea to implement classical inheritance in JavaScript I mean that trying to simulate actual classes, interfaces, access modifiers, etc. in JavaScript is a bad idea. Nevertheless, classical inheritance as a design pattern in JavaScript is useful as it's just syntactic sugar for prototypal inheritance (e.g. maximally minimal classes). I use this design pattern in my code all the time (a la augment).

JavaScript is a prototypal object-oriented programming language. Not a classical object-oriented programming language. Sure, you can implement classical inheritance on top of JavaScript but before you do keep the following things in mind:

  1. You're going against the spirit of the language, which means that you'll be faced with problems. Lots of problems - performance, readability, maintainability, etc.
  2. You don't need classes. Thomas, I know that you truly believe that you need classes but trust me on this. You don't.

For your sake I'll provide two answers to this question. The first one will show you how to do classical inheritance in JavaScript. The second one (which I recommend) will teach you to embrace prototypal inheritance.

Classical Inheritance in JavaScript

Most programmers start with trying to implement classical inheritance in JavaScript. Even JavaScript Gurus like Douglas Crockford tried to implement classical inheritance in JavaScript. I too tried to implement classical inheritance in JavaScript.

First I created a library called Clockwork and then augment. However I wouldn't recommend you to use either of these libraries because they go against the spirit of JavaScript. The truth is that I was still an amateur JavaScript programmer when I wrote these classical inheritance libraries.

The only reason I mention this is because everyone is an amateur at some point of time, and although I would prefer that you didn't use classical inheritance patterns in JavaScript, I can't expect you to understand why prototypal inheritance matters just yet.

You can't learn how to cycle without falling down a few times. I believe you're still in the learning phase with respect to prototypal inheritance. Your need for classical inheritance is like the training wheels on cycles.

Nevertheless, training wheels are important. If you want there are some classical inheritance libraries out there which should make you more comfortable writing code in JavaScript. One such library is jTypes. Just remember to take off the training wheels when you are confident of your skills as a JavaScript programmer.

Note: Personally I don't like jTypes one bit.

Prototypal Inheritance in JavaScript

I'm writing this section as a milestone for you so that you can come back later and know what to do next when you are ready to learn about true prototypal inheritance.

First of all the following line is wrong:

The javascript prototype-based object-oriented programming style is interesting, but there are a lot of situations where you need the ability to create objects from a class.

This is wrong because:

  1. You will never need to create objects from a class in JavaScript.
  2. There is no way to create a class in JavaScript.

Yes it's possible to simulate classical inheritance in JavaScript. However you're still inheriting properties from objects and not classes. For example, ECMAScript Harmony classes are just syntactic sugar for the classical pattern of prototypal inheritance.

In the same context the example you gave is also wrong:

For instance in a vector drawing application, the workspace will usually be empty at the beginning of the drawing : I cannot create a new "line" from an existing one. More generally, every situation where objects are being dynamically created require the use of classes.

Yes you can create a new line from an existing one even though the workspace is empty in the beginning. What you need to understand is that the line is not actually drawn though.

var line = {
    x1: 0,
    y1: 0,
    x2: 0,
    y2: 0,
    draw: function () {
        // drawing logic
    },
    create: function (x1, y1, x2, y2) {
        var line = Object.create(this);
        line.x1 = x1;
        line.y1 = y1;
        line.x2 = x2;
        line.y2 = y2;
        return line;
    }
};

Now you can draw your the above line by simply calling line.draw or else you could create a new line from it:

var line2 = line.create(0, 0, 0, 100);
var line3 = line.create(0, 100, 100, 100);
var line4 = line.create(100, 100, 100, 0);
var line5 = line.create(100, 0, 0, 0);

line2.draw();
line3.draw();
line4.draw();
line5.draw();

The lines line2, line3, line4 and line5 form a 100x100 square when drawn.

Conclusion

So you see you really don't need classes in JavaScript. Objects are enough. Encapsulation can be easily achieved using functions.

That being said you can't have public functions of each instance access the private state of the object without each instance having its own set of public functions.

This is not a problem however because:

  1. You don't really need private state. You may think that you do, but you really don't.
  2. If you really want to make a variable private then as ThiefMaster mentioned just prefix the variable name with an underscore and tell your users not to mess with it.

这篇关于没有办法在javascript中有基于类的对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆