使用getter和setter将参数复制到对象实例

时间:2013-06-19 23:03:03

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

我有这个构造函数对象:

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 }

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

2 个答案:

答案 0 :(得分:2)

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

function () {
    return obj[prop];
}

使用

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

答案 1 :(得分:1)

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

@ 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