【问题标题】:Javascript "private" vs. instance propertiesJavascript“私有”与实例属性
【发布时间】:2012-02-08 16:05:09
【问题描述】:

我正在做一些 Javascript 研发工作,虽然我已经阅读了 Javascript:权威指南Javascript 面向对象编程,但我仍然遇到一些小问题我从基于类的 OOP 转向基于词汇的、基于对象的 OOP。

我喜欢模块。命名空间、子类和接口。 w00吨。这是我正在玩的东西:

var Classes = {
    _proto : {
        whatAreYou : function(){
            return this.name;
        }
    },
    Globe : function(){
        this.name = "Globe"
    },
    Umbrella : new function(){
        this.name = "Umbrella"
    }(),
    Igloo : function(){
        function Igloo(madeOf){
            this.name = "Igloo"
            _material = madeOf;
        }
        // Igloo specific
        Igloo.prototype = {
            getMaterial : function(){
                return _material;
            }
        }
        // the rest
        for(var p in Classes._proto){
            Igloo.prototype[p] = Classes._proto[p]
        }
        return new Igloo(arguments[0]);
    },
    House : function(){
        function House(){
            this.name = "My House"
        }
        House.prototype = Classes._proto
        return new House()
    }
}
Classes.Globe.prototype = Classes._proto
Classes.Umbrella.prototype = Classes._proto

$(document).ready(function(){    
    var globe, umb, igloo, house;

    globe     = new Classes.Globe();
    umb       = Classes.Umbrella;
    igloo     = new Classes.Igloo("Ice");
    house     = new Classes.House();

    var objects = [globe, umb, igloo, house]

    for(var i = 0, len = objects.length; i < len; i++){
        var me = objects[i];
        if("whatAreYou" in me){
            console.log(me.whatAreYou())
        }else{
            console.warn("unavailable")
        }
    }
})

我试图找到将我的代码模块化(并了解原型设计)并将所有内容分开的最佳方法。注意Globe 是一个需要用new 实例化的函数,Umbrella 是一个单例并且已经声明,Igloo 使用了我今天在工作中想到的东西,并且似乎工作得和我想的一样好希望,House 是另一个用于测试的 Iglooesque 函数。

这个的输出是:

Globe
unavailable
Igloo
My House

到目前为止一切顺利。由于语法原因,必须在 Classes 对象之外声明 Globe 原型,Umbrella 不能接受,因为它已经存在(或实例化或......不知道这个“正确”术语),并且 Igloo 有一些闭包声明给你。

但是...

如果我将其更改为:

var Classes = {
    _proto : {
        whatAreYou : function(){
            return _name;
        }
    },
    Globe : function(){
        _name = "Globe"
    },
    Umbrella : new function(){
        _name = "Umbrella"
    }(),
    Igloo : function(){
        function Igloo(madeOf){
            _name = "Igloo"
            _material = madeOf;
        }
        // Igloo specific
        Igloo.prototype = {
            getMaterial : function(){
                return _material;
            }
        }
        // the rest
        for(var p in Classes._proto){
            Igloo.prototype[p] = Classes._proto[p]
        }
        return new Igloo(arguments[0]);
    },
    House : function(){
        function House(){
            _name = "My House"
        }
        House.prototype = Classes._proto
        return new House()
    }
}
Classes.Globe.prototype = Classes._proto
Classes.Umbrella.prototype = Classes._proto

$(document).ready(function(){    
    var globe, umb, igloo, house;

    globe     = new Classes.Globe();
    umb       = Classes.Umbrella;
    igloo     = new Classes.Igloo("Ice");
    house     = new Classes.House();

    var objects = [globe, umb, igloo, house]

    for(var i = 0, len = objects.length; i < len; i++){
        var me = objects[i];
        if("whatAreYou" in me){
            console.log(me.whatAreYou())
        }else{
            console.warn("unavailable")
        }
    }
})

并将this.name 变成_name(“私有”属性),它不起作用,而是输出:

My House
unavailable
My House
My House

有人好心解释一下吗?显然_name 在每次迭代时都会被覆盖,而不是读取它所附加的对象的属性。

这一切似乎有点过于冗长,需要this 和有点奇怪的 IMO。

谢谢:)

【问题讨论】:

  • 因为你的“私人”是全球性的。
  • 我最初有 var 关键字,但错过了将其放回原处。这就是为什么您不在凌晨 3 点提问的原因;)无论如何,谢谢您的回答,它使现在更有意义了,同样的解决方案也适用。干杯!
  • 您可能对ES5 OO sugar感兴趣
  • 我已经看到并使用了其中一些库,这些库允许更结构化的类 OOP 风格的使用,但我仍然需要了解该语言。不过谢谢,我一直在寻找好的库。
  • 文章列出了原型的OO机制。不是肮脏的经典 OO 仿真。我个人最喜欢的是combining extend and Object.create

标签: javascript namespaces closures


【解决方案1】:

你声明了一个全局变量。在声明此内容后,您可以在代码中的任何位置使用它。无论您在哪里向_name(更接近window._name)提出请求,您都会收到一个全球性的信息。在您的情况下,每个函数中都替换了 _name 。最后一个功能是House,已经设置为“My House”

“私有”(局部)变量的声明必须使用var声明

看看这个:

var foo = function( a ) { 
    _bar = a;
    this.showBar = function() { 
       console.log( _bar );
    }
};
var a = new foo(4);   // _bar ( ie window._bar) is set to 4

a.showBar(); //4


var b = new foo(1); // _bar  is set to 1
a.showBar(); //1
b.showBar(); //1

_bar = 5; // window._bar = 5; 
a.showBar();// 5

应该是:

var foo = function( a ) { 

    var _bar = a;
    // _bar is now visibled only from both that function
    // and functions that will create or delegate from this function,
    this.showBar = function() { 
       console.log( _bar );
    };
    this.setBar = function( val ) { 
        _bar = val;
    };
    this.delegateShowBar = function() { 
       return function( ) { 
           console.log( _bar );
       }
    }
};
foo.prototype.whatever = function( ){ 
    //Remember - here don't have access to _bar
};

var a = new foo(4);
a.showBar(); //4

_bar // ReferenceError: _bar is not defined  :)
var b = new foo(1);

a.showBar(); //4
b.showBar(); //1

delegatedShowBar  = a.delegateShowBar();
a.setBar(6);
a.showBar();//6
delegatedShowBar(); // 6

【讨论】:

    【解决方案2】:

    如果删除关键字“this”,则 _name 位于“Globe”范围内。

    查看您的代码。

    var globe, umb, igloo, house;
    
    globe     = new Classes.Globe();
    umb       = Classes.Umbrella;
    igloo     = new Classes.Igloo("Ice");
    house     = new Classes.House();
    

    最后房子会用“我的房子”的名字覆盖地球范围内的“_name”值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-03
      • 2013-11-19
      • 1970-01-01
      • 2010-11-27
      • 1970-01-01
      • 1970-01-01
      • 2010-10-17
      • 1970-01-01
      相关资源
      最近更新 更多