【问题标题】:Javascript object: How to create a working object inclusive encapsulation?Javascript 对象:如何创建工作对象的包容性封装?
【发布时间】:2013-02-03 03:07:34
【问题描述】:

我想使用面向对象的 Javascript,但我的“对象”的行为并不像我期望的那样。

这是我的对象:

var Test = function(a){
    var variable = a;

    this.getA = function(){
        return this.variable;
    }

    this.setA = function(a){
        this.variable = a;
    }
}

现在我运行这段代码:

var a = new Test("foo");
var b = new Test("bar");

alert(a.getA());                //undefined, but "foo" expected
alert(a.getA() == b.getA());    //true, but false expected

alert(a.variable);              //undefined, as expected

a.variable = "whatever";
alert(a.getA());                //"whatever", but undefined expected
alert(a.variable);              //"whatever", but undefined expected

a.setA("somewhere");
alert(a.getA());                //"somewhere", as expected
alert(a.variable);              //"somewhere", but undefined expected

有谁知道如何创建一个功能对象,而不需要在开始时调用“setA(a)”,并且对象封装不允许 a.variable = “whatever”;?

【问题讨论】:

  • 您的期望基于什么? var variablethis.variable 没有直接关系

标签: javascript object constructor encapsulation


【解决方案1】:

如果您要封装a 的值,则无需使用this.variable 来访问该值,只需将this.variable 更改为variable 即可解决此问题。

变量具有函数作用域,因此var variable 定义了一个变量,该变量不仅适用于Test,还适用于setAgetA

var Test = function(a){
    var variable = a;

    this.getA = function(){
        //you want to access the variable,
        //not the property on the instance
        return variable;

    }

    this.setA = function(a){
        variable = a;
    }
}

【讨论】:

  • 有趣的是“this”有时会做什么。 ;-D 非常感谢!
【解决方案2】:

在 JS 中引用的任何 this 都将可公开访问。

但是,由于 closure 的概念,您可以拥有完全私有的状态,只需在函数内部声明变量(或函数)。

此外,除非您希望通过编码获得原型,否则您甚至不需要new,也不需要this

一个例子:

var makePerson = function (secret) {

    var is_alive = true,

        sayName = function () {
            if (!is_alive) { return; }
            console.log("My name is " + secret.name + ".");
        },

        sayAge = function () {
            if (!is_alive) { return; }
            console.log("My age is " + secret.age + ".");
        },

        haveBirthday = function () {
            if (!is_alive) { return; }
            secret.name += 1;
            console.log("I'm " + secret.name + 
                        ", and today I turned " + secret.age + ".");
        },

        die = function () {
            is_alive = false;
            console.log(secret.name + " died today;" +
                        " they were " + secret.age + " year" +
                        (secret.age > 1 ? "s" : "") + " old."   );
        },

        public_interface = { sayName      : sayName,
                             sayAge       : sayAge,
                             haveBirthday : haveBirthday,
                             die          : die           };

    return public_interface;
};


var bob = makePerson({ name : "Bob", age : 32 });

任何人都不能从外面触摸secret.namesecret.ageis_alive

bob.name; // undefined
bob.is_alive = false;  // Doesn't matter -- the code isn't relying on a public property.


bob.sayAge();       // "My age is 32"
bob.haveBirthday(); // "I'm Bob, and today I turned 33"
bob.die();          // "Bob died today; they were 33 years old"

更好的是,JS 允许你随时更改分配,所以你可能会担心这样的事情:

// person overwriting the function
bob.haveBirthday = function () { is_alive = false; };

...但是绝对没有理由担心有人这样做,因为他们无法访问这些内部属性。

bob.haveBirthday(); // window.is_alive = false;
bob.sayAge(); "My age is 33";

同样,如果你试图重写一个函数来窃取一个值:

bob.sayName = function () { return secret.name; };
bob.sayName(); // window.secret.name;  OR  ERROR: can't call `name` of `undefined`

任何未定义INSIDE函数的函数都NO可以访问内部属性或方法.

