【问题标题】:javascript property accessorsjavascript 属性访问器
【发布时间】:2012-09-07 21:43:55
【问题描述】:

在 Javascript 中,使用属性访问器似乎并不常见(不像其他 OO 语言,例如 Java)。

如果我有一个带有名称的Person 对象,定义为

function Person(name) {
   this.name = name;
}

一个人的名字不会改变,但我确实希望能够在需要时访问它,所以我可以这样做:

function Person(name) {
   var name = name;
   this.getName = function() {
      return name;
   }
}

即使在动态语言中,我认为使用 getter 和 setter 的原则也适用于静态类型的 OO 语言(例如封装、添加验证、限制访问等)

这个问题可能会因为主观而被关闭,但我很好奇为什么这种行为不会更频繁地出现(例如,如果一切都是公开的,Java 开发人员会发疯的)。

在 javascript 中是否有“标准”方式来执行此操作?我见过Object.defineProperty,但并非所有浏览器都支持。

【问题讨论】:

  • 我认为这可能部分与减少带宽负载的愿望有关。额外的标记意味着线路上的额外位。虽然在像这样的小例子中,它可能看起来无关紧要,但在跨越数万行的强大应用程序中,它可能变得很重要。
  • 额外的定义也意味着客户端的额外内存使用,与我之前的评论相同。
  • 我认为已经给出的答案表明这对 SO 来说不是一个好问题,因为它很容易得到基于意见的答案。

标签: javascript accessor


【解决方案1】:

Javascript 具有可拦截的属性访问器:

http://ejohn.org/blog/javascript-getters-and-setters/

恕我直言,这是一个比 Java 更严格的显式 getter 执行统一访问原则更好的解决方案,但这也是该语言简单性和不灵活性的一部分(例如 Groovy 允许类似的拦截)。

【讨论】:

  • 在实践中,这种情况经常出现吗?或者您通常会看到直接的财产访问权?
  • 除非您需要修改访问器逻辑,否则您将使用直接属性访问:然后您将使用拦截。您可能需要问自己为什么在 Java 中使用 getter 和 setter,如果它们不做任何事情:封装原则背后的实际实际原因是什么。
  • 有时我会问自己为什么,尤其是在简单的属性上。从理论上讲,如果您想在 getter 或 setter 中添加一些其他行为(例如日志记录、验证等)。但实际上,这在简单属性上并不经常发生,因此它更像是一种 Java 约定(我更喜欢 groovy 的做法,您没有显式声明 getter 和 setter,但它们是生成并自动调用的,但允许您编写直接属性访问的语法)。
  • 是的,客户端代码的可维护更改。在 Java(和类似语言)中,使用直接属性访问会使内部更改和装饰器等模式复杂化。也许并不经常需要,但小额投资可能会带来大回报。在提供更灵活的方式来挂钩的语言中(包括大多数较新的语言),可以在需要时应用逻辑,在不需要时省略逻辑(不需要先发制人的约定)。
【解决方案2】:

我知道我对这个主题的想法。

getter 和 setter 都是邪恶的。

等等!真的!请稍等片刻,让我解释一下。

仅仅使用一种方法来获取和设置一个值是..好吧..有点毫无意义。它没有保护,不是真的,你投入的就是你得到的。

另一方面,我更喜欢将信息放入,然后将信息取出的方法。但这是神奇的部分!这不是相同的信息。不是直接的。

function Person(name) {
  this.getFullName = function() {return this.firstName + " " + this.lastName;};
  this.setBirthday = function(date) { this.birthday = date; };

  this.getAge = function() { /* Return age based on the birthday */ };
  this.isOfLegalDrinkingAge function() { /* do your math here too */ };
}

但大多数时候我只是将静态数据推入并取出静态数据。将它隐藏在 getter 和 setter 后面有什么意义?

作为次要原因,在处理 DOM 和大多数宿主对象时,您需要设置属性。你不玩 getter 和 setter。不使用它们符合 JS 编码员所做的其他“风格”。

