I want to achieve behaviour like down in code:

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

var myFoo = new Foo('myName');

myFoo.name('newMyName'); // sets myFoo.name = 'newMyName'
myFoo.name(); // returns 'myName'

But it is obvious that in that case I'm overridding name property with name function. Is anyhow possible to achieve that functionality?

有帮助吗?

解决方案

When talking about getters and setters in javascript you may be talking about one of two concepts:

1. Getters and setters as a concept like in any other OO language.

This is the case illustrated by the code in your question. In this case, an object's property is simply that, a property which may or be either an object or a function. javascript keeps track of both within the same namespace. Indeed, functions are just objects in javascript so there is no concept of a separate namespace for functions like you'd find in languages like C.

In this case "getters" and "setters" are just regular functions so the value needs to be stored separately. There are several strategies around this.

One is to use implicit getSomething() and setSomething() style functions commonly found in Java. This allows you to disambiguate the getters and setters from the property name since the getters and setters have the word "get" and "set" added to the name.

The second strategy is the one you've written in your question. In this case you need to store the property in another name so as not to share the same name with the getter/setter.

The third strategy is to store the value in a closure:

    function Foo (name) {
        var name = name;
        this.name = function (str) {
            if (str !== undefined) name = str;
            return name;
        }
    }

Note that in the code above the value is stored in name but the getter/setter is this.name which is a completely different variable. This allows your example code to work as you expected:

    var me = new Foo('Mark');
    me.name(); // returns Mark
    me.name('Andy'); // sets name to Andy

2. Getters and setters as a mechanism in javascript.

This is a feature of newer versions of javascript that follows the ECMAscript 5 specification. This feature allows properties to execute code when reading or writing to it similar to how the .innerHTML property of DOM object invokes the HTML parser when you assign something to it.

The syntax of getters and setters is similar to functions but introduces the get and set keywords in place of function.

A simple example of a property with getter and setter:

    var me = {
        first_name : "",
        last_name : "",
        get name() {
            return this.first_name + " " + this.last_name;
        },
        set name(str) {
            var n = str.split(/\s+/);
            this.first_name = n.shift();
            this.last_name = n.join(' ');
        }
    }

The code above allows you to treat the functions to get and set the first_name and last_name as if it is a variable instead of a function. To use the name getter and setter you'd simply do:

    me.name = "James Bond";
    alert(me.first_name); // should alert James
    alert(me.last_name); // should alert Bond
    me.last_name = "Dean";
    alert(me.name); // should alert James Dean

Using the javascript get/set mechanism, you can't store the value in the object using the same name. For example:

    var foo = {
        set bar(x) {this.bar=x}
    }

The code above will compile but trying to set bar: foo.bar = 1 will cause a stack overflow because of the infinite loop - the this.bar= inside the setter will call the setter again.

其他提示

If you want to use JavaScript getter/setter with the same name as the properties, e.g. to intercept certain setters to implement side effects, you can create a Proxy for your object.

function editableProxy (myObj) {
    return new Proxy(myObj, {
        toJSON: () => myObj,
        get: function (target, prop) {
            return Reflect.get(myObj, prop);
        },
        set: function (target, prop, receiver) {
            if (prop === 'billTo') {
                myObj.billToId = receiver?.id;
            }
            return Reflect.set(myObj, prop, receiver);
        },
    });
};

All getters work normally. Setters work normally, but if you set a billTo it also sets a billToId.

let da = {id:123}
let wrapped = editableProxy(da)
let id = wrapped.id // 123
wrapped.id=234
wrapped.id===da.id // true
wrapped.billTo={id:567,name:'Big Bad Bill'} // triggers setter side effect
wrapped.billToId // 567
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top