2016-06-22 23 views
0

TypeScript 1.8我试图围绕如何使用set访问器来拦截对象属性(和子属性)的编辑操作。它没有按照我的预期工作,我不知道我的代码是否有问题。限制ot Typescript设置访问器或问题与我的代码?

这里是我的类的摘录:

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被调用时,下面是输出到控制台:

递增的setAction 1

设置_person:setAction命令= 1

递增setAction为2

递增的setAction至3

递增的setAction至4

递增的setAction至5

对象{名: “珍”,数据:对象}

data在最终Object更新为country="Mexico"和Bowling funFactor=8。所以所有编辑都成功完成,但Set访问器只被调用一次。为什么是这样?

看看the docs(向下滚动到访问器部分)没有提到这个限制。

其他注意事项: 据我所知,为了执行person.name='Janet',我需要先得到person,所以我希望get要对所有这些操作调用。但由于person.name从'玛丽'改为'珍妮特',确实设为为一个新值。那么,为什么不是二传手?我正在努力处理它的逻辑。我期望这个过程是:1)get person,2)set person.name

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

回答

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

回答

1

好,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 = ... 

EXTEND

a working example显示问题的实际情况。当我们调用引用属性的setter(例如Person)时,我们分配一个引用。之后,当我们更改引用对象的属性时,我们不会更改原始引用。点击此处查看:

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

+0

我明白,为了执行'person.name ='Janet'',我需要先得到'person',所以我希望'GET'是正如你所提到的那样呼吁所有这些行动。然而,由于'person.name'从'Mary'变成了'Janet',它确实**将**设置为一个新值。那么,为什么不是二传手?我正在努力处理它的逻辑。我期望的过程是:1)'get person',2)'set person.name' – BeetleJuice

+0

那么1)得到人..意味着给我参考人。因此,当我们改变名称时,我们在内存中有一个地址(这是参考),其中人员实例是2)。我们不会改变对人的引用。它仍然是同一个对象..只是某处(在堆上)改变了它的设置名称。因此,这个人的二传手是真实的,以引用这个人。不涉及与该实例相关的属性。也许试着准备一些关于引用和值类型的东西。 http://www.zsoltnagy.eu/understand-value-and-reference-types-in-javascript/ –

+0

我对引用类型和值类型之间的区别有所了解(感谢您的链接;我会看一看) 。我不知道“* setter是真的引用,而不是属性*”这是有道理的,但我链接到的Typescript文档没有提及它。你有没有参考这个,你可以添加到你的答案? – BeetleJuice