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

查看:26
本文介绍了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 is undefined.将 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 没有 classes 基于类的对象模型.它使用更强大的原型继承,它可以模仿类,但并不适合它.一切都是对象,对象[可以]从其他对象继承.

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.

构造函数只是一个为新创建的对象分配属性的函数.对象(通过使用 new 关键字) 可以通过 this 关键字(对于函数来说是本地的).

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).

方法也只是一个在对象上调用的函数——同样,this指向对象.至少当该函数作为对象的属性被调用时,使用 成员运算符(点,括号).这会给新手带来很多困惑,因为如果您传递该函数(例如传递给事件侦听器),它会与访问它的对象分离".

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.

让我们看看它的实际效果:

Let's see it in action:

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揭示原型模式中如何实现继承?

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天全站免登陆