【问题标题】:Copy parameters to object instance with getters and setters使用 getter 和 setter 将参数复制到对象实例
【发布时间】:2013-06-16 16:02:00
【问题描述】:

我有这个构造函数对象:

function Bindable(obj) {
    var prop;

    for (prop in obj) {
        this.__defineGetter__(prop, function () {
            return obj[prop];
        });

        this.__defineSetter__(prop, function (val) {
            obj[prop] = val;
        });
    }
}

这样称呼的:

var model = new Bindable({
    name: 'Dave',
    level: 10,
    strength: 5
});

如果我console.log(model),则输出为:

Bindable { name=5, level=5, strength=5 }

为什么构造函数中的每个属性都分配了相同的值?

【问题讨论】:

  • 你为什么使用非标准的和弃用的__definePropert__而不是标准的Object.defineProperty
  • 因为这对我来说是新闻。

标签: javascript object constructor getter-setter ecmascript-5


【解决方案1】:

您正在创建一个闭包,该闭包在执行 getter/setter 函数时进行评估,而不是在定义它们时进行评估。在它们执行时,prop 具有在循环执行期间分配的最后一个值。您需要避免在 prop 上创建闭包。一种方法是使用IIFE。而不是使用这个参数:

function () {
    return obj[prop];
}

使用

(function(p) {
    return function() {
        return obj[p];
    };
}(prop));

【讨论】:

  • 这似乎是正确的。 .binding 处理程序而不是 IIFE 不会在这里提供更简单的解决方案吗?
  • 我不明白.binding 在这种情况下是如何工作的。请解释一下。
  • @davidkennedy85 There you go。您可以在绑定中设置 p 的值,而不是显式地包装在一个闭包中。
  • @BenjaminGruenbaum - 您仍然需要一个函数作为bind 的参数。您还需要提供一个this 参数(可能是null),这只会增加代码混乱。和 David 一样,我不明白 bind 是如何简化的。
  • 当前代码:(function(p) { return function() { return obj[p];};}(prop));。新代码function(p){ return obj[p]}.bind(null,prop);。你来判断。
【解决方案2】:

作为替代方案,这应该适合您。

Same principle as explained@Ted Hopp

但是现在我们有一个可重用的函数createGetterSetter,它使用ECMA5 方法Object.defineProperty 来定义getters and setters,正如@Benjamin Gruenbaum 所指出的那样。

它也使用 ECMA5 Object.keys 而不是您使用的 for..in

我认为这比 Ted 建议的解决方案更简洁(每个人都有自己的偏好)。

我不确定改进空间的唯一部分是var self = this;

Javascript

/*jslint maxerr: 50, indent: 4, browser: true */
/*global console */

(function () {
    "use strict";

    function createGetterSetter(object, map, prop) {
        Object.defineProperty(object, prop, {
            get: function () {
                return map[prop];
            },
            set: function (val) {
                map[prop] = val;
            }
        });
    }

    function Bindable(obj) {
        var self = this;

        Object.keys(obj).forEach(function (prop) {
            createGetterSetter(self, obj, prop);
        });
    }

    var model = new Bindable({
        name: 'Dave',
        level: 10,
        strength: 5
    });

    console.log(model.name, model.level, model.strength);
}());

输出

Dave 10 5

开启jsfiddle

【讨论】:

  • 这是一个非常优雅的解决方案。不过,我会将 Ted 的答案保留为选定的答案,因为它只是说明了问题所在。
猜你喜欢
  • 2011-08-27
  • 1970-01-01
  • 1970-01-01
  • 2010-09-29
  • 1970-01-01
  • 2012-08-25
  • 2018-08-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多