Javascript:我是否需要为对象中的每个变量放置this.var? [英] Javascript: Do I need to put this.var for every variable in an object?

查看:146
本文介绍了Javascript:我是否需要为对象中的每个变量放置this.var?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在C ++中,我最熟悉的语言,通常是一个声明这样的对象:

In C++, the language I'm most comfortable with, usually one declares an object like this:

class foo
{
public:
    int bar;
    int getBar() { return bar; }
}

调用 getBar()工作正常(忽略 bar 可能未初始化的事实)。 getBar()中的变量 bar 在类 foo ,所以我不需要说 this-> bar 除非我真的需要明确表示我指的是' bar 而不是参数。

Calling getBar() works fine (ignoring the fact that bar might be uninitialized). The variable bar within getBar() is in the scope of class foo, so I don't need to say this->bar unless I really need to make it clear that I'm referring to the class' bar instead of, say, a parameter.

现在,我正试图在Javascript中开始使用OOP。所以,我查找如何定义类并尝试相同的事情:

Now, I'm trying to get started with OOP in Javascript. So, I look up how to define classes and try the same sort of thing:

function foo()
{
     this.bar = 0;
     this.getBar = function() { return bar; }
}

它给了我 bar未定义。将更改为 this.bar 可以解决问题,但为每个变量执行此操作会使我的代码变得非常混乱。这对每个变量都是必要的吗?由于我找不到任何与此相关的问题,这让我觉得我做的事情从根本上是错误的。

And it gives me bar is undefined. Changing the bar to this.bar fixes the issue, but doing that for every variable clutters up my code quite a bit. Is this necessary for every variable? Since I can't find any questions relating to this, it makes me feel like I'm doing something fundamentally wrong.

编辑:是的,所以,从评论我得到的是 this.bar ,一个对象的属性,引用不同于的东西bar ,一个局部变量。有人可以说,为什么这就是范围和对象,以及是否有另一种方法来定义一个不需要的对象?

Right, so, from the comments what I'm getting is that this.bar, a property of an object, references something different than bar, a local variable. Can someone say why exactly this is, in terms of scoping and objects, and if there's another way to define an object where this isn't necessary?

推荐答案

JavaScript没有基于类的对象模型。它使用了更强大的原型继承,它可以模仿类,但不适合它。一切都是对象,对象[可以]从其他对象继承。

JavaScript has no classes class-based object model. It uses the mightier prototypical inheritance, which can mimic classes, but is not suited well for it. Everything is an object, and objects [can] inherit from other objects.

构造函数只是一个为新创建的对象分配属性的函数。对象(通过 关键字)可以通过 关键字(该函数的本地关键字)。

A constructor is just a function that assigns properties to newly created objects. The object (created by a call with the new keyword) can be referenced trough the this keyword (which is local to the function).

A方法也只是一个名为 on 对象的函数 - 再次用这个指向该对象。至少当该函数作为对象的属性被调用时,使用成员运营商(点,括号)。这会给新手带来很多困惑,因为如果你传递那个函数(例如传递给事件监听器),它就会被访问它的对象分离。

A method also is just a function which is called on an object - again with this pointing to the object. At least when that function is invoked as a property of the object, using a member operator (dot, brackets). This causes lots of confusion to newbies, because if you pass around that function (e.g. to an event listener) it is "detached" from the object it was accessed on.

现在遗产在哪里? 类的实例继承自同一原型对象。方法被定义为该对象上的函数属性(而不是每个实例的一个函数),您调用它们的实例只是继承该属性。

Now where is the inheritance? Instances of a "class" inherit from the same prototype object. Methods are defined as function properties on that object (instead of one function for each instance), the instance on which you call them just inherits that property.

示例:

function Foo() {
    this.bar = "foo"; // creating a property on the instance
}
Foo.prototype.foo = 0; // of course you also can define other values to inherit
Foo.prototype.getBar = function() {
    // quite useless
    return this.bar;
}

var foo = new Foo; // creates an object which inherits from Foo.prototype,
                   // applies the Foo constructor on it and assigns it to the var
foo.getBar(); // "foo" - the inherited function is applied on the object and
              // returns its "bar" property
