Typescript Set Accessor 的限制或我的代码有问题?

Limitation ot Typescript Set Accessor or issue with my code?

TypeScript 1.8 我正在努力思考如何使用 set 访问器拦截对对象属性(和子属性)的编辑操作。它没有像我预期的那样工作,我想知道我的代码是否有问题。

这是我的 class:

的摘录
private setAction:number = 0; //track # of edits

private _person:{ //data to be edited
    name:string,
    data:{
        activities:Array<{
            activityName:string,
            funFactor:number
        }>,
        country:string
    }
};

//public interfaces for set/get operations
public set person(val:any){
    //indicate which edit is occuring
    console.log('setting _person: setAction='+this.setAction);

    if(!this._person) this._person = val;//initial set operation
    let p = this._person;
    p.name = val.name || p.name;
    p.data.activities = val.data.activities || p.data.activities;
    p.data.country = val.data.country || p.data.country;
}

public get person(){
    return this._person;
}

public addActivity(name:string,value:number){
    this.person.data.activities.push(
        {activityName:name,funFactor:value});
}

//Edit this.person and test whether Set Accessor is called
onLoad(){

    console.log('Incrementing setAction to '+ ++this.setAction);
    this.person = {
        name:'Mary',
        data:{
            activities:[],
            country:'Argentina'
        }
    };

    console.log('Incrementing setAction to '+ ++this.setAction);
    this.person.name = 'Janet';

    console.log('Incrementing setAction to '+ ++this.setAction);
    this.addActivity('Bowling',7);

    console.log('Incrementing setAction to '+ ++this.setAction);
    this.person.data.country = 'Mexico';

    console.log('Incrementing setAction to '+ ++this.setAction);
    this.person.data.activities[0].funFactor = 8;

    console.log(this.person);
}

调用onLoad时,控制台输出如下:

Incrementing setAction to 1

setting _person: setAction=1

Incrementing setAction to 2

Incrementing setAction to 3

Incrementing setAction to 4

Incrementing setAction to 5

Object {name:"Janet", data:Object}

决赛 Object 中的 data 更新为 country="Mexico" 和保龄球 funFactor=8。所以所有的编辑都成功完成了,但是 Set 访问器只被调用了一次。为什么是这样?

查看 the docs(向下滚动到 Accessors 部分)没有提到此限制。

补充说明: 我知道为了执行 person.name='Janet',我需要先获取 person,所以我希望在所有这些操作中调用 get。然而,由于 person.name 由 'Mary' 更改为 'Janet',因此确实 设置了 为新值。那么为什么不调用 setter 呢?我正在为它的逻辑而苦苦挣扎。我希望这个过程是:1) get person, 2) set person.name

当 属性 从一个值更改为另一个值时, getter 和 setter 不应该都被调用吗?

已回答

我一直认为 getset 是在读取或写入属性时调用的。这就是向我解释的方式。 TypeScript 文档说“TypeScript 支持 getters/setters 作为拦截对对象成员的访问的方式 ”。 Radim Köhler 帮助我理解了当代码不是与对象属性而是与对象引用交互时调用这些函数。总之,当我执行person.name='Janet'的时候,虽然属性的值发生了变化,但是person仍然指向内存中的同一个对象,所以没有set操作。

好吧,setter 只被调用了一次,在那一行

this.person = {
    name:'Mary',
    data:{
        activities:[],
        country:'Argentina'
    }
};

彼此实际上是在呼唤getter

console.log('Incrementing setAction to '+ ++this.setAction);
this.person.name = 'Janet';

console.log('Incrementing setAction to '+ ++this.setAction);
this.addActivity('Bowling',7);

console.log('Incrementing setAction to '+ ++this.setAction);
this.person.data.country = 'Mexico';

console.log('Incrementing setAction to '+ ++this.setAction);
this.person.data.activities[0].funFactor = 8;

因为 this.person.data 就像

let person = this.person; // getter
person.data = ...

延长

a working example 显示了正在发生的问题。当我们调用引用 属性(例如 Person)的 setter 时,我们分配了一个引用。稍后,当我们更改该引用对象的属性时,我们不会更改原始引用。在这里查看:

class Person {
    // name has setter
    private _name = null;
    set name(name: string) { this._name = name; console.log(name) };
    get name() { return this._name}

    // age does not one
    age: number = null;
}

class PersonHolder {

    private _person;
    set person(person: Person) { this._person = person; 
                                 console.log(JSON.stringify(person)) };
    get person() { return this._person}
}

var holder = new PersonHolder();

// this will log to console { name: null, age: null}
holder.person = new Person();
// this will log to console "new name"
holder.person.name = "new name"
// this will NOT log to console... no setter
holder.person.age = 11;

直播example