原型的实现和属性的封装

时间:2013-10-29 13:09:42

标签: javascript

需要具有可以实例化的类,保存私有和公共变量/方法。

只是想要理智地检查我在原型上的实现是否正确。

之前:(jsFiddle:http://jsfiddle.net/7UqSv/1/

var MyObject = (function ()
{        
    var oid = "'oid123'";
    var x = 1; 
    var y = 1;          
    incrementx = function()
    {        
         x = x +1;
         console.log('value of x: ' + x);
    }
    incrementxagain = function()
    {        
         x = x +1;
         console.log('value of x: ' + x);
    }
    return {
        oid : oid,
        incrementx: function (){ incrementx(); },
        incrementxagain: function (){ incrementxagain(); }      
    }
});

var NewMyObject = new MyObject();
NewMyObject.incrementx(); //outputs "value of x: 2"
NewMyObject.incrementxagain(); //outputs "value of x: 3"
console.log('oid ' + NewMyObject.oid); //outputs "oid 'oid123'"

之后:(jsFiddle:http://jsfiddle.net/7UqSv/6/

var MyObject = (function ()
{        
    var oid = "'oid123'";
    this.x = 1; 
    var y = 1;    
    //*** ADDED REFERENCE TO THIS USING $this
    var $this = this;
    //*** MOVED 'incrementx' FUNCTION TO PROTOTYPE BELOW
    incrementxagain = function()
    {        
         $this.x = $this.x +1;
         console.log('value of x: ' + $this.x);
    }
    return {
        oid : oid,
        incrementx: function (){ $this.incrementx(); },
        incrementxagain: function (){ incrementxagain(); }      
    }
});

 //****** ADDED PROTOTYPE METHOD
MyObject.prototype.incrementx = function() { 
    this.x = this.x + 1; 
    console.log('value of x:' + this.x);
}

var NewMyObject = new MyObject();
NewMyObject.incrementx(); //outputs "value of x: 2"
NewMyObject.incrementxagain(); //outputs "value of x: 3"
console.log('oid ' + NewMyObject.oid); //outputs "oid 'oid123'"

两者都有效,但发现很奇怪我必须在变量上使用var更改为this,然后在对象创建的$ this中存储对此的引用?此外,意味着由于我的代码有很多变量,我将不得不编写更多的代码,因为现在需要额外引用'this'?即:

这样:

result =(x + y + z)*(x + y + z);

变为:

this.result =(this.x + this.y + this.z)*(this.x + this.y + this.z);

只是一个完整性检查,我在这里做的不是anit模式或什么?

由于

1 个答案:

答案 0 :(得分:0)

一些评论:

  • 是的,不幸的是,在使用成员访问的任何地方都需要this
  • 常见的模式是使用名为self(或_self等)的变量来保留this引用。我会避免使用$this,因为它可能意味着涉及jQuery(或其他库)。这当然是我对编码约定的偏好,只要它在你的代码库中是一致的就没有错误。
  • 存储this引用用于从闭包(例如回调)引用this,例如:

    var MyObject = function() {
        var self = this;
        jQuery(something).on("click", function() {
            // `this` here is NOT what you expect; it is set by jQuery to be
            // the DOM element in this case; to refer to the object, use `self`
            // as defined above:
            self.clicked();
        });
    };
    
  • 您不需要构造函数周围的括号:var MyObj = (function()...);var MyObj = function()...;

  • 当您从构造函数返回某些内容时,它将成为构造对象。所以this != returnedValue !!! 注意,这可能会在您的代码中引入微妙的错误!!!! 因此,只需将内容添加到this(我稍后会举例)
  • >
  • 顺便说一下,incrementxagain 定义为var,所以它已经到了全球范围!另一个微妙的错误!!!
  • 名称MyObject有点迷惑; MyObject包含构造函数(传统OO术语中的类),而不是对象实例。所以我宁愿将其命名为MyClass(并将其用作var myObject = new MyClass())。这或多或少是一种偏好。

我的建议/示例,基于你的建议:

var MyClass = function(element) {
    // public fields
    this.oid = "'oid123'";
    this.x = 1;
    // private field
    var y = 1;
    // `element`, the argument, is another private field preserved in this closure

    var self = this;

    jQuery(element).on("click", function() {
        self.clicked();
    });

    // public accessor of private field
    this.getY = function() {
        // no this or self; the `y` variable of the closure is accessed
        return y;
    };

    // public method accessing private state
    this.incrementxagain = function() {
        // no inner closure, use `this` directly
        this.x = this.x + y;
    }
    // don't return anything; `this` is set correctly
});

// public methods
MyClass.prototype.incrementx = function() { 
    this.x = this.x + 1;
};

MyClass.prototype.clicked = function() {
    ...
};

var element = document.getElementById("foo");
var myObject = new MyClass(element);

现在myObject具有以下属性:

  • 的oid
  • X

和方法:

  • incrementx()
  • 点击()
  • 的getY()
  • incrementxagain()

我用于创建私有伪方法的模式,以便不为每个实例创建Function个对象:

var MyClass = (function() {
    function privatePseudoMethod1(x) {
        // `this` is passed as argument
        x.doStuff();
    }

    function privatePseudoMethod2() {
        // `this` is what you expect, but the call is more verbose
        this.doStuff();
    }

    // CONSTRUCTOR (to be returned after the prototype is set
    function MyClass(element) {
        ...
    }

    MyClass.prototype.xxx = function() {
        // two ways of calling private pseudo-methods
        privatePseudoMethod1(this);
        privatePseudoMethod1.call(this);
    };

    MyClass.prototype.doStuff = function() {
        ...
    };

    return MyClass; // <--- this becomes the constructor
})(); // <--- NOTE: the outer function is executed just once