您可以以完全相同的方式拥有私有方法 - 事实上,所有这些函数都是私有的,直到我将它们全部附加到 public_interface 对象(这是我返回的)。

如果您开始使用prototype,请务必记住这一点。

var Thing = function (secret) {};
Thing.prototype.sayName = function () { console.log("My name is " + secret.name); };
var thing = new Thing({ name : "Bob", age : 32 });

thing.sayName(); // "My name is undefined"

甚至原型函数都不能访问私有状态——它们必须使用公共状态(通过this)。

您可以使用更复杂的结构,使多个闭包具有publicprivateprivate staticpublic static(这是prototype 最相似的)属性,但这是一个更高级一点,一开始会更混乱。

【讨论】:

  • 难以置信,这正是我完全看不懂的那种 JS 代码。也许我将来会学到这个。 ;) 同时,我仍然使用“new”,因为它从 Javascript 1.2 开始就存在并且是一种非常简单的方法。 +1 用于在 Javascript 中使用快速数组。我个人将数组 (JSON) 用于数据结构(模型),而将普通对象用于控制器。虽然我没有看到任何模型的 JS 对象的用途(好吧,数组也是对象,不是吗?),我也看不出为什么命令“new”应该是一件坏事,例如本地事件处理程序对象(“本地”=浏览器客户端中的永久对象)。
  • 这些不是 "fast-arrays",它们是对象。与其他必须创建类才能拥有对象的语言不同,在 JS 中,您只需转到 {} 即可获得一个对象。而JS中的EVERYTHING是一个对象,包括函数。这就是var func = function () {}; func.properties = {}; 起作用的原因。 func(); 有效。 func.properties.num = 12; 有效。而new 不是问题(但如果您使用this 并忘记致电new 可能会导致巨大的问题),不理解或使用任何私人状态,何时需要它是问题所在。如果你从不需要私有状态,那么我想不用担心。
  • 不。它是一个对象。如果我有var Thing = function () {};var makeThing = function () { return {}; };,并且我调用var a = new Thing(), b = makeThing(); 除了能够在Thing 上设置prototype(“公共静态”属性/方法),并且a.constructor; 指向@987654354 @,他们做的事情几乎完全相同。但是,如果您忘记在构造函数上调用 new,而不是返回具有公共属性/方法的新对象 ({}),它会将这些属性设置为 window... ...哎呀!
  • public_interface 没有数组?那么......但我认为它是一个数组,因为数组是从那以后的第一个对象。 ;) 对我来说:“object” = 提供访问局部变量的方法,“array” = 用于存储数据的基本数据结构(除了框架本身提供的基本方法之外没有任何方法,这些方法通常非常快)。但是,是的,Javascript 确实是一种非常灵活的语言,从字面上看,你可以做任何事情,但这并不能更好地理解其他程序员的代码。
  • @Marcus : public_interface 在我的示例中是一个附加了 methods 的 JavaScript 对象(它们都是 functions)。这些方法可以访问公共状态(globalthis),但也可以访问private 状态。 public_interface 对象没有附加一个“数据”对象。实际上,这就是为什么我在示例中将其称为 public_interface 的原因... ...因为它扩展了 public interfaceprivate 访问您分配给它的任何变量。这比大多数 JS 实现更像 Java/C/etc。
【解决方案3】:

只是为了好玩(或出于演示目的),我同时找到了另一个解决方案:

var Test = function(x){
    var variables = function(){}
    variables.variable = x; 

    this.getA = function(){
        return variables.variable;
    }

    this.setA = function(x){
        variables.variable = x;
    }
}

测试结果:

    var a = new Test("foo");
    var b = new Test("baz");

    alert(a.getA());                //"foo" as expected
    alert(a.getA() == b.getA());    //false as expected

    a.variable = "whatever";
    alert(a.getA());                //"foo" as expected
    alert(a.variable);              //"whatever", doesn't seem preventable

    a.setA("somewhere");
    alert(a.getA());                //"somewhere", as expected
    alert(a.variable);              //"whatever", doesn't seem preventable

【讨论】:

    猜你喜欢
    • 2011-03-24
    • 1970-01-01
    • 2010-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多