foo.bar; // "foo" - we could have done this easier.
foo[foo.bar]; // 0 - access the "foo" property, which is inherited
foo.foo = 1;  // and now overwrite it by creating an own property of foo
foo[foo.getBar()]; // 1 - gets the overwritten property value. Notice that
(new Foo).foo;     // is still 0

因此,我们只使用该对象的属性并对此感到满意。但是所有这些都是公开的,可以被覆盖/更改/删除!如果这与你无关,那你很幸运。您可以通过在名称前加上下划线来表示属性的私密性,但这只是对其他开发人员的提示,可能不会被遵守(尤其是错误)。

So, we did only use properties of that object and are happy with it. But all of them are "public", and can be overwritten/changed/deleted! If that doesn't matter you, you're lucky. You can indicate "privateness" of properties by prefixing their names with underscores, but that's only a hint to other developers and may not be obeyed (especially in error).

所以聪明的头脑找到了一个解决方案,它使用构造函数作为闭包,允许创建私有属性。每次执行javascript函数都会为局部变量创建一个新的变量环境,一旦执行完成,就可能会收集垃圾。在该范围内声明的每个函数也可以访问这些变量,并且只要可以调用这些函数(例如,通过事件监听器),环境就必须保持不变。因此,通过从构造函数中导出本地定义的函数,您可以使用只能由这些函数访问的局部变量来保留该变量环境。

So, clever minds have found a solution that uses the constructor function as a closure, allowing the creating of private "attributes". Every execution of a javascript function creates a new variable environment for local variables, which may get garbage collected once the execution has finished. Every function that is declared inside that scope also has access to these variables, and as long as those functions could be called (e.g. by an event listener) the environment must persist. So, by exporting locally defined functions from your constructor you preserve that variable environment with local variables that can only be accessed by these functions.

让我们看到它在行动:

function Foo() {
    var bar = "foo"; // a local variable
    this.getBar = function getter() {
        return bar; // accesses the local variable
    }; // the assignment to a property makes it available to outside
}

var foo = new Foo; // an object with one method, inheriting from a [currently] empty prototype
foo.getBar(); // "foo" - receives us the value of the "bar" variable in the constructor

此getter函数在构造函数中定义,现在称为特权方法,因为它可以访问私有(本地)属性(变量)。 bar 的值永远不会改变。当然,您也可以为它声明一个setter函数,并且可以添加一些验证等。

This getter function, which is defined inside the constructor, is now called a "privileged method" as it has access to the "private" (local) "attributes" (variables). The value of bar will never change. You also could declare a setter function for it, of course, and with that you might add some validation etc.

请注意原型对象上的方法没有访问权限到构造函数的局部变量,但他们可能使用特权方法。让我们添加一个:

Notice that the methods on the prototype object do not have access to the local variables of the constructor, yet they might use the privileged methods. Let's add one:

Foo.prototype.getFooBar = function() {
    return this.getBar() + "bar"; // access the "getBar" function on "this" instance
}
// the inheritance is dynamic, so we can use it on our existing foo object
foo.getFooBar(); // "foobar" - concatenated the "bar" value with a custom suffix

所以,你可以结合使用两种方法。请注意,特权方法需要更多内存,因为您创建了具有不同范围链的不同函数对象(但代码相同)。如果你要创建大量的实例,你应该只在原型上定义方法。

So, you can combine both approaches. Notice that the privileged methods need more memory, as you create distinct function objects with different scope chains (yet the same code). If you are going to create incredibly huge amounts of instances, you should define methods only on the prototype.

当你设置继承时,它会变得更加复杂一个类到另一个 - 基本上你必须让子原型对象从父类继承,并在子实例上应用父构造函数来创建私有属性。看一下更正javascript继承继承原型中的私有变量以JAVASCRIPT模块模式定义私有字段成员和继承如何在JS Revealing原型模式中实现继承?

It gets even a little more complicated when you are setting up inheritance from one "class" to another - basically you have to make the child prototype object inherit from the parent one, and apply the parent constructor on child instances to create the "private attributes". Have a look at Correct javascript inheritance, Private variables in inherited prototypes, Define Private field Members and Inheritance in JAVASCRIPT module pattern and How to implement inheritance in JS Revealing prototype pattern?

这篇关于Javascript:我是否需要为对象中的每个变量放置this.var?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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