javascript - 覆盖对象上的 setter

标签 javascript

我有一个带有 getter 和 setter 的 Object,我打算在其中保护一个属性,以便它只能通过一种方法进行更新。我们称此对象为 Person,它具有以下结构:

function Person(data) {
    var _name = data.name;

    this.name = function () {
        return _name;
    };
    this.setName = data.setName || function (newValue) {
        _name = newValue;
    };
}

我希望能够覆盖 setName 并将不同的实现传递给 Person 的每个实例,但我似乎无法让它正常工作。我确定这是一个关闭问题,但我无法理解它。

鉴于以下使用场景,我做错了什么?

var p1 = new Person({
    name: "Paul",
    setName: function (newValue) {
        this._name = newValue;
    }
});
var p2 = new Person({ name: "Bob" });
p1.setName("Paul (updated)");
p2.setName("Bob (updated)");

p1 永远不会更新其值,因此始终是“Paul”,而 p2 会更新并变为“Bob(已更新)”。我希望能够创建尽可能多的 Person 实例,其中 some 有自己的 setName 和其他实例将只使用默认实例。

我试过将 data.setName 包装在这样的闭包中,并设置我的自定义 setName 以返回值:

this.setName = data.setName ? function () {
    return (function (value) {
        value = data.setName();
    }(_name));
} : function (newValue) { _name = newValue; }

但我运气不好 - 我显然没有像我想的那样得到闭包!任何帮助总是感激。

codepen.io example here

最佳答案

this._name = newValue;

_name 是私有(private)变量,不是属性。无法在 this 上访问它。看看Javascript: Do I need to put this.var for every variable in an object?如果您不确定两者之间的区别。

function (value) {
    value = data.setName();
}

value 这里是该函数范围的局部变量,而不是对您传入的 _name 变量的“引用”。设置它只会将不同的值放入该局部变量,但不更改任何其他内容。


可能的解决方案:

  • 将有权访问 _name 变量的 setter 函数传递给 验证器:

    function Person(data) {
        var _name = data.name;
    
        this.name = function () {
            return _name;
        };
        if (data.nameValidator) 
            this.setName = function(newValue) {
                _name = data.nameValidator(newValue, _name);
            };
        else
            this.setName = function (newValue) {
                _name = newValue;
            };
    }
    var p1 = new Person({
        name: "Paul",
        nameValidator: function (newValue, oldValue) {
            return (newValue /* ... */) ? newValue : oldValue;
        }
    });
    
  • 或者让验证器返回值:

    function Person(data) {
        var _name = data.name;
    
        this.name = function () {
            return _name;
        };
        this.setName = function (newValue) {
            _name = newValue;
        };
        if (data.makeNameValidator) 
            this.setName = data.makeNameValidator(this.setName);
    }
    var p1 = new Person({
        name: "Paul",
        makeNameValidator: function (nameSetter) {
            return function(newValue) {
                if (newValue) // ...
                    nameSetter(newValue);
            };
        }
    });
    
  • 或者使 _name 成为验证器可以写入的属性。您也可以将它放在原始的 data 对象上,以免将其暴露在 Person 接口(interface)上:

    function Person(data) {
        this.name = function () {
            return data.name;
        };
        if (data.setName)
            this.setName = data.setName.bind(data);
        else
            this.setName = function(newValue) {
                _name = newValue;
            };
    }
    var p1 = new Person({
        name: "Paul",
        setName: function (newValue) {
            if (newValue) // ...
                this.name = newValue;
        }
    });
    

关于javascript - 覆盖对象上的 setter ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22934209/

相关文章:

javascript - 将 JSON 文件作为变量加载到 JS

javascript - Angular 表达式无法使用构造函数属性判断变量类型

javascript - 按值对数组键进行排序

javascript - 如何使用 Nativescript-Vue 分配一个元素来进行动画处理?

javascript - SOAP 请求中缺少激活全局自定义操作所需的输入字段

java - 手机缝隙相机 - 有更强大的选择吗?

javascript - 页面加载时 css 和 js 的最小和最大加载

javascript - 三.CurvePath和自定义标记

javascript - 如何使用 jQuery 过滤 DropDownList 中的选项

javascript - 滚动时导航栏发生变化,无法使用库