【讨论】:

  • @BillyMoon -- 想知道他是否可以将他的用户名更改为“Javascript Preacher”
  • 感谢您的解释。我认为它不是 javascript“风味”的事实正是我在这里所追求的。
  • 我的问题是想知道事物是函数还是属性。有时它看起来相当随意。 Person.firstName 有效,但 Person.firstName() 不起作用,相反我需要使用 Person.fullName() 而不是 Person.fullName ...
  • @CuddleBunny 我明白你的意思。您始终可以使用typeof 运算符并查看它是否是一个函数。例如console.log(typeof Person.firstName)
  • 当然可以。我也总是使用 Visual Studio 在 JS 中进行开发,它往往会告诉我它是什么。我只是喜欢一致性。
【解决方案3】:

我认为答案是在 javascript 中模拟类并不常见,因为该语言实际上是原型语言。

虽然可以创建类结构(如您的示例中所示),但它们并不像 java 类,作为程序员,您最终会与细微差别作斗争。

但是,如果您接受了 javascript 的原型特性,那么您会因该语言的不同但具有凝聚力且简单的结构而获得回报。

没有必要使用具有原型结构的 getter 和 setter,因为您可以简单地设置一个对象,好吧,将其设置为一个值,然后通过调用它作为一个值来获取它。

Javascript 不会强迫您编写结构化代码,也不会阻止您这样做。我认为围绕 javascript 发展起来的文化已经形成了一种很好的编码风格,这种风格是完全有效的,并且与我使用的任何其他语言都不同。

我知道这个答案不是确定的和结论性的,但希望其中有一些想法可以帮助您找到您正在寻找的分析器。

【讨论】:

  • 谢谢。您可以直接在 java 中执行相同的 get/set 值(例如,如果您将事情公开),但这似乎不受欢迎。我想这在很大程度上与语言的习语已经成为什么有关。
  • Java 中的一个主要问题是您不希望以后更改类的接口。作为一种专为长期代码维护而设计的编译语言,其优先级与 JS 不同,JS 是一种部署在快速变化的网络环境中的基于源代码的语言。
【解决方案4】:

如果我没有正确理解问题,我深表歉意,但自我执行功能是使成员公开/私有的一种方式

var Person = function(){
  var _name = "Roger",
      self = { getName : function (){ return _name; }};
  return self;
}()

然后您可以从任何地方访问 Person.getName(),但不能设置 _name。

【讨论】:

  • 我知道你能做到这一点,只是看起来这不是很常见的做法......
【解决方案5】:

这是我用于本地字段的:

TYPE_DEFAULT_VALUE= {
    number: 0,
    string: "",
    array: [],
    object: {},
};

typeOf = function (object) {
    if (typeof object === "number" && isNaN(object))
        return NaN;
    try {
        return Object.prototype.toString.call(object).slice(8, -1).toLowerCase();
    }
    catch(ex) {
        return "N/A";
    };
};

getAccessor = function(obj, key, type, defaultValue) {
    if (defaultValue === undefined) 
        defaultValue =  TYPE_DEFAULT_VALUE[type] === undefined ? null : TYPE_DEFAULT_VALUE[type];
    return {
        enumerable: true,
        configurable: true,
        get: function () {
            if (obj[key] === undefined) 
                obj[key] = defaultValue;
            return obj[key];
        },
        set: function (value) {
            if (typeOf(value) === type)
                obj[key] = value;
        },
    };
}

LocalFields = function (fields, object) {
    /**
    * field properties
    * { 
    *   type: [ required ] ( number | string | array | object | ... ),
    *   defaultValue: [ optional ]
    * }
    */
    if (! fields)
        throw "Too few parameters ...";
    if (! object) 
        object = this;

    var obj = this;
    var fieldsAccessor = {};
    for(key in fields){
        field = fields[key];
        fieldHandler = key[0].toUpperCase() + key.substr(1);
        if(! field.type)
            throw "Type not set for field: " + key;

        fieldsAccessor[fieldHandler] = getAccessor(obj, fieldHandler, field.type, field.defaultValue)
    }
    Object.defineProperties(object, fieldsAccessor);
}

现在对于每个班级,我可以调用如下内容:

Person = function(){
    new LocalFields({
        id:     { type: "number" },
        name:   { type: "string" },
    }, this);
}

然后像 VS getter 和 setter 一样调用:

var alex = new Person();
alex.Name = "Alex Ramsi";
console.clear();
console.info(alex.Name);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-05
    • 2011-11-14
    • 1970-01-01
    • 2023-03-31
    • 2016-08-06
    • 1970-01-01
    相关资源
    最近更新